diff -u --recursive --new-file v2.1.15/linux/CREDITS linux/CREDITS
--- v2.1.15/linux/CREDITS	Thu Dec 12 19:36:55 1996
+++ linux/CREDITS	Wed Dec 18 11:45:43 1996
@@ -308,7 +308,9 @@
 N: Terry Dawson
 E: terry@perf.no.itg.telecom.com.au
 E: terry@albert.vk2ktj.ampr.org (Amateur Radio use only)
+D: trivial hack to add variable address length routing to Rose.
 D: AX25-HOWTO, HAM-HOWTO, IPX-HOWTO, NET-2-HOWTO
+D: ax25-utils maintainer.
 
 N: Todd J. Derr
 E: tjd@fore.com
@@ -349,7 +351,7 @@
 D: SCSI code
 D: Assorted snippets elsewhere
 D: Boot sector "..." printing
-S: 2255 Spruce
+S: 2037 Walnut #6
 S: Boulder, Colorado 80302
 S: USA
 
@@ -1009,8 +1011,8 @@
 N: Jonathan Naylor
 E: jsn@cs.nott.ac.uk
 E: g4klx@amsat.org
-E: G4KLX@GB7DAD (Packet Radio)
-D: AX.25 and NET/ROM protocol suites
+D: AX.25, NET/ROM and ROSE amateur radio protocol suites
+D: CCITT X.25 PLP and LAPB.
 S: 24 Castle View Drive
 S: Cromford
 S: Matlock
diff -u --recursive --new-file v2.1.15/linux/Documentation/Changes linux/Documentation/Changes
--- v2.1.15/linux/Documentation/Changes	Thu Dec 12 19:36:55 1996
+++ linux/Documentation/Changes	Sat Dec 14 13:41:53 1996
@@ -19,7 +19,7 @@
 generated by texinfo so a diff is useless anyway (though I can
 incorporate one by hand if you insist upon sending it that way ;-).
 
-Last updated: December 3, 1996.
+Last updated: December 13, 1996.
 Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
 
 Current Minimal Requirements
@@ -31,12 +31,12 @@
 - Kernel modules	 2.1.13
 - Gnu C 		 2.7.2.1
 - Binutils		 2.7.0.3
-- Linux C Library	 5.4.13
+- Linux C Library	 5.4.17
 - Dynamic Linker (ld.so) 1.8.5
 - Linux C++ Library	 2.7.2.1
 - Procps		 1.01
-- SysVinit		 2.64
-- Util-linux		 2.5
+- SysVinit		 2.69
+- Sysklogd               1.3-3
 - Mount                  2.5p
 - Net-tools              1.32-alpha
 - Kbd                    0.91
@@ -64,7 +64,7 @@
    For modules to work, you need to be running libc-5.4.x or greater.
 Since updates to libc fix other problems as well (security flaws, for
 example) and since 5.4.7 is missing a few needed symbols, try to get
-the latest 5.4.x you can.  Currently, libc-5.4.13 is the latest public
+the latest 5.4.x you can.  Currently, libc-5.4.17 is the latest public
 release.
 
    If you upgrade to libc-5.4.x, you also have to upgrade your dynamic
@@ -86,6 +86,29 @@
 system, you don't have to upgrade just so the kernel will work (though
 feel free to upgrade if you want the gcc bug fixes).
 
+Networking Changes
+==================
+
+   The network code now assumes less about your setup, which can cause
+routing problems due to init scripts expecting the old behavior.
+
+   Lines like:
+
+   `/sbin/ifconfig lo 127.0.0.1 /sbin/route add -net 127.0.0.0'
+
+   need to be changed to something like:
+
+   `/sbin/ifconfig lo 127.0.0.1 /sbin/route add -net 127.0.0.0 netmask
+255.0.0.0 dev lo'
+
+   for routing to be set up correctly.
+
+SysVinit
+========
+
+   To avoid an oops while shutting down or rebooting the computer,
+upgrade to SysVinit 2.69.
+
 How to know the version of the installed programs
 *************************************************
 
@@ -128,11 +151,11 @@
 Linux C Library
 ===============
 
-The 5.4.13 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libc-5.4.13.bin.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.13.bin.tar.gz
-Installation notes for 5.4.13:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.gcc-2.7.2.1
+The 5.4.17 release:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/libc-5.4.17.bin.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.4.17.bin.tar.gz
+Installation notes for 5.4.17:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.libc-5.4.17
 ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.4.13
 
 Linux C++ Library
@@ -169,9 +192,9 @@
 SysVinit utilities
 ==================
 
-The 2.64 release:
-ftp://tsx-11.mit.edu/pub/linux/sources/sbin/sysvinit-2.64.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.64.tar.gz
+The 2.69 release (when it gets there):
+ftp://tsx-11.mit.edu/pub/linux/sources/sbin/sysvinit-2.69.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.69.tar.gz
 
 Other Info
 ==========
diff -u --recursive --new-file v2.1.15/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.15/linux/Documentation/Configure.help	Thu Dec 12 19:36:56 1996
+++ linux/Documentation/Configure.help	Fri Dec 13 11:22:23 1996
@@ -1,7 +1,8 @@
 # Maintained by Axel Boldt (boldt@math.ucsb.edu) 
 #
 # This version of the Linux kernel configuration help texts
-# corresponds to the kernel versions 2.1.x.
+# corresponds to the kernel versions 2.1.x. Be aware that these are
+# development kernels and need not be completely stable.
 #
 # International versions of this file available on the WWW:
 #   - http://jf.gee.kyoto-u.ac.jp/JF/JF-ftp/euc/Configure.help.euc
@@ -9,6 +10,10 @@
 # (tetsu@cauchy.nslab.ntt.jp). 
 #   - http://nevod.perm.su/service/linux/doc/kernel/Configure.help 
 # is a Russian translation, maintained by kaf@linux.nevod.perm.su.
+#   - http://www.linux-kheops.com/traduc/kernels/
+# has a French translation of the whole kernel, including
+# Configure.help. This is maintained by David Bourgin
+# (dbourgin@wsc.com). 
 #
 # Information about what a kernel is, what it does, how to patch and
 # compile it and much more is contained in the Kernel-HOWTO, available
@@ -119,12 +124,12 @@
   before burning the CD, or want to use floppy images without first
   writing them to floppy.  This option also allows one to mount a
   filesystem with encryption.  To use these features, you need a
-  recent version of mount (check the file Documentation/Changes for
-  location and latest version).  Note that this loop device has
+  recent version of mount (available via ftp (user: anonymous) from
+  ftp.win.tue.nl/pub/linux/util/).  Note that this loop device has
   nothing to do with the loopback device used for network connections
   from the machine to itself.  Most users will answer N here.
 
-Enhanced IDE/MFM/RLL disk/cdrom/tape support
+Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support
 CONFIG_BLK_DEV_IDE 
   This will use the full-featured IDE driver to control up to four IDE
   interfaces, for a combination of up to eight IDE
@@ -168,9 +173,12 @@
 
 Include IDE/ATA-2 DISK support
 CONFIG_BLK_DEV_IDEDISK
-  This will include enhanced support for MFM/RLL/IDE disks. If you
+  This will include enhanced support for MFM/RLL/IDE harddisks. If you
   have a MFM/RLL/IDE disk, and there is no special reason to use the
-  old harddisk driver instead, say Y.
+  old harddisk driver instead, say Y.  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. If unsure, say Y.
 
 Include IDE/ATAPI CDROM support
 CONFIG_BLK_DEV_IDECD
@@ -189,31 +197,43 @@
   linux boot loader) cannot properly deal with IDE/ATAPI CDROMs, so
   install lilo-16 or higher, available from
   sunsite.unc.edu:/pub/Linux/system/Linux-boot/lilo.
+  If you want to compile the 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.
 
 Include IDE/ATAPI TAPE support
 CONFIG_BLK_DEV_IDETAPE
   If you have an IDE tape drive using the ATAPI protocol, say Y.
-  ATAPI is a new protocol used by IDE TAPE and ATAPI drives,
-  similar to the SCSI protocol.  At boot time, the TAPE drive will
-  be identified along with other IDE devices, as "hdb" or "hdc",
-  or something similar, and will be mapped to a character device such
-  as "ht0".  Be sure to consult the drivers/block/ide-tape.c and
-  Documentation/ide.txt files for usage information.
+  ATAPI is a new protocol used by IDE tape and CDROM drives, similar
+  to the SCSI protocol.  At boot time, the tape drive will be
+  identified along with other IDE devices, as "hdb" or "hdc", or
+  something similar, and will be mapped to a character device such as
+  "ht0".  Be sure to consult the drivers/block/ide-tape.c and
+  Documentation/ide.txt files for usage information.  If you want to
+  compile the 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.
 
 Include IDE/ATAPI FLOPPY support
 CONFIG_BLK_DEV_IDEFLOPPY
-  If you have an IDE floppy drive using the ATAPI protocol, say Y.
-  ATAPI is a new protocol used by IDE CDROM/TAPE/FLOPPY drives,
+  If you have an IDE floppy drive which uses the ATAPI protocol, say
+  Y. Chances are that you don't, because these animals are rare.
+  ATAPI is a new protocol used by IDE CDROM/tape/floppy drives,
   similar to the SCSI protocol.  At boot time, the FLOPPY drive will
-  be identified along with other IDE devices, as "hdb" or "hdc",
-  or something similar.
+  be identified along with other IDE devices, as "hdb" or "hdc", or
+  something similar. If you want to compile the 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.
 
 SCSI emulation support
 CONFIG_BLK_DEV_IDESCSI
   This will provide SCSI host adapter emulation for IDE ATAPI devices,
-  and will allow you to use a SCSI driver instead of a native ATAPI
-  driver.  If both SCSI emulation and native support are compiled into
-  the kernel, the native support will be used.  Normally, say N.
+  and will allow you to use a SCSI device driver instead of a native
+  ATAPI driver. This is useful if you have an ATAPI device for which
+  no native driver has been written; you can then use this emulation
+  together with an appropriate SCSI device driver. If both this SCSI
+  emulation and native ATAPI support are compiled into the kernel, the
+  native support will be used.  Normally, say N.
 
 CMD640 chipset bugfix/support
 CONFIG_BLK_DEV_CMD640
@@ -250,6 +270,13 @@
   Linux.  This may slow disk throughput by a few percent, but at least
   things will operate 100% reliably. If unsure, say Y.
 
+Intel 82371 PIIX (Triton I/II) DMA support
+CONFIG_BLK_DEV_TRITON
+  This will improve performance if you have an Intel PCI Triton I/II
+  IDE interface chipset (i82371FB or i82371SB). For details, read the
+  comments at the beginning of drivers/block/triton.c and
+  Documentation/ide.txt. If unsure, say N.
+
 Other IDE chipset support
 CONFIG_IDE_CHIPSETS
   Say Y here if you want to include enhanced support for various IDE
@@ -275,6 +302,18 @@
   of the Holtek card, and permits faster I/O speeds to be set as well.
   See the Documentation/ide.txt and ht6560b.c files for more info.
 
+PROMISE DC4030  support (EXPERIMENTAL)
+CONFIG_BLK_DEV_PROMISE
+  This driver provides support for the second port and cache of
+  Promise IDE interfaces, e.g. DC4030 and DC5030. It is enabled at
+  kernel runtime using the "ide0=dc4030" kernel boot parameter. See
+  the file drivers/block/promise.c file for more info.
+
+OPTi 82C621     support (EXPERIMENTAL)
+CONFIG_BLK_DEV_OPTI621
+  This is a driver for the OPTi 82C621 EIDE controller.
+  Please read the comments at the top of drivers/block/opti621.c.
+
 QDI QD6580 support
 CONFIG_BLK_DEV_QD6580
   This driver is enabled at runtime using the "ide0=qd6580" kernel
@@ -417,40 +456,49 @@
 Networking support
 CONFIG_NET
   Unless you really know what you are doing, you should say Y
-  here. The reason is that some programs need it even if you configure
-  a stand-alone machine that won't be connected to any other computer.
-  from an older kernel, you should consider updating your networking
-  tools too; read net/README for details.
+  here. The reason is that some programs need kernel networking
+  support even if you configure a stand-alone machine that won't be
+  connected to any other computer.  If you are upgrading from an older
+  kernel, you should consider updating your networking tools too
+  because changes in the kernel and the tools often go hand in hand;
+  see http://www.inka.de/sites/lina/linux/NetTools/index_en.html for
+  details. 
 
 Network aliasing
 CONFIG_NET_ALIAS
-  This is for setting multiple IP addresses on the same low-level
-  network device driver. Typically used for services that act
-  differently based on the address they listen on (e.g. "multihosting"
-  on Apache httpd) or for connecting to different logical networks
-  through the same physical interface.  This is the generic part,
-  later when configuring network protocol options you will be asked
-  for protocol-specific aliasing support.  See
-  Documentation/networking/alias.txt for more info.  If you need this
-  feature (for any protocol, like IP) say Y; if unsure, say N.
+  This will allow you to set multiple network addresses on the same
+  low-level network device driver. Typically used for services that
+  act differently based on the address they listen on
+  (e.g. "multihosting" or "virtual domains" on the web server apache
+  and the ftp server wuftpd) or for connecting to different logical
+  networks through the same physical interface (most commonly an
+  ethernet networking card).  This is the generic part, later when
+  configuring network protocol options you will be asked for
+  protocol-specific aliasing support, and you will have to say Y to at
+  least one of them.  See Documentation/networking/alias.txt for more
+  info.  If you need this feature (for any protocol, like IP) say Y;
+  if unsure, say N.
 
 Network firewalls
 CONFIG_FIREWALL
   A firewall is a computer which protects a local network from the
-  rest of the World: all traffic to and from computers on the local
-  net is inspected by the firewall first. If you want to configure
-  your Linux box as a firewall for a local network, say Y here. If
-  your local network is TCP/IP based, you will have to say Y to "IP:
-  firewalling", below.  You also need to say Y here and enable "IP
-  firewalling" below in order to be able to use IP masquerading
-  (i.e. local computers can chat with an outside host, but that
-  outside host is made to think that it is talking to the firewall
-  box. Makes the local network completely invisible and avoids the
-  need to allocate valid IP host addresses for the machines on the
-  local net) or to use the ip packet accounting to see what is using
-  all your network bandwidth. Chances are that you should use this on
-  any machine being run as a router and not on a host. If unsure, say
-  N.
+  rest of the world: all traffic to and from computers on the local
+  net is inspected by the firewall first, and sometimes blocked. If
+  you want to configure your Linux box as a firewall for a local
+  network, say Y here. If your local network is TCP/IP based, you will
+  then also have to say Y to "IP: firewalling", below.  
+  You also need to say Y here and enable "IP firewalling" below in
+  order to be able to use IP masquerading (i.e. local computers can
+  chat with an outside host, but that outside host is made to think
+  that it is talking to the firewall box -- makes the local network
+  completely invisible and avoids the need to allocate valid IP host
+  addresses for the machines on the local net) and IP packet
+  accounting (keeping track of what is using all your network
+  bandwidth) and IP transparent proxying (makes the computers on the
+  local network think they're talking to a remote computer, while in
+  reality the traffic is redirected by your Linux firewall to a local
+  proxy server). Chances are that you should use this on every machine
+  being run as a router and not on any regular host. If unsure, say N.
 
 Sun floppy controller support
 CONFIG_BLK_DEV_SUNFD
@@ -554,15 +602,15 @@
   Find out whether you have a PCI motherboard. PCI is the name of a
   bus system, i.e. the way the CPU talks to the other stuff inside
   your box. Other bus systems are ISA, EISA, Microchannel (MCA) or
-  VESA. If you have PCI, say Y, otherwise N. 
-  Note: some old PCI motherboards have BIOS bugs and may crash if 
-  "PCI bios support" is enabled (but they run fine without
-  this option). The PCI-HOWTO, available via ftp (user: anonymous) in
+  VESA. If you have PCI, say Y, otherwise N. Note: some old PCI
+  motherboards have BIOS bugs and may crash if "PCI bios support" is
+  enabled (but they run fine without this option). The PCI-HOWTO,
+  available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO, contains valuable information
   about which PCI hardware does work under Linux and which doesn't.
   If some of your PCI devices don't work and you get a warning during
   boot time ("man dmesg"), please follow the instructions at the top
-  of include/linux/pci.h. 
+  of include/linux/pci.h.
 
 PCI bridge optimization (experimental)
 CONFIG_PCI_OPTIMIZE
@@ -572,17 +620,21 @@
 
 MCA support
 CONFIG_MCA
-  MicroChannel Architecture is found in some IBM PS/2 machines and laptops.
-  See Documentation/mca.txt before attempting to build an MCA bus kernel.
+  MicroChannel Architecture is found in some IBM PS/2 machines and
+  laptops. It is a bus system similar to PCI or ISA.  See
+  Documentation/mca.txt before attempting to build an MCA bus kernel.
+  Note that this is still experimental code.
 
 Intel 82371 PIIX (Triton I/II) DMA support
 CONFIG_BLK_DEV_TRITON
   If your PCI system uses an IDE harddrive (as opposed to SCSI, say)
   and includes the Intel 430FX PCI Triton chipset, you will want to
   enable this option to allow use of bus-mastering DMA data transfers.
-  Read the comments at the beginning of drivers/block/triton.c.  Check
-  the file Documentation/Changes for location and latest version of
-  the hdparm utility. It is safe to say Y to this question.
+  Read the comments at the beginning of drivers/block/triton.c.  You
+  can get the latest version of the hdparm utility via ftp (user:
+  anonymous) from
+  sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/; it is used to
+  tune your harddisk. It is safe to say Y to this question.
 
 System V IPC
 CONFIG_SYSVIPC
@@ -624,19 +676,6 @@
   and read Documentation/modules.txt. Saying M or N here is dangerous
   because some crucial programs on your system might be in ELF format.
 
-Compile kernel as ELF - if your GCC is ELF-GCC
-CONFIG_KERNEL_ELF
-  The gcc version 2.7.0 and newer produces the new ELF binary format
-  as default. If you have such a compiler (try "gcc -v"), say Y here,
-  otherwise N.  
-  It is possible, albeit almost pointless, to compile the kernel in
-  a.out (i.e. QMAGIC) format even if your compiler produces ELF as
-  default. For that, you would have to say N here and change the
-  variables LD and CC in the toplevel Makefile. Similarly, if your
-  compiler produces a.out by default but is able to produce ELF, you
-  can compile the kernel in ELF by saying Y here and editing the
-  variables CC and LD in the toplevel Makefile.
-
 Kernel support for A.OUT binaries
 CONFIG_BINFMT_AOUT
   A.out (Assembler.OUTput) is a set of formats for libraries and
@@ -659,25 +698,25 @@
 Kernel support for JAVA binaries
 CONFIG_BINFMT_JAVA
   JAVA is an object oriented programming language developed by SUN;
-  JAVA programs are compiled into "JAVA bytecode" which can then be
-  interpreted by run time systems on many different operating systems.
-  These JAVA binaries are becoming a universal executable format. This
-  option allows you to run a Java binary just like any other Linux
-  program: by typing in its name. As more and more Java programs
-  become available, the use for this will gradually increase. You can
-  even execute HTML files containing JAVA applets (= JAVA binaries) if
-  those files start with the string "<!--applet-->". If you want to
-  use this, read Documentation/java.txt and the Java on Linux HOWTO,
-  available via ftp (user: anonymous) at
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. You will then need to install
-  the run time system contained in the Java Developers Kit (JDK) as
-  described in the HOWTO. If you disable this option it will reduce
-  your kernel by about 4kB. This is not much and by itself does not
-  warrant removing support. However its removal is a good idea if you
-  do not have the JDK installed. If you don't know what to answer at
-  this point then answer Y. You may answer M for module support and
-  later load the module when you install the JDK or find an interesting
-  Java program that you can't live without.
+  JAVA programs are compiled into "JAVA bytecode" binaries which can
+  then be interpreted by run time systems on many different operating
+  systems.  These JAVA binaries are becoming a universal executable
+  format. Saying Y here allows you to execute a JAVA bytecode binary
+  just like any other Linux program: by typing in its name. As more
+  and more Java programs become available, the use for this will
+  gradually increase. You can even execute HTML files containing JAVA
+  applets (= JAVA binaries) if those files start with the string
+  "<!--applet-->". If you want to use this, read
+  Documentation/java.txt and the Java on Linux HOWTO, available via
+  ftp (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. You
+  will then need to install the run time system contained in the Java
+  Developers Kit (JDK) as described in the HOWTO. If you disable this
+  option it will reduce your kernel by about 4kB. This is not much and
+  by itself does not warrant removing support. However its removal is
+  a good idea if you do not have the JDK installed. If you don't know
+  what to answer at this point then answer Y. You may answer M for
+  module support and later load the module when you install the JDK or
+  find an interesting Java program that you can't live without.
 
 Processor type
 CONFIG_M386
@@ -692,6 +731,16 @@
   say "386" or "486" here even if running on a Pentium or PPro
   machine. If you don't know what to do, say "386".
 
+Video mode selection support
+CONFIG_VIDEO_SELECT
+  This enables support for text mode selection on kernel startup. If you
+  want to take advantage of some high-resolution text mode your card's
+  BIOS offers, but the traditional Linux utilities like SVGATextMode
+  don't, you can enable this and set the mode using the "vga=" option
+  from your boot loader (LILO or LOADLIN) or set "vga=ask" which brings
+  up a video mode menu on kernel startup. Read Documentation/svga.txt
+  for more information. If unsure, say N.
+
 Compile the kernel into the ELF object format 
 CONFIG_ELF_KERNEL
   ELF (Executable and Linkable Format) is a format for libraries and
@@ -745,12 +794,12 @@
   use it.  If you select Y here, the kernel will take care of this all
   by itself, together with the user level daemon "kerneld".  Note that
   "kerneld" will also automatically unload all unused modules, so you
-  don't have to use "rmmod" either.
-  kerneld will also provide support for different user-level beeper
-  and screen blanker programs later on.
-  The "kerneld" daemon is included in the package "modules-1.2.8" and
-  later. You will probably want to read the kerneld mini-HOWTO,
-  available via ftp (user: anonymous) from
+  don't have to use "rmmod" either.  kerneld will also provide support
+  for different user-level beeper and screen blanker programs later
+  on.  The "kerneld" daemon is included in the modules package (check
+  Documentation/Changes for latest version and location). You will
+  probably want to read the kerneld mini-HOWTO, available via ftp
+  (user: anonymous) from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If unsure, say Y.
 
 ARP daemon support (EXPERIMENTAL)
@@ -851,27 +900,30 @@
   about 2kB. You may need to read the FIREWALL-HOWTO, available via
   ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also, you will need the
-  ipfwadm tool (check the file Documentation/Changes for location and
-  latest version) to allow selective blocking of internet traffic
-  based on type, origin and destination.  You need to enable IP
-  firewalling in order to be able to use IP masquerading (i.e. local
-  computers can chat with an outside host, but that outside host is
-  made to think that it is talking to the firewall box. Makes the
-  local network completely invisible and avoids the need to allocate
-  valid IP host addresses for the machines on the local net) or to use
-  the IP packet accounting to see what is using all your network
-  bandwidth.  This option is also needed when you want to enable the
-  transparent proxying support (makes the computers on the local
-  network think they're talking to a remote computer, while in reality
-  the traffic is redirected by your Linux firewall to a local proxy
-  server).
+  ipfwadm tool (available via ftp (user: anonymous) from
+  ftp.xos.nl/pub/linux/ipfwadm/) to allow selective blocking of
+  internet traffic based on type, origin and destination.  You need to
+  enable IP firewalling in order to be able to use IP masquerading
+  (i.e. local computers can chat with an outside host, but that
+  outside host is made to think that it is talking to the firewall box
+  -- makes the local network completely invisible and avoids the need
+  to allocate valid IP host addresses for the machines on the local
+  net) and IP packet accounting (keeping track of what is using all
+  your network bandwidth) and IP transparent proxying (makes the
+  computers on the local network think they're talking to a remote
+  computer, while in reality the traffic is redirected by your Linux
+  firewall to a local proxy server). If unsure, say N.
 
 IP: firewall packet netlink device
 CONFIG_IP_FIREWALL_NETLINK
-  When packets hit the firewall and are blocked the first 128 bytes of each
-  datagram is passed to optional user space monitoring software that can
-  then look for attacks and take actions such as paging the administrator of
-  the site.
+  If you say Y here and when packets hit your Linux firewall and are
+  blocked, the first 128 bytes of each such packet are passed on to
+  optional user space monitoring software that can then look for
+  attacks and take actions such as paging the administrator of the
+  site. To use this, you need to create a character special file under
+  /dev with major number 36 and minor number 3 using mknod ("man
+  mknod"), and you need (to write) a program that reads from that
+  device and takes appropriate action.
 
 IP: accounting
 CONFIG_IP_ACCT
@@ -882,8 +934,8 @@
   firewalling. The data is accessible with "cat /proc/net/ip_acct", so
   you want to say Y to the /proc filesystem below, if you say Y
   here. To specify what exactly should be recorded, you need the tool
-  ipfwadm (check the file Documentation/Changes for location and
-  latest version).
+  ipfwadm (available via ftp (user: anonymous) from
+  ftp.xos.nl/pub/linux/ipfwadm/).
 
 IP: tunneling
 CONFIG_NET_IPIP
@@ -922,21 +974,28 @@
 CONFIG_IP_MASQUERADE
   If one of the computers on your local network for which your Linux
   box acts as a firewall wants to send something to the outside, your
-  box can "masquerade" as that host, i.e. it forwards the traffic to
-  the intended destination, but makes it look like it came from the
-  firewall box itself. It works both ways: if the outside host
-  answers, the firewall will silently forward the traffic to the
-  corresponding local computer. This way, the computers on your local
-  net are completely invisible to the outside world, even though they
-  can reach the outside and can be reached. This makes it possible to
-  have the computers on the local network participate on the internet
-  even if they don't have officially registered IP addresses.  (This
-  last problem can also be solved by connecting the Linux box to the
-  Internet using SLiRP [SLiRP is a SLIP/PPP emulator that works if you
-  have a regular dial up shell account on some UNIX computer; get it
-  from ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/].)
-  Details on how to set things up are contained in the
-  IP Masquerading FAQ, available at http://www.indyramp.com/masq/
+  box can "masquerade" as that computer, i.e. it forwards the traffic
+  to the intended outside destination, but makes it look like it came
+  from the firewall box itself. It works both ways: if the outside
+  host replies, the Linux firewall will silently forward the traffic
+  to the corresponding local computer. This way, the computers on your
+  local net are completely invisible to the outside world, even though
+  they can reach the outside and can be reached. This makes it
+  possible to have the computers on the local network participate on
+  the internet even if they don't have officially registered IP
+  addresses.  (This last problem can also be solved by connecting the
+  Linux box to the Internet using SLiRP [SLiRP is a SLIP/PPP emulator
+  that works if you have a regular dial up shell account on some UNIX
+  computer; get it via ftp (user: anonymous) from
+  ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/].)  Details
+  on how to set things up are contained in the IP Masquerading FAQ,
+  available at http://www.indyramp.com/masq/. If you say Y here, then
+  the modules ip_masq_ftp.o (for ftp transfers through the firewall),
+  ip_masq_irc.o (for irc chats through the firewall), and
+  ip_masq_raudio.o (for realaudio downloads through the firewall) will
+  automatically be compiled. Modules are pieces of code which can be
+  inserted in and removed from the running kernel whenever you want;
+  read Documentation/modules.txt for details.
 
 IP: always defragment 
 CONFIG_IP_ALWAYS_DEFRAG 
@@ -946,7 +1005,7 @@
   reassembled (defragmented) before being processed, even if they are
   about to be forwarded.  This option is highly recommended if you
   have enabled the masquerading support (CONFIG_IP_MASQUERADE),
-  because this facility requires that second and further fragments can
+  because that facility requires that second and further fragments can
   be related to TCP or UDP port numbers, which are only stored in the
   first fragment.  When using IP firewall support
   (CONFIG_IP_FIREWALL), you might also want to enable this option, to
@@ -960,11 +1019,12 @@
 
 IP: aliasing support
 CONFIG_IP_ALIAS
-  Sometimes it is useful to give several addresses to a single network
-  interface (= serial port or ethernet card). The most common case is
-  that you want to serve different WWW documents to the outside
-  according to which of your host names they used to connect to
-  you. This is explained in detail on the WWW at
+  Sometimes it is useful to give several IP addresses to a single
+  physical network interface (= serial port or ethernet card). The
+  most common case is that you want to serve different WWW or ftp
+  documents to the outside according to which of your host names was
+  used to connect to you. This is called "multihosting" or "virtual
+  domains" and is explained in detail on the WWW at
   http://www.thesphere.com/~dlp/TwoServers/ (to browse the WWW, you
   need to have access to a machine on the Internet that has one of the
   programs lynx, netscape or Mosaic). Another scenario would be that
@@ -1030,10 +1090,22 @@
   sending very small chunks, we start out sending big ones and if we
   then discover that some host along the way likes its chunks smaller,
   we adjust to a smaller size. This is good, so most people say
-  N. However, some versions of DOS NCSA telnet (and other software)
+  N here. However, some versions of DOS NCSA telnet (and other software)
   are broken and can only connect to your Linux machine if you say Y
-  here. See also Documentation/networking/ncsa-telnet for the location
-  of fixed NCSA telnet clients.
+  here. See Documentation/networking/ncsa-telnet for the location
+  of fixed NCSA telnet clients. If in doubt, say N.
+
+Path MTU Discovery (normally enabled)
+CONFIG_PATH_MTU_DISCOVERY
+  MTU (maximal transfer unit) is the size of the chunks we send out
+  over the net. "Path MTU Discovery" means that, instead of always
+  sending very small chunks, we start out sending big ones and if we
+  then discover that some host along the way likes its chunks smaller,
+  we adjust to a smaller size. This is good, so most people say
+  Y here. However, some versions of DOS NCSA telnet (and other software)
+  are broken and can only connect to your Linux machine if you say N
+  here. See Documentation/networking/ncsa-telnet for the location
+  of fixed NCSA telnet clients. If in doubt, say Y.
 
 Disable NAGLE algorithm (normally enabled)
 CONFIG_TCP_NAGLE_OFF
@@ -1070,6 +1142,20 @@
   a second or   satellite links this option will make no difference to
   performance.
 
+The IPv6 protocol
+CONFIG_IPV6
+  This is experimental support for the next version of the Internet
+  Protocol IP version 6 (also called IPng "IP next
+  generation"). Features of this new protocol include: expanded
+  address space, authentication and privacy, and seamless
+  interoperability with the current version of IP. For details, see
+  http://playground.sun.com/pub/ipng/html/ipng-main.html and the file
+  net/ipv6/README in the kernel source.  The IPv6 support is also
+  available as a module ( = 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.  It's
+  safe to say N for now.
+
 The IPX protocol
 CONFIG_IPX
   This is support for the Novell networking protocol, IPX, commonly
@@ -1114,7 +1200,7 @@
   across routers.  If you are using an internal network, have multiple
   interfaces that route IPX, or will want to route IPX connections over
   ppp to internal networks, setting this will allow the type 20 packets
-  to be propogated to all connected networks.  These packets are used by
+  to be propagated to all connected networks.  These packets are used by
   Novell NETBIOS and the NETBIOS name functions of SMB protocols that
   work over IPX (e.g. the "Network Neighborhood" on another popular OS
   cum GUI).  In brief, if your Linux box needs to route IPX packets,
@@ -1153,20 +1239,24 @@
   use a low speed TNC (a Terminal Node Controller acts as a kind of
   modem connecting your computer's serial port to your radio's
   microphone input and speaker output) supporting the KISS protocol or
-  the various SCC cards that are supported by the Ottawa PI, the
-  Gracilis Packetwin and the generic Z8530 driver. Another option are
-  the Baycom modem serial and parallel port hacks (supported by their
-  own driver) and the other baycom cards (SCC) (supported by the Z8530
-  driver).  Information about where to get supporting software for
-  Linux amateur radio as well as information about how to configure an
-  AX.25 port is contained in the HAM-HOWTO, available via ftp (user:
-  anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. You might also
-  want to check out the file Documentation/networking/ax25.txt in the
-  kernel source. More information about digital amateur radio in
-  general is on the WWW at
-  http://www.cis.ohio-state.edu/hypertext/faq/usenet/radio/ham-radio/digital-faq/faq.html
-  (To browse the WWW, you need to have access to a machine on the
-  Internet that has one of the programs lynx, netscape or Mosaic).
+  one of the various SCC cards that are supported by the Ottawa PI,
+  the Gracilis Packetwin or the generic Z8530 driver. Another option
+  are the Baycom modem serial and parallel port hacks or the soundcard
+  modem (supported by their own drivers). If you say Y here, you also
+  have to say Y to one of those drivers. Information about where to
+  get supporting software for Linux amateur radio as well as
+  information about how to configure an AX.25 port is contained in the
+  HAM-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. You might also want to check
+  out the file Documentation/networking/ax25.txt in the kernel
+  source. More information about digital amateur radio in general is
+  on the WWW at http://www.tapr.org/tapr/html/pkthome.html.  (To
+  browse the WWW, you need to have access to a machine on the Internet
+  that has one of the programs lynx, netscape or Mosaic).  This driver
+  is also available as a module ( = 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.
 
 Amateur Radio NET/ROM
 CONFIG_NETROM
@@ -1175,13 +1265,15 @@
   amateur radio users as well as information about how to configure an
   AX.25 port is contained in the HAM-HOWTO, available via ftp (user:
   anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. You also might
-  also want to check out the file
-  Documentation/networking/ax25.txt. More information about digital
-  amateur radio in general is on the WWW at
-  http://www.cis.ohio-state.edu/hypertext/faq/usenet/radio/ham-radio/digital-faq/faq.html
-  (To browse the WWW, you need to have access to a machine on the
-  Internet that has one of the programs lynx, netscape or
-  Mosaic). 
+  want to check out the file Documentation/networking/ax25.txt. More
+  information about digital amateur radio in general is on the WWW at
+  http://www.tapr.org/tapr/html/pkthome.html (To browse the WWW, you
+  need to have access to a machine on the Internet that has one of the
+  programs lynx, netscape or Mosaic).
+  This driver is also available as a module ( = 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.
 
 AX.25 over Ethernet
 CONFIG_BPQETHER
@@ -1191,6 +1283,24 @@
   useful if some other computer on your local network has a direct
   amateur radio connection.
 
+Amateur Radio X.25 PLP (Rose)
+CONFIG_ROSE
+  The Packet Layer Protocol (PLP) is a way to route packets over X.25
+  connections in general and amateur radio AX.25 connections in
+  particular, essentially an alternative to NET/ROM.  A comprehensive
+  listing of all the software for Linux amateur radio users as well as
+  information about how to configure an AX.25 port is contained in the
+  HAM-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. You also might want to check
+  out the file Documentation/networking/ax25.txt. More information
+  about digital amateur radio in general is on the WWW at
+  http://www.tapr.org/tapr/html/pkthome.html (To browse the WWW, you
+  need to have access to a machine on the Internet that has one of the
+  programs lynx, netscape or Mosaic).  This driver is also available
+  as a module ( = 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.
+
 Bridging (EXPERIMENTAL)
 CONFIG_BRIDGE
   If you say Y here, then your Linux box will be able to act as an
@@ -1216,11 +1326,11 @@
   able to read from and write to character special files in the /dev
   directory having major mode 36. So far, the kernel uses it to
   publish some network related information if you enable "Routing
-  messages", below or firewall netlink.
-  You need to include this if you want to use arpd, a daemon that
-  helps keep the internal ARP cache (a mapping between IP addresses
-  and hardware addresses on the local network) small. If unsure, say
-  N.
+  messages", below. It is also used by the firewall code if you say Y
+  to "Kernel/User network link driver" further down.  You also need to
+  say Y here if you want to use arpd, a daemon that helps keep the
+  internal ARP cache (a mapping between IP addresses and hardware
+  addresses on the local network) small. If unsure, say N.
 
 Routing messages
 CONFIG_RTNETLINK
@@ -1277,12 +1387,12 @@
   say M here and read Documentation/modules.txt and
   Documentation/scsi.txt .
 
-Enable vendor-specific extentions (for SCSI CDROM)
+Enable vendor-specific extensions (for SCSI CDROM)
 CONFIG_BLK_DEV_SR_VENDOR
   This enables the usage of vendor specific SCSI commands. This is
   required for some stuff which is newer than the SCSI-II standard,
-  most important is the multisession CD support. You'll probably want
-  to say y here, unless you have a _real old_ CD-ROM drive.
+  most important is the MultiSession CD support. You'll probably want
+  to say Y here, unless you have a _real old_ CD-ROM drive.
 
 SCSI generic support
 CONFIG_CHR_DEV_SG
@@ -1400,7 +1510,9 @@
 CONFIG_SCSI_EATA_DMA
   This is support for the EATA-DMA protocol compliant SCSI Host
   Adaptors like the SmartCache III/IV, SmartRAID controller families
-  and the DPT PM2011B and PM2012B controllers.  Please read the
+  and the DPT PM2011B and PM2012B controllers.  Note that there is
+  also another driver for the same hardware: "EATA ISA/EISA/PCI
+  support". You should enable only one of them. Please read the
   SCSI-HOWTO, available via ftp (user: anonymous) at
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  This driver is also
   available as a module (= code which can be inserted in and removed
@@ -1526,20 +1638,22 @@
   SCSI-2 specifications allow scsi devices to negotiate a synchronous 
   transfer period of 25 nano-seconds or more.
   The transfer period value is 4 times the agreed transfer period.
-  So, data can be transferred at a 10 MHz frequency, allowing 10 MB/second 
-  throughput with 8 bits scsi-2 devices and 20 MB/second with wide16 devices.
-  This frequency can be used safely with differential devices but may cause 
-  problems with singled-ended devices.
+  So, data can be transferred at a 10 MHz frequency, allowing 10
+  MB/second throughput with 8 bits scsi-2 devices and 20 MB/second
+  with wide16 devices.  This frequency can be used safely with
+  differential devices but may cause problems with singled-ended
+  devices.
   Specify 0 if you want to only use asynchronous data transfers.
-  Otherwise, specify a value between 5 and 10.
-  Commercial O/Ses generally use 5 Mhz frequency for synchronous transfers.
-  It is a reasonnable default value.
-  However, a flawless singled-ended scsi bus supports 10 MHz data transfers.
-  Regardless the value choosen in the Linux configuration, the synchronous 
-  period can be changed after boot-up through the /proc/scsi file system.
-  The generic command is:
+  Otherwise, specify a value between 5 and 10.  Commercial O/Ses
+  generally use 5 Mhz frequency for synchronous transfers.  It is a
+  reasonable default value.
+  However, a flawless singled-ended scsi bus supports 10 MHz data
+  transfers.  Regardless the value chosen in the Linux configuration,
+  the synchronous period can be changed after boot-up through the
+  /proc/scsi file system. The generic command is:
       echo "setsync #target period" >/proc/scsi/ncr53c8xx/0
   Use a 25 ns period for 10 Mhz synchronous data transfers.
+  If you don't know what to do now, go with the default.
 
 use normal IO
 CONFIG_SCSI_NCR53C8XX_IOMAPPED
@@ -1574,10 +1688,22 @@
 
 maximum number of queued commands
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS
-  This option allows you to specify the maximum number of commands that 
-  can be queud to a device, when tagged command queuing is possible.
-  The default value is 4. Minimum is 2, maximum is 12.
-  The normal answer therefore is the default one.
+  This option allows you to specify the maximum number of commands
+  that can be queued to a device, when tagged command queuing is
+  possible.  The default value is 4. Minimum is 2, maximum is 12.  The
+  normal answer therefore is the default one.
+
+force asynchronous transfer mode
+CONFIG_SCSI_NCR53C8XX_FORCE_ASYNCHRONOUS
+  This option allows you to force asynchronous transfer mode for all
+  SCSI devices at linux startup. You can enable synchronous
+  negotiation with the "setsync" control command after boot-up, for
+  example:
+     echo "setsync 2 25" >/proc/scsi/ncr53c8xx/0
+  asks the driver to set the period to 25 ns (10MB/sec) for target 2
+  of controller 0 (please read drivers/scsi/README.ncr53c8xx for more
+  information). The safe answer therefore is Y.  The normal answer
+  therefore is N.
 
 force synchronous negotiation
 CONFIG_SCSI_NCR53C8XX_FORCE_SYNC_NEGO
@@ -1586,6 +1712,11 @@
   Answer Y only if you suspect some device to be so humble.
   The normal answer therefore is N.
  
+IBMMCA SCSI support
+CONFIG_SCSI_IBMMCA
+  If your computer sports an MCA bus system architecture (IBM PS/2)
+  with an SCSI harddrive, say Y here.
+
 disable master parity checking
 CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK
   Some hardware may have problems with parity during master cycles on
@@ -1676,7 +1807,7 @@
   drivers/scsi/ultrastor.h. If you want to compile this as a module (
   = code which can be inserted in and removed from the running kernel
   whenever you want), say M here and read Documentation/modules.txt.
-  Note that there is also another driver for UltraStor hardware:
+  Note that there is also another driver for the same hardware:
   "UltraStor 14F/34F support", above.
  
 7000FASST SCSI support
@@ -1693,8 +1824,8 @@
   This driver supports all the EATA/DMA-compliant SCSI host adapters
   and does not need any BIOS32 service.
   DPT ISA and all EISA i/o addresses are probed looking for the "EATA"
-  signature. If "PCI bios support" is enabled, the addresses of all the
-  PCI SCSI controllers reported by BIOS32 are probed as well.
+  signature. If "PCI bios support" is enabled, the addresses of all
+  the PCI SCSI controllers reported by BIOS32 are probed as well.
   Note that there is also another driver for the same hardware:
   "EATA-DMA support". You should enable only one of them.
   You want to read the start of drivers/scsi/eata.c and the
@@ -1719,7 +1850,10 @@
   This is support for the AM53/79C974 SCSI host adapters. Please read
   drivers/scsi/README.AM53C974 for details. Also, the SCSI-HOWTO,
   available via ftp (user: anonymous) at
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO, is for you.
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO, is for you. 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.
 
 IOMEGA Parallel Port ZIP drive SCSI support
 CONFIG_SCSI_PPA
@@ -1888,13 +2022,7 @@
   will show up in the directory modules once you have said "make
   modules". If unsure, say N.
 
-16 channels instead of 4 
-CONFIG_PPP_LOTS
-  Saying Y here will allow you to have up to 16 PPP connections
-  running in parallel. This is mainly useful if you intend your linux
-  box to act as a dial-in PPP server. Most people can say N.
-
-STRIP (Starmode Radio IP) support
+STRIP (Metricom Starmode radio IP)
 CONFIG_STRIP
   Say Y if you have a Metricom radio and intend to use Starmode Radio
   IP.  STRIP is a radio protocol developed for the MosquitoNet project
@@ -1907,8 +2035,11 @@
   phone line and use it as a modem.)  You can use STRIP on any Linux
   machine with a serial port, although it is obviously most useful for
   people with laptop computers. If you think you might get a Metricom
-  radio in the future, there is no harm in saying yes to STRIP now,
-  except that it makes the kernel a bit bigger.
+  radio in the future, there is no harm in saying Y to STRIP now,
+  except that it makes the kernel a bit bigger. You can also compile
+  this as a module ( = code which can be inserted in and removed from
+  the running kernel whenever you want), say M here and read
+  Documentation/modules.txt.
 
 WIC (Radio IP bridge)
 CONFIG_WIC
@@ -1923,7 +2054,8 @@
   in order to communicate with other computers.  If you want to use
   this, read Documentation/networking/z8530drv.txt and the AX.25-HOWTO,
   available via ftp (user: anonymous) at
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If you want to compile this
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  Also make sure to say Y to
+  "Amateur Radio AX.25 Level 2" support. If you want to compile this
   as a module ( = code which can be inserted in and removed from the
   running kernel whenever you want), say M here and read
   Documentation/modules.txt.
@@ -1933,12 +2065,14 @@
   This is an experimental driver for Baycom style simple amateur radio
   modems that connect to either a serial interface or a parallel
   interface. The driver supports the ser12 and par96 designs. To
-  configure the driver, use the sethdlc utility available
-  in the standard ax25 utilities package. For information on the modems,
-  see http://www.baycom.de and drivers/net/README.baycom.
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt. This is recommended.
+  configure the driver, use the sethdlc utility available in the
+  standard ax25 utilities package. For information on the modems, see
+  http://www.baycom.de and drivers/net/README.baycom.  If you want to
+  use this, you need to say Y to "Amateur Radio AX.25 Level 2" support
+  as well.  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.
 
 Soundcard modem driver for AX.25
 CONFIG_SOUNDMODEM
@@ -1948,10 +2082,23 @@
   utilities available in the standard ax25 utilities package. For
   informations on how to key the transmitter, see
   http://www.ife.ee.ethz.ch/~sailer/pcf/ptt_circ/ptt.html and
-  drivers/net/README.soundmodem. If you want to compile this as a
-  module ( = code which can be inserted in and removed from the
-  running kernel whenever you want), say M here and read
-  Documentation/modules.txt. This is recommended.
+  drivers/net/README.soundmodem. To use this driver, you also need to
+  say Y to "Amateur Radio AX.25 Level 2" support. 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. Note that
+  this driver and the sound driver cannot both work at the same time.
+
+Serial port KISS driver for AX.25
+CONFIG_MKISS
+  KISS is the protocol used to send IP traffic over AX.25 radio
+  connections, somewhat similar to SLIP for telephone lines. Say Y
+  here if you intend to send internet traffic over amateur radio,
+  using some device connected to your machine's serial port. In that
+  case, you also have to say Y to "Amateur Radio AX.25 Level 2"
+  support.  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.
 
 PLIP (parallel port) support
 CONFIG_PLIP
@@ -2062,6 +2209,14 @@
   This is support for the intel ethernet cards on some Sun workstations
   (all those with a network interface 'ie0' under SunOS).
 
+Ethernet (10 or 100Mbit)
+CONFIG_NET_ETHERNET
+  Ethernet is a widely used protocol on local area networks. If you
+  have a ethernet card in your computer and want to use it under
+  Linux, say Y here. Note that the answer to this question doesn't
+  directly affect the kernel: saying N will just cause this configure
+  script to skip all the questions about ethernet card drivers.
+
 Western Digital/SMC cards
 CONFIG_NET_VENDOR_SMC
   If you have a network (ethernet) card belonging to this class, say Y
@@ -2196,6 +2351,18 @@
   Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
+3c523 support CONFIG_ELMC
+  If you have a network (ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. This driver is also available
+  as a module ( = 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 as well as
+  Documentation/networking/net-modules.txt. If you plan to use more
+  than one network card under linux, read the
+  Multiple-Ethernet-mini-HOWTO, available from
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+
 3c509/3c579 support
 CONFIG_EL3
   If you have a network (ethernet) card belonging to the 3Com
@@ -2399,9 +2566,12 @@
 CONFIG_NI65
   If you have a network (ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you plan to use more than
-  one network card under linux, read the Multiple-Ethernet-mini-HOWTO,
-  available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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. If you plan to use more
+  than one network card under linux, read the
+  Multiple-Ethernet-mini-HOWTO, available from
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
 Ottawa PI and PI/2 support
 CONFIG_PI
@@ -2414,16 +2584,23 @@
   you can say Y here and should read the HAM-HOWTO, available via ftp
   (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also,
   you should have said Y to "AX.25 support" above, because AX.25 is
-  the protocol used for digital traffic over radio links.
+  the protocol used for digital traffic over radio links. If you want
+  to compile this as a module ( = code which can be inserted in and
+  removed from the running kernel whenever you want), say M here and
+  read Documentation/modules.txt.
 
 Gracilis PackeTwin support
 CONFIG_PT
-  This card is similar to the PI card (mentioned above).  It is used
-  mainly by amateur radio operators for packet radio.  You should have
-  already said Y to "AX.25 support" as this card uses that protocol.
-  More information about this driver can be found in the file
-  drivers/net/README.pt.  NOTE: The card is capable of DMA and full
-  duplex but neither of these have been coded in the driver as yet.
+  This is a card used mainly by amateur radio operators for packet
+  radio.  You should have already said Y to "AX.25 support" as this
+  card uses that protocol.  More information about this driver can be
+  found in the file drivers/net/README.pt.  NOTE: The card is capable
+  of DMA and full duplex but neither of these have been coded in the
+  driver as yet.  This driver is also available as a module ( = 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 as well as
+  Documentation/networking/net-modules.txt.
 
 WaveLAN support
 CONFIG_WAVELAN
@@ -2702,10 +2879,35 @@
 
 Traffic Shaper (EXPERIMENTAL)
 CONFIG_SHAPER
-  The traffic shaper adds a set of devices that may be attached to the
-  other devices in the kernel and used to limit their bandwidth. The
-  shapecfg program for setting up shaper devices is available from
-  ftp://shadow.cabi.net/....
+  A traffic shaper is a special device (typically called /dev/shaper0)
+  that attaches to some other network device (such as your first
+  ethernet card /dev/eth0) and limits the outgoing bandwidth on that
+  device to a configurable upper bound, for example 64000 bits per
+  second. It works like this: you can send all the traffic that would
+  normally go to /dev/eth0 to /dev/shaper0 instead; the traffic will
+  be slowed down a bit and then forwarded to /dev/eth0. This could be
+  useful for something, but I don't know for what. To set up and
+  configure shaper devices, you need the shapecfg program, available
+  via ftp (user: anonymous) from shadow.cabi.net/pub/Linux in the
+  shaper package. Please read Documentation/networking/shaper.txt.
+  This driver is also available as a module ( = 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 N.
+
+FDDI driver support
+CONFIG_FDDI
+  Fiber Distributed Data Interface is a high speed local area network
+  design; essentially a replacement for high speed ethernet. FDDI can
+  run over copper or fiber. If you are connected to such a network and
+  want a driver for the FDDI card in your computer, say Y here (and
+  then also Y to the driver for your FDDI card, below). Most people
+  will say N.
+
+Digital DEFEA and DEFPA adapter support
+CONFIG_DEFXX
+  This is support for the DIGITAL series of EISA (DEFEA) and PCI
+  (DEFPA) controllers which can connect you to a local FDDI network.
 
 Support non-SCSI/IDE/ATAPI drives
 CONFIG_CD_NO_IDESCSI
@@ -2867,22 +3069,11 @@
   If you say Y here, you will be able to set per user limits for disk
   usage (also called diskquotas). Currently, it works only for the
   ext2 filesystem. You need additional software in order to use quota
-  support; check the file Documentation/Changes for that. Probably the
+  support; it is available via ftp (user: anonymous) from
+  ftp.funet.fi/pub/Linux/kernel/src/subsystems/quota/. Probably the
   quota support is only useful for multi user systems. If unsure, say
   N.
 
-Mandatory lock support
-CONFIG_LOCK_MANDATORY
-  File locking is a system designed to prevent that several processes
-  write to the same file at the same time, causing data
-  corruption. Mandatory file locking is more secure than the usual
-  algorithm and is used by some Unix System 5 style database
-  applications. For details, read Documentation/mandatory.txt. To use
-  this option safely you must have newer NFS daemons, new samba, new
-  netatalk, new mars-nwe and other file servers. At the time of
-  writing none of these are available. So it's safest to say N here
-  unless you really know that you need this feature.
-
 Minix fs support
 CONFIG_MINIX_FS
   Minix is a simple operating system used in many classes about
@@ -3022,16 +3213,15 @@
   your harddisk: the files are created on the fly when you access
   them. Also, you cannot read the files with less: you need to use
   more or cat. The filesystem is explained in the Kernel Hacker's
-  Guide, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/LDP and also on the proc(8) manpage
-  ("man 8 proc").  This option will enlarge your kernel by about 18
-  kB. It's totally cool; for example, "cat /proc/interrupts" gives
-  information about what the different IRQs are used for at the moment
-  (there is a small number of Interrupt ReQuest lines in your computer
-  that are used by the periphery to gain the CPU's attention - often a
-  source of trouble if two devices are mistakenly configured to use
-  the same IRQ). Several programs depend on this, so everyone should
-  say Y here.
+  Guide at http://www.redhat.com:8080/HyperNews/get/khg.html on the
+  Web, and also on the proc(8) manpage ("man 8 proc").  This option
+  will enlarge your kernel by about 18 kB. It's totally cool; for
+  example, "cat /proc/interrupts" gives information about what the
+  different IRQs are used for at the moment (there is a small number
+  of Interrupt ReQuest lines in your computer that are used by the
+  periphery to gain the CPU's attention - often a source of trouble if
+  two devices are mistakenly configured to use the same IRQ). Several
+  programs depend on this, so everyone should say Y here.
   
 NFS filesystem support
 CONFIG_NFS_FS
@@ -3187,21 +3377,22 @@
 CONFIG_SMB_FS
   SMB (Server Message Buffer) is the protocol Windows for Workgroups
   (WfW), Windows NT and Lan Manager use to talk to each other over an
-  ethernet. Enabling this allows you to mount their filesystems and
-  access them just like any other unix directory. For details, read
-  Documentation/filesystems/smbfs.txt.  Note: if you just want your
-  box to act as an SMB *server* and make files and printing services
-  available to Windows clients (which need to have a TCP/IP stack),
-  you don't need to enable this filesystem support; you can use the
-  program samba (available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/system/Network/samba) for that. General
-  information about how to connect Linux, Windows machines and Macs is
-  on the WWW at http://eats.com/linux_mac_win.html (to browse the WWW,
-  you need to have access to a machine on the Internet that has one of
-  the programs lynx, netscape or Mosaic).  If you want to compile the
-  SMB support 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. Most people say N, however.
+  ethernet. Enabling this allows you to mount their filesystems (often
+  called "shares") and access them just like any other unix
+  directory. For details, read Documentation/filesystems/smbfs.txt.
+  Note: if you just want your box to act as an SMB *server* and make
+  files and printing services available to Windows clients (which need
+  to have a TCP/IP stack), you don't need to enable this filesystem
+  support; you can use the program samba (available via ftp (user:
+  anonymous) in sunsite.unc.edu:/pub/Linux/system/Network/samba) for
+  that. General information about how to connect Linux, Windows
+  machines and Macs is on the WWW at
+  http://eats.com/linux_mac_win.html (to browse the WWW, you need to
+  have access to a machine on the Internet that has one of the
+  programs lynx, netscape or Mosaic).  If you want to compile the SMB
+  support 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. Most people say N, however.
 
 SMB Win95 bug work-around
 CONFIG_SMB_WIN95
@@ -3314,9 +3505,12 @@
 
 Hayes ESP serial port support
 CONFIG_ESP
-  This is a driver which supports Hayes ESP serial ports.  It uses DMA to
-  transfer data to and from the host.  Make sure to read
-  drivers/char/README.esp.  This driver may be compiled as a loadable module.
+  This is a driver which supports Hayes ESP serial ports.  It uses DMA
+  to transfer data to and from the host.  Make sure to read
+  drivers/char/README.esp. 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 driver may be compiled as a loadable module.
 
 Hayes ESP serial port DMA channel
 CONFIG_ESP_DMA_CHANNEL
@@ -3357,7 +3551,6 @@
   tells you how to specify the port and IRQ to be used by PLIP at
   module load time.
 
-
 Mouse Support (not serial mice)
 CONFIG_MOUSE
   This is for machines with a bus mouse or a PS/2 mouse as opposed to
@@ -3397,11 +3590,15 @@
   particular, the C&T 82C710 mouse on TI Travelmates is a PS/2
   mouse. Although PS/2 mice are not technically bus mice, they are
   explained in detail in the Busmouse-HOWTO, available via ftp (user:
-  anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If you want to
-  compile this as a module ( = code which can be inserted in and
-  removed from the running kernel whenever you want), say M here and
-  read Documentation/modules.txt. If you are unsure, say N and read
-  the HOWTO nevertheless: it will tell you what you have.
+  anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO.  When using a
+  PS/2 mouse, you can get problems if you want to use the mouse both
+  on the Linux console and under X. The mconv utility, available in
+  sunsite.unc.edu:/pub/Linux/system/Misc, solves this problem. If you
+  want to compile this mouse 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. If you are unsure,
+  say N and read the HOWTO nevertheless: it will tell you what you
+  have.
 
 C&T 82C710 mouse port support (as on TI Travelmate)
 CONFIG_82C710_MOUSE
@@ -3444,7 +3641,10 @@
 
 QIC-02 tape support
 CONFIG_QIC02_TAPE
-  If you have a non-SCSI tape drive like that, say Y.
+  If you have a non-SCSI tape drive like that, say Y. Or, 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.
 
 Do you want runtime configuration for QIC-02
 CONFIG_QIC02_DYNCONF
@@ -3481,18 +3681,20 @@
   APM compliant BIOSes.  Specifically, the 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).  This
-  driver does not spin down disk drives (see hdparm(8) for that); and
-  it doesn't turn off VESA-compliant "green" monitors.  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). If you get random kernel OOPSes that don't
-  seem to be related to anything and you have a motherboard with APM
-  support, try disabling/enabling this option. Generally, if you don't
-  have a battery in your machine, there isn't much point in using this
+  notification of APM "events" (e.g., battery status
+  change). Supporting software can be gotten via ftp (user: anonymous)
+  from tsx-11.mit.edu/pub/linux/packages/laptops/apm/. This driver
+  does not spin down disk drives (see hdparm(8) for that); and it
+  doesn't turn off VESA-compliant "green" monitors.  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). If you get random kernel OOPSes that don't seem to be
+  related to anything and you have a motherboard with APM support, try
+  disabling/enabling this option. Generally, if you don't have a
+  battery in your machine, there isn't much point in using this
   driver.
 
 Ignore USER SUSPEND
@@ -3669,13 +3871,13 @@
 ProAudioSpectrum 16 support
 CONFIG_PAS
   Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio
-  16 or Logitech SoundMan 16.  Don't answer 'y' if you have some other
+  16 or Logitech SoundMan 16.  Don't answer Y if you have some other
   card made by Media Vision or Logitech since they are not PAS16
   compatible.
 
 SoundBlaster (SB, SBPro, SB16, clones) support
 CONFIG_SB
-  Answer "y" if you have an original SoundBlaster card made by
+  Answer Y if you have an original SoundBlaster card made by
   Creative Labs or a 100% hardware compatible clone (like the
   Thunderboard or SM Games). If your card was in the list of supported
   cards look at the card specific instructions in the
@@ -3815,9 +4017,9 @@
   /proc/profile (enable the /proc filesystem!) and in order to read
   it, you need the readprofile package from sunsite.unc.edu. Its
   manpage gives information regarding the format of profiling data. To
-  become a kernel hacker, you can start with the Kernel Hacker's
-  Guide, available via ftp (user: anonymous) from
-  sunsite.unc.edu:/pub/Linux/docs/LDP. Mere mortals say N.
+  become a kernel hacker, you can start with the Kernel Hacker's Guide
+  at http://www.redhat.com:8080/HyperNews/get/khg.html. Mere mortals
+  say N.
  
 Profile shift count
 CONFIG_PROFILE_SHIFT
@@ -3911,16 +4113,6 @@
   machine see http://cap.anu.edu.au/cap/projects/linux or mail to
   hackers@cafe.anu.edu.au
 
-Video mode selection support
-CONFIG_VIDEO_SELECT
-  This enables support for text mode selection on kernel startup. If you
-  want to take advantage of some high-resolution text mode your card's
-  BIOS offers, but the traditional Linux utilities like SVGATextMode
-  don't, you can enable this and set the mode using the "vga=" option
-  from your boot loader (LILO or LOADLIN) or set "vga=ask" which brings
-  up a video mode menu on kernel startup. Read Documentation/svga.txt
-  for more information. If unsure, say "n".
-
 # need an empty line after last entry, for sed script in Configure.
 
 #
@@ -4008,4 +4200,14 @@
 # LocalWords:  mgetty sendfax gert greenie muc lowlevel Lasermate LanManager io
 # LocalWords:  OOPSes trackball binghamton mobileip ncr IOMAPPED settags ns ser
 # LocalWords:  setsync NEGO MPARITY autotuning prefetch PIIX cdwrite utils rc
-# LocalWords:  PCWATCHDOG berkprod bitgate
+# LocalWords:  PCWATCHDOG berkprod bitgate boldt ucsb jf kyoto jp euc Tetsuyasu
+# LocalWords:  YAMADA tetsu cauchy nslab ntt nevod perm su doc kaf kheops wsc
+# LocalWords:  traduc Bourgin dbourgin helptext menuconfig kfill READMEs HOWTOs
+# LocalWords:  IDEDISK IDEFLOPPY EIDE firewalls QMAGIC ZMAGIC LocalWords opti
+# LocalWords:  SVGATextMode vga svga Xterminal Xkernel syr jmwobus comfaqs dhcp
+# LocalWords:  IPv IPng interoperability ipng ipv radio's tapr pkthome PLP nano
+# LocalWords:  Ses Mhz sethdlc SOUNDMODEM WindowsSoundSystem smdiag pcf inka ES
+# LocalWords:  smmixer ptt circ soundmodem MKISS FDDI DEFEA DEFPA DEFXX redhat
+# LocalWords:  HyperNews khg mconv sed lina wuftpd MicroChannel netlink irc cum
+# LocalWords:  raudio realaudio PPROP NETBIOS GUI IBMMCA ELMC Racal Interlan fi
+# LocalWords:  eth shapecfg src esp PCWD PREVSTAT
diff -u --recursive --new-file v2.1.15/linux/Documentation/devices.tex linux/Documentation/devices.tex
--- v2.1.15/linux/Documentation/devices.tex	Thu Dec 12 19:36:56 1996
+++ linux/Documentation/devices.tex	Wed Dec 18 11:07:59 1996
@@ -42,7 +42,7 @@
 %
 \title{{\bf Linux Allocated Devices}}
 \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$}
-\date{Last revised: December 7, 1996}
+\date{Last revised: December 16, 1996}
 \maketitle
 %
 \noindent
@@ -187,7 +187,8 @@
 \major{60}{--63}{}{Local/experimental use}
 \major{64}{}{char }{ENskip kernel encryption package}
 \major{65}{}{char }{Sundance ``plink'' Transputer boards}
-\major{66}{--119}{}{Unallocated}
+\major{66}{}{char }{YARC PowerPC PCI coprocessor card}
+\major{67}{--119}{}{Unallocated}
 \major{120}{--127}{}{Local/experimental use}
 \major{128}{--239}{}{Unallocated}
 \major{240}{--254}{}{Local/experimental use}
@@ -477,6 +478,8 @@
 	\minor{137}{/dev/qcam1}{QuickCam on {\file lp1}}
 	\minor{138}{/dev/qcam2}{QuickCam on {\file lp2}}
 	\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}
 \end{devicelist}
 
 \begin{devicelist}
@@ -1194,7 +1197,14 @@
 $<$jth@prosig.demon.co.uk$>$ for information. 
 
 \begin{devicelist}
-\major{66}{--119}{}{Unallocated}
+\major{66}{}{char }{YARC PowerPC PCI coprocessor card}
+	\minor{0}{/dev/yppcpci00}{First YARC card}
+	\minor{1}{/dev/yppcpci01}{Second YARC card}
+	\minordots
+\end{devicelist}
+
+\begin{devicelist}
+\major{67}{--119}{}{Unallocated}
 \end{devicelist}
 
 \begin{devicelist}
diff -u --recursive --new-file v2.1.15/linux/Documentation/devices.txt linux/Documentation/devices.txt
--- v2.1.15/linux/Documentation/devices.txt	Thu Dec 12 19:36:56 1996
+++ linux/Documentation/devices.txt	Wed Dec 18 11:07:59 1996
@@ -283,6 +283,8 @@
 		137 = /dev/qcam1	QuickCam on lp1
 		138 = /dev/qcam2	QuickCam on lp2
 		139 = /dev/openprom	SPARC OpenBoot PROM
+		140 = /dev/relay8	Berkshire Products Octal relay card
+		141 = /dev/relay16	Berkshire Products ISO-16 relay card
 
  11 char	Raw keyboard device
 		  0 = /dev/kbd		Raw keyboard device
@@ -838,7 +840,12 @@
 		This is a commercial driver; contact James Howes
 		<jth@prosig.demon.co.uk> for information.
 
- 66-119		UNALLOCATED
+ 66 char	YARC PowerPC PCI coprocessor card
+		  0 = /dev/yppcpci00	First YARC card
+		  1 = /dev/yppcpci01	Second YARC card
+		      ...
+
+ 67-119		UNALLOCATED
 
 120-127		LOCAL/EXPERIMENTAL USE
 
diff -u --recursive --new-file v2.1.15/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt
--- v2.1.15/linux/Documentation/ioctl-number.txt	Thu Dec 12 19:36:56 1996
+++ linux/Documentation/ioctl-number.txt	Mon Dec 16 13:11:07 1996
@@ -1,5 +1,5 @@
 Ioctl Numbers
-2 Dec 1996
+16 Dec 1996
 Michael Chastain
 <mec@shout.net>
 
@@ -21,8 +21,7 @@
 or number from the table below.  If you are writing a driver for a new
 device and need a letter, pick an unused letter.  You can register the
 letter by patching this file and submitting the patch to Linus Torvalds.
-Or you can e-mail me at <mec@duracef.shout.net> and I'll register one
-for you.
+Or you can e-mail me at <mec@shout.net> and I'll register one for you.
 
 The second argument to _IO, _IOW, _IOR, or _IOWR is a sequence number
 to distinguish ioctls from each other.  The third argument is the size
@@ -51,7 +50,7 @@
     code to call verify_area to validate parameters.
 
 This table lists ioctls visible from user land for Linux/i386.  It is
-current to Linux 2.1.14.
+current to Linux 2.1.15.
 
 Code	Seq#	Include File		Comments
 ========================================================
@@ -82,7 +81,9 @@
 'T'	all	linux/soundcard.h	conflict!
 'T'	all	asm-i386/ioctls.h	conflict!
 'V'	all	linux/vt.h
-'W'	00-1F	linux/pcwd.h
+'W'	00-1F	linux/watchdog.h
+'W'	20-27	linux/octal-relay.h	in development
+'W'	28-2F	linux/iso16-relay.h	in development
 'Y'	all	linux/cyclades.h
 'a'	all	various, see http://lrcwww.epfl.ch/linux-atm/magic.html
 'c'	all	linux/comstats.h
@@ -97,11 +98,12 @@
 't'	80-8F	linux/isdn_ppp.h
 'u'	all	linux/smb_fs.h
 'v'	all	linux/ext2_fs.h
-'w'	all	CERN SCI driver (in development)
+'w'	all	CERN SCI driver		in development
 0x89	00-0F	asm-i386/sockios.h
 0x89	10-DF	linux/sockios.h
 0x89	E0-EF	linux/sockios.h		SIOCPROTOPRIVATE range
 0x89	F0-FF	linux/sockios.h		SIOCDEVPRIVATE range
+0x8B	all	linux/wireless.h
 0x90	00	linux/sbpcd.h
-0x99	00-0F	537-Addinboard driver (in development, e-mail contact:
-					b.kohl@ipn-b.comlink.apc.org)
+0x99	00-0F	537-Addinboard driver	in development, e-mail contact:
+					b.kohl@ipn-b.comlink.apc.org
diff -u --recursive --new-file v2.1.15/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt
--- v2.1.15/linux/Documentation/networking/ip-sysctl.txt	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/networking/ip-sysctl.txt	Wed Dec 18 11:45:43 1996
@@ -0,0 +1,94 @@
+/proc/sys/net/ipv4/* variables:
+
+ip_forwarding - "SNMP" BOOLEAN
+	2 - disabled (default)
+	1 - enabled
+
+	This variable is special, its change resets all configuration
+	parameters to their default state (RFC1122 for hosts, RFC1812
+	for routers)
+
+ip_default_ttl - INTEGER
+	default 64
+
+ip_log_martians - BOOLEAN
+	log packets with strange or impossible addresses.
+	default TRUE (router)
+		FALSE (host)
+
+ip_accept_redirects - BOOLEAN
+	Accept ICMP redirect messages.
+	default TRUE (host)
+		FALSE (router)
+
+ip_secure_redirects - BOOLEAN
+	Accept ICMP redirect messages only for gateways,
+	listed in default gateway list.
+	default TRUE
+
+ip_addrmask_agent - BOOLEAN
+	Reply to ICMP ADDRESS MASK requests.
+	default TRUE (router)
+		FALSE (host)
+
+ip_rfc1620_redirects - BOOLEAN
+	Send(router) or accept(host) RFC1620 shared media redirects.
+	Overrides ip_secure_redirects.
+	default TRUE (should be FALSE for distributed version,
+		      but I use it...)
+
+ip_bootp_agent - BOOLEAN
+	Accept packets with source address of sort 0.b.c.d
+	and destined to this host, broadcast or multicast.
+	Such packets are silently ignored otherwise.
+
+	default FALSE
+
+ip_bootp_relay - BOOLEAN
+	Accept packets with source address 0.b.c.d destined
+	not to this host as local ones. It is supposed, that
+	BOOTP relay deamon will catch and forward such packets.
+
+	default FASLE
+	Not Implemented Yet.
+
+
+ip_source_route - BOOLEAN
+	Accept packets with SRR option.
+	default TRUE (router)
+		FALSE (host)
+
+
+ip_no_pmtu_disc - BOOLEAN
+	Disable Path MTU Discovery.
+	default FALSE
+
+ip_rfc1812_filter - INTEGER
+	2 - do source validation by reversed path, as specified in RFC1812
+	    Recommended option for single homed hosts and stub network
+	    routers. Could cause troubles for complicated (not loop free)
+	    networks running a slow unreliable protocol (sort of RIP),
+	    or using static routes.
+
+	1 - (DEFAULT) Weaker form of RP filtering: drop all the packets
+	    that look as sourced at a directly connected interface, but
+	    were input from another interface.
+	    
+	0 - No source validation. 
+
+	NOTE: do not disable this option! All BSD derived routing software
+	(sort of gated, routed etc. etc.) is confused by such packets,
+	even if they are valid.
+
+ip_fib_model - INTEGER
+	0 - (DEFAULT) Standard model. All routes are in class MAIN.
+	1 - default routes go to class DEFAULT. This mode should
+	    be very convenient for small ISPs making policy routing.
+	2 - RFC1812 compliant model.
+	    Interface routes are in class MAIN.
+	    Gateway routes are in class DEFAULT.
+
+
+
+Alexey Kuznetsov.
+kuznet@ms2.inr.ac.ru
diff -u --recursive --new-file v2.1.15/linux/Documentation/networking/policy-routing.txt linux/Documentation/networking/policy-routing.txt
--- v2.1.15/linux/Documentation/networking/policy-routing.txt	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/networking/policy-routing.txt	Wed Dec 18 11:45:43 1996
@@ -0,0 +1,150 @@
+Classes
+-------
+
+	"Class" is complete routing table in common sence.
+	I.e. it is tree of nodes (destination prefix, tos, metric)
+	with attached information: gateway, device etc.
+	This tree is looked up as specified in RFC1812 5.2.4.3
+	1. Basic match
+	2. Longest match
+	3. Weak TOS.
+	4. Metric. (should not be in kernel space, but they are)
+	5. Additional pruning rules. (not in kernel space).
+	
+	We have two special type of nodes:
+	REJECT - abort route lookup and return an error value.
+	THROW  - abort route lookup in this class.
+
+
+	Currently number of classes is limited by 255
+	(0 is reserved for "not specified class")
+
+	Three classes are builtin:
+
+	RT_CLASS_LOCAL=255 - local interface addresses,
+	broadcasts, nat addresses.
+
+	RT_CLASS_MAIN=254  - all normal routes are put there
+	by default.
+
+	RT_CLASS_DEFAULT=253 - if ip_fib_model==1, then
+	normal default routes are put there, if ip_fib_model==2
+	all gateway routes are put there.
+
+
+Rules
+-----
+	Rule is record of (src prefix, src interface, tos, dst prefix)
+	with attached information.
+
+	Rule types:
+	RTP_ROUTE - lookup in attached class
+	RTP_NAT   - lookup in attached class and if a match is found,
+		    translate packet source address.
+	RTP_MASQUERADE - lookup in attached class and if a match is found,
+		    masquerade packet as sourced by us.
+	RTP_DROP   - silently drop the packet.
+	RTP_REJECT - drop the packet and send ICMP NET UNREACHABLE.
+	RTP_PROHIBIT - drop the packet and send ICMP COMM. ADM. PROHIBITED.
+
+	Rule flags:
+	RTRF_LOG - log route creations.
+	RTRF_VALVE - One way route (used with masquerading)
+
+Default setup:
+
+root@amber:/pub/ip-routing # iproute -r
+Kernel routing policy rules
+Pref Source             Destination        TOS Iface   Cl
+   0 default            default            00  *       255
+ 254 default            default            00  *       254
+ 255 default            default            00  *       253
+
+
+Lookup algorithm
+----------------
+
+	We scan rules list, and if a rule is matched, apply it.
+	If route is found, return it.
+	If it is not found or THROW node was matched, continue
+	to scan rules.
+
+Applications
+------------
+
+1.	Just ignore classes. All the routes are put to MAIN class
+	(and/or to DEFAULT class).
+
+	HOWTO:  iproute add PREFIX [ tos TOS ] [ gw GW ] [ dev DEV ]
+		[ metric METRIC ] [ reject ] ... (look at iproute utility)
+
+		or use route utility from current net-tools.
+		
+2.	Opposite case. Just forget all that you know about routing
+	tables. Every rule is supplied with its own gateway, device
+	info. record. This approach is not appropriate for automated
+	route maintanance, but it is ideal for manual configuration.
+
+	HOWTO:  iproute addrule [ from PREFIX ] [ to PREFIX ] [ tos TOS ]
+		[ dev INPUTDEV] [ pref PREFERENCE ] route [ gw GATEWAY ]
+		[ dev OUTDEV ] .....
+
+	Warning: just now size of routing table in this approach is
+	limited by 256. If someone will like this model, I'll
+	relax this limitation.
+
+3.	OSPF classes (see RFC1583, RFC1812 E.3.3)
+	Very clean, stable and robust algorithm for OSPF routing
+	domains. Unfortunately, it is not used widely in the Internet.
+
+	Proposed setup:
+	255 local addresses
+	254 interface routes
+	253 ASE routes with external metric
+	252 ASE routes with internal metric
+	251 inter-area routes
+	250 intra-area routes for 1st area
+	249 intra-area routes for 2nd area
+	etc.
+	
+	Rules:
+	iproute addrule class 253
+	iproute addrule class 252
+	iproute addrule class 251
+	iproute addrule to a-prefix-for-1st-area class 250
+	iproute addrule to another-prefix-for-1st-area class 250
+	...
+	iproute addrule to a-prefix-for-2nd-area class 249
+	...
+
+	Area classes must be terminated with reject record.
+	iproute add default reject class 250
+	iproute add default reject class 249
+	...
+
+4.	The Variant Router Requirements Algorithm (RFC1812 E.3.2)
+	Create 16 classes for different TOS values.
+	It is funny, but pretty useless algorithm.
+	I listed it just to show power of new routing code.
+
+5.	All the variaty of combinations......
+
+
+GATED
+-----
+
+	Gated does not understand classes, but it will work
+	happily in MAIN+DEFAULT. All policy routes can be set
+	and maintained manually.
+
+IMPORTANT NOTE
+--------------
+	route.c has compilation time switch CONFIG_IP_LOCAL_RT_POLICY.
+	If it is set, locally originated packets are routed
+	using all the policy list. It is not very convenient and
+	pretty ambiguous, when used with NAT and masquerading.
+	I set it to FALSE by default.
+
+
+Alexey Kuznetov
+kuznet@ms2.inr.ac.ru
diff -u --recursive --new-file v2.1.15/linux/Documentation/networking/routing.txt linux/Documentation/networking/routing.txt
--- v2.1.15/linux/Documentation/networking/routing.txt	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/networking/routing.txt	Wed Dec 18 11:45:43 1996
@@ -0,0 +1,48 @@
+The directory ip-routing contains:
+
+- patch to official linux-2.0 kernel tree
+
+- iproute.c - "professional" routing table maintainance utility.
+
+- rdisc.tar.gz - rdisc daemon, ported from Sun.
+	STRONGLY RECOMMENDED FOR ALL HOSTS.
+
+- routing.tgz - original Mike McLagan's route by source patch.
+		Currently it is obsolete.
+
+- gated.dif-ss<NEWEST>.gz - gated-R3_6Alpha_2 fixes.
+	        Look at README.gated
+
+- mrouted-3.8.dif.gz - mrouted-3.8 fixes.
+
+- rtmon.c - trivial debugging utility: reads and stores netlink.
+
+
+NEWS for user.
+
+- Policy based routing. Routing decisions are made on the base
+  not only of destination address, but also source address,
+  TOS and incoming interface.
+- Complete set of IP level control messages.
+  Now Linux is the only in the world OS comlying to RFC requirements.
+  Great win 8)
+- New interface addressing paradigm.
+  Assignment of address ranges to interface,
+  multiple prefixes etc. etc.
+  Do not bother, it is compatible with old one. Moreover:
+- You more need not make "route add aaa.bbb.ccc... eth0",
+  it is made automatically.
+- "Abstract" UNIX sockets and security enhancements.
+  It is necessary to use TIRPC and TLI emulation library.
+
+NEWS for hacker.
+
+- New destination cache. Flexible, robust and just beatiful.
+- Network stack is reordered, simplified, optimized, a lot of bugs fixed.
+  (well, and new bugs are intoduced, but I've yet not seen them 8))
+  It is difficult to descibe all the changes, look into source.
+
+If you see this file, then this patch works 8)
+
+Alexey Kuznetsov.
+kuznet@ms2.inr.ac.ru
diff -u --recursive --new-file v2.1.15/linux/Documentation/networking/x25.txt linux/Documentation/networking/x25.txt
--- v2.1.15/linux/Documentation/networking/x25.txt	Thu Jan  1 02:00:00 1970
+++ linux/Documentation/networking/x25.txt	Wed Dec 18 11:45:43 1996
@@ -0,0 +1,38 @@
+Linux X.25 Project
+
+As my third year dissertation at University I have taken it upon myself to
+write an X.25 implementation for Linux. My aim is to provide a complete X.25
+Packet Layer and a LAPB module to allow for "normal" X.25 to be run using
+Linux. There are two sorts of X.25 cards available, intelligent ones that
+implement LAPB on the card itself, and unintelligent ones that simply do
+framing, bit-stuffing and checksumming. These both need to be handled by the
+system.
+
+I therefore decided to write the implementation such that as far as the
+Packet Layer is concerned, the link layer was being performed by a lower
+layer of the Linux kernel and therefore it did not concern itself with
+implementation of LAPB. Therefore the LAPB modules would be called by
+unintelligent X.25 card drivers and not by intelligent ones, this would
+provide a uniform device driver interface, and simplify configuration.
+
+To confuse matters a little, an 802.2 LLC implementation for Linux is being
+written which will allow X.25 to be run over an Ethernet (or Token Ring) and
+conform with the JNT "Pink Book", this will have a different interface to
+the Packet Layer but there will be no confusion since the class of device
+being served by the LLC will be completely seperate from LAPB. The LLC
+implementation is being done as part of another protocol project (SNA) and
+by a different author.
+
+Just when you thought that it could not become more confusing, another
+option appeared, XOT. This allows X.25 Packet Layer frames to operate over
+the Internet using TCP/IP as a reliable link layer. An RFC exists that
+specifies the format and behaviour of the protocol. If time permits this
+option will also be actively considered.
+
+It is hoped that a linux-x25 mailing list will be opened soon to allow for
+the discussion of Linux X.25, but it hasn't appeared yet.
+
+Jonathan
+
+jsn@cs.nott.ac.uk
+g4klx@g4klx.demon.co.uk
diff -u --recursive --new-file v2.1.15/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.15/linux/MAINTAINERS	Thu Dec 12 19:36:57 1996
+++ linux/MAINTAINERS	Wed Dec 18 10:47:20 1996
@@ -120,16 +120,16 @@
 S:	Maintained
 
 DAMA SLAVE for AX.25
-P: Joerg Reuter
-M: jreuter@lykos.oche.de
-L: linux-hams@vger.rutgers.edu
-S: Maintained
+P:	Joerg Reuter
+M:	jreuter@lykos.oche.de
+L:	linux-hams@vger.rutgers.edu
+S:	Maintained
 
 Z8530 DRIVER FOR AX.25
-P: Joerg Reuter
-M: jreuter@lykos.oche.de
-L: linux-hams@vger.rutgers.edu
-S: Maintained
+P:	Joerg Reuter
+M:	jreuter@lykos.oche.de
+L:	linux-hams@vger.rutgers.edu
+S:	Maintained
 
 BUSLOGIC SCSI DRIVER
 P:	Leonard N. Zubkoff
@@ -314,6 +314,13 @@
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
+HAYES ESP SERIAL DRIVER:
+P:	Andrew J. Robinson
+M:	arobinso@nyx.net
+L:	linux-kernel@vger.rutgers.edu
+W:	http://www.nyx.net/~arobinso
+S:	Maintainted
+
 MOUSE AND MISC DEVICES [GENERAL]
 P:	Alessandro Rubini
 M:	rubini@ipvvis.unipv.it
@@ -324,6 +331,11 @@
 P:	William Roadcap
 M:	roadcapw@cfw.com
 L:	linux-kernel@vger.rutgers.edu
+S:	Maintained
+
+CONFIGURE.HELP
+P:	Axel Boldt
+M:	boldt@math.ucsb.edu
 S:	Maintained
 
 LANCE AND LANCE32 NETWORK DRIVER
diff -u --recursive --new-file v2.1.15/linux/Makefile linux/Makefile
--- v2.1.15/linux/Makefile	Thu Dec 12 19:36:57 1996
+++ linux/Makefile	Sat Dec 14 14:37:14 1996
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 15
+SUBLEVEL = 16
 
 ARCH = i386
 
diff -u --recursive --new-file v2.1.15/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.1.15/linux/arch/alpha/defconfig	Sat Nov 30 12:03:07 1996
+++ linux/arch/alpha/defconfig	Sun Dec 15 19:41:56 1996
@@ -80,7 +80,7 @@
 #
 # CONFIG_INET_PCTCP is not set
 # CONFIG_INET_RARP is not set
-# CONFIG_NO_PATH_MTU_DISCOVERY is not set
+CONFIG_PATH_MTU_DISCOVERY=y
 CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
 
@@ -160,9 +160,11 @@
 # CONFIG_DGRS is not set
 # CONFIG_NET_POCKET is not set
 # CONFIG_FDDI is not set
+# CONFIG_DLCI is not set
 # CONFIG_PLIP is not set
 # CONFIG_PPP is not set
 # CONFIG_NET_RADIO is not set
+# CONFIG_NET_HAM is not set
 # CONFIG_SLIP is not set
 # CONFIG_TR is not set
 
@@ -206,6 +208,7 @@
 # CONFIG_CYCLADES is not set
 # CONFIG_STALDRV is not set
 # CONFIG_RISCOM8 is not set
+# CONFIG_ESPSERIAL is not set
 # CONFIG_PRINTER is not set
 CONFIG_MOUSE=y
 # CONFIG_ATIXL_BUSMOUSE is not set
diff -u --recursive --new-file v2.1.15/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c
--- v2.1.15/linux/arch/alpha/mm/fault.c	Fri Nov  1 17:13:14 1996
+++ linux/arch/alpha/mm/fault.c	Mon Dec 16 13:06:27 1996
@@ -112,7 +112,7 @@
 	if ((fixup = search_exception_table(regs->pc)) != 0) {
 		unsigned long newpc;
 		newpc = fixup_exception(dpf_reg, fixup, regs->pc);
-		printk("Taking exception at %lx (%lx)\n", regs->pc, newpc);
+		printk("Taking exception at [<%lx>] (%lx)\n", regs->pc, newpc);
 		regs->pc = newpc;
 		return;
 	}
diff -u --recursive --new-file v2.1.15/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- v2.1.15/linux/arch/i386/boot/setup.S	Sat Mar 30 20:58:57 1996
+++ linux/arch/i386/boot/setup.S	Wed Dec 18 11:45:43 1996
@@ -294,6 +294,33 @@
 	stosb
 is_disk1:
 
+! check for Micro Channel (MCA) bus
+	mov ax,cs		! aka #SETUPSEG
+	sub ax,#DELTA_INITSEG	! aka #INITSEG
+	mov ds,ax
+	mov ds,ax
+	xor ax,ax
+	mov [0x220], ax		! set table length to 0
+	mov ah, #0xc0
+	stc
+	int 0x15		! puts feature table at es:bx
+	jc no_mca
+	push ds
+	mov ax,es
+	mov ds,ax
+	mov ax,cs		! aka #SETUPSEG
+	sub ax, #DELTA_INITSEG	! aka #INITSEG
+	mov es,ax
+	mov si,bx
+	mov di,#0x220
+	mov cx,(si)
+	add cx,#2		! table length is a short
+	rep
+	movsb
+	pop ds
+
+no_mca:
+
 ! Check for PS/2 pointing device
 
 	mov	ax,cs		! aka #SETUPSEG
diff -u --recursive --new-file v2.1.15/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.1.15/linux/arch/i386/defconfig	Thu Dec 12 19:36:57 1996
+++ linux/arch/i386/defconfig	Sat Dec 14 14:49:50 1996
@@ -116,6 +116,7 @@
 # CONFIG_PLIP is not set
 # CONFIG_PPP is not set
 # CONFIG_NET_RADIO is not set
+# CONFIG_NET_HAM is not set
 # CONFIG_SLIP is not set
 # CONFIG_TR is not set
 
@@ -159,7 +160,7 @@
 # CONFIG_CYCLADES is not set
 # CONFIG_STALDRV is not set
 # CONFIG_RISCOM8 is not set
-# CONFIG_ESP is not set
+# CONFIG_ESPSERIAL is not set
 # CONFIG_PRINTER is not set
 # CONFIG_MOUSE is not set
 # CONFIG_UMISC is not set
diff -u --recursive --new-file v2.1.15/linux/arch/i386/kernel/Makefile linux/arch/i386/kernel/Makefile
--- v2.1.15/linux/arch/i386/kernel/Makefile	Thu Dec 12 19:36:57 1996
+++ linux/arch/i386/kernel/Makefile	Mon Dec 16 14:36:16 1996
@@ -66,6 +66,6 @@
 	$(CPP) -D__SMP__ -traditional $< -o $@
 
 clean:
-	rm -f trampoline hexify
+	rm -f trampoline hexify trampoline.hex
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.15/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c
--- v2.1.15/linux/arch/i386/kernel/bios32.c	Mon Sep 23 13:22:07 1996
+++ linux/arch/i386/kernel/bios32.c	Wed Dec 18 10:27:06 1996
@@ -46,6 +46,8 @@
  * Apr 16, 1995 : Source merge with the DEC Alpha PCI support. Most of the code
  *	moved to drivers/pci/pci.c.
  *
+ * Dec 7, 1996  : Added support for direct configuration access of boards
+ *      with Intel compatible access schemes (tsbogend@alpha.franken.de)
  *
  */
 
@@ -57,6 +59,7 @@
 
 #include <asm/page.h>
 #include <asm/segment.h>
+#include <asm/io.h>
 
 #define PCIBIOS_PCI_FUNCTION_ID 	0xb1XX
 #define PCIBIOS_PCI_BIOS_PRESENT 	0xb101
@@ -116,6 +119,28 @@
 } bios32_indirect = { 0, KERNEL_CS };
 
 #ifdef CONFIG_PCI
+
+/*
+ * function table for accessing PCI configuration space
+ */
+struct pci_access {
+    int (*find_device)(unsigned short, unsigned short, unsigned short, unsigned char *, unsigned char *);
+    int (*find_class)(unsigned int, unsigned short, unsigned char *, unsigned char *);
+    int (*read_config_byte)(unsigned char, unsigned char, unsigned char, unsigned char *);
+    int (*read_config_word)(unsigned char, unsigned char, unsigned char, unsigned short *);
+    int (*read_config_dword)(unsigned char, unsigned char, unsigned char, unsigned int *);
+    int (*write_config_byte)(unsigned char, unsigned char, unsigned char, unsigned char);
+    int (*write_config_word)(unsigned char, unsigned char, unsigned char, unsigned short);
+    int (*write_config_dword)(unsigned char, unsigned char, unsigned char, unsigned int);
+};
+
+/*
+ * pointer to selected PCI access function table
+ */
+struct pci_access *access_pci = NULL;
+
+
+
 /*
  * Returns the entry point for the given service, NULL on error
  */
@@ -201,12 +226,8 @@
 	return memory_start;
 }
 
-int pcibios_present(void)
-{
-	return pcibios_entry ? 1 : 0;
-}
 
-int pcibios_find_class (unsigned int class_code, unsigned short index,
+int pci_bios_find_class (unsigned int class_code, unsigned short index,
 	unsigned char *bus, unsigned char *device_fn)
 {
 	unsigned long bx;
@@ -228,7 +249,7 @@
 }
 
 
-int pcibios_find_device (unsigned short vendor, unsigned short device_id,
+int pci_bios_find_device (unsigned short vendor, unsigned short device_id,
 	unsigned short index, unsigned char *bus, unsigned char *device_fn)
 {
 	unsigned short bx;
@@ -250,7 +271,7 @@
 	return (int) (ret & 0xff00) >> 8;
 }
 
-int pcibios_read_config_byte(unsigned char bus,
+int pci_bios_read_config_byte(unsigned char bus,
 	unsigned char device_fn, unsigned char where, unsigned char *value)
 {
 	unsigned long ret;
@@ -269,7 +290,7 @@
 	return (int) (ret & 0xff00) >> 8;
 }
 
-int pcibios_read_config_word (unsigned char bus,
+int pci_bios_read_config_word (unsigned char bus,
 	unsigned char device_fn, unsigned char where, unsigned short *value)
 {
 	unsigned long ret;
@@ -288,7 +309,7 @@
 	return (int) (ret & 0xff00) >> 8;
 }
 
-int pcibios_read_config_dword (unsigned char bus,
+int pci_bios_read_config_dword (unsigned char bus,
 	unsigned char device_fn, unsigned char where, unsigned int *value)
 {
 	unsigned long ret;
@@ -307,7 +328,7 @@
 	return (int) (ret & 0xff00) >> 8;
 }
 
-int pcibios_write_config_byte (unsigned char bus,
+int pci_bios_write_config_byte (unsigned char bus,
 	unsigned char device_fn, unsigned char where, unsigned char value)
 {
 	unsigned long ret;
@@ -326,7 +347,7 @@
 	return (int) (ret & 0xff00) >> 8;
 }
 
-int pcibios_write_config_word (unsigned char bus,
+int pci_bios_write_config_word (unsigned char bus,
 	unsigned char device_fn, unsigned char where, unsigned short value)
 {
 	unsigned long ret;
@@ -345,7 +366,7 @@
 	return (int) (ret & 0xff00) >> 8;
 }
 
-int pcibios_write_config_dword (unsigned char bus,
+int pci_bios_write_config_dword (unsigned char bus,
 	unsigned char device_fn, unsigned char where, unsigned int value)
 {
 	unsigned long ret;
@@ -364,6 +385,356 @@
 	return (int) (ret & 0xff00) >> 8;
 }
 
+/*
+ * function table for BIOS32 access
+ */
+struct pci_access pci_bios_access = {
+      pci_bios_find_device,
+      pci_bios_find_class,
+      pci_bios_read_config_byte,
+      pci_bios_read_config_word,
+      pci_bios_read_config_dword,
+      pci_bios_write_config_byte,
+      pci_bios_write_config_word,
+      pci_bios_write_config_dword
+};
+
+
+
+/*
+ * Given the vendor and device ids, find the n'th instance of that device
+ * in the system.  
+ */
+int pci_direct_find_device (unsigned short vendor, unsigned short device_id,
+			   unsigned short index, unsigned char *bus,
+			   unsigned char *devfn)
+{
+    unsigned int curr = 0;
+    struct pci_dev *dev;
+
+    for (dev = pci_devices; dev; dev = dev->next) {
+	if (dev->vendor == vendor && dev->device == device_id) {
+	    if (curr == index) {
+		*devfn = dev->devfn;
+		*bus = dev->bus->number;
+		return PCIBIOS_SUCCESSFUL;
+	    }
+	    ++curr;
+	}
+    }
+    return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+
+/*
+ * Given the class, find the n'th instance of that device
+ * in the system.
+ */
+int pci_direct_find_class (unsigned int class_code, unsigned short index,
+			  unsigned char *bus, unsigned char *devfn)
+{
+    unsigned int curr = 0;
+    struct pci_dev *dev;
+
+    for (dev = pci_devices; dev; dev = dev->next) {
+	if (dev->class == class_code) {
+	    if (curr == index) {
+		*devfn = dev->devfn;
+		*bus = dev->bus->number;
+		return PCIBIOS_SUCCESSFUL;
+	    }
+	    ++curr;
+	}
+    }
+    return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+/*
+ * Functions for accessing PCI configuration space with type 1 accesses
+ */
+#define CONFIG_CMD(bus, device_fn, where)   (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
+
+int pci_conf1_read_config_byte(unsigned char bus, unsigned char device_fn,
+			       unsigned char where, unsigned char *value)
+{
+    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
+    switch (where & 3) {
+	case 0: *value = inb(0xCFC);
+		break;
+	case 1: *value = inb(0xCFD);
+		break;
+	case 2: *value = inb(0xCFE);
+		break;
+	case 3: *value = inb(0xCFF);
+		break;
+    }
+    return PCIBIOS_SUCCESSFUL;
+}
+
+int pci_conf1_read_config_word (unsigned char bus,
+    unsigned char device_fn, unsigned char where, unsigned short *value)
+{
+    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);    
+    if (where & 2)
+    	*value = inw(0xCFE);
+    else
+    	*value = inw(0xCFC);
+    return PCIBIOS_SUCCESSFUL;    
+}
+
+int pci_conf1_read_config_dword (unsigned char bus, unsigned char device_fn, 
+				 unsigned char where, unsigned int *value)
+{
+    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
+    *value = inl(0xCFC);
+    return PCIBIOS_SUCCESSFUL;    
+}
+
+int pci_conf1_write_config_byte (unsigned char bus, unsigned char device_fn, 
+				 unsigned char where, unsigned char value)
+{
+    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);    
+    outb(value, 0xCFC);
+    return PCIBIOS_SUCCESSFUL;
+}
+
+int pci_conf1_write_config_word (unsigned char bus, unsigned char device_fn, 
+				 unsigned char where, unsigned short value)
+{
+    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
+    outw(value, 0xCFC);
+    return PCIBIOS_SUCCESSFUL;
+}
+
+int pci_conf1_write_config_dword (unsigned char bus, unsigned char device_fn, 
+				  unsigned char where, unsigned int value)
+{
+    outl(CONFIG_CMD(bus,device_fn,where), 0xCF8);
+    outl(value, 0xCFC);
+    return PCIBIOS_SUCCESSFUL;
+}
+
+#undef CONFIG_CMD
+
+/*
+ * functiontable for type 1
+ */
+struct pci_access pci_direct_conf1 = {
+      pci_direct_find_device,
+      pci_direct_find_class,
+      pci_conf1_read_config_byte,
+      pci_conf1_read_config_word,
+      pci_conf1_read_config_dword,
+      pci_conf1_write_config_byte,
+      pci_conf1_write_config_word,
+      pci_conf1_write_config_dword
+};
+
+/*
+ * Functions for accessing PCI configuration space with type 2 accesses
+ */
+#define IOADDR(devfn, where)   ((0xC000 | ((devfn & 0x78) << 5)) + where)
+#define FUNC(devfn)            (((devfn & 7) << 1) | 0xf0)
+
+int pci_conf2_read_config_byte(unsigned char bus, unsigned char device_fn, 
+			       unsigned char where, unsigned char *value)
+{
+    if (device_fn & 0x80)
+	return PCIBIOS_DEVICE_NOT_FOUND;
+    outb (FUNC(device_fn), 0xCF8);
+    outb (bus, 0xCFA);
+    *value = inb(IOADDR(device_fn,where));
+    outb (0, 0xCF8);
+    return PCIBIOS_SUCCESSFUL;
+}
+
+int pci_conf2_read_config_word (unsigned char bus, unsigned char device_fn, 
+				unsigned char where, unsigned short *value)
+{
+    if (device_fn & 0x80)
+	return PCIBIOS_DEVICE_NOT_FOUND;
+    outb (FUNC(device_fn), 0xCF8);
+    outb (bus, 0xCFA);
+    *value = inw(IOADDR(device_fn,where));
+    outb (0, 0xCF8);    
+    return PCIBIOS_SUCCESSFUL;
+}
+
+int pci_conf2_read_config_dword (unsigned char bus, unsigned char device_fn, 
+				 unsigned char where, unsigned int *value)
+{
+    if (device_fn & 0x80)
+	return PCIBIOS_DEVICE_NOT_FOUND;
+    outb (FUNC(device_fn), 0xCF8);
+    outb (bus, 0xCFA);
+    *value = inl (IOADDR(device_fn,where));    
+    outb (0, 0xCF8);    
+    return PCIBIOS_SUCCESSFUL;
+}
+
+int pci_conf2_write_config_byte (unsigned char bus, unsigned char device_fn, 
+				 unsigned char where, unsigned char value)
+{
+    outb (FUNC(device_fn), 0xCF8);
+    outb (bus, 0xCFA);
+    outb (value, IOADDR(device_fn,where));
+    outb (0, 0xCF8);    
+    return PCIBIOS_SUCCESSFUL;
+}
+
+int pci_conf2_write_config_word (unsigned char bus, unsigned char device_fn, 
+				 unsigned char where, unsigned short value)
+{
+    outb (FUNC(device_fn), 0xCF8);
+    outb (bus, 0xCFA);
+    outw (value, IOADDR(device_fn,where));
+    outb (0, 0xCF8);    
+    return PCIBIOS_SUCCESSFUL;
+}
+
+int pci_conf2_write_config_dword (unsigned char bus, unsigned char device_fn, 
+				  unsigned char where, unsigned int value)
+{
+    outb (FUNC(device_fn), 0xCF8);
+    outb (bus, 0xCFA);
+    outl (value, IOADDR(device_fn,where));    
+    outb (0, 0xCF8);    
+    return PCIBIOS_SUCCESSFUL;
+}
+
+#undef IOADDR
+#undef FUNC
+
+/*
+ * functiontable for type 2
+ */
+struct pci_access pci_direct_conf2 = {
+      pci_direct_find_device,
+      pci_direct_find_class,
+      pci_conf2_read_config_byte,
+      pci_conf2_read_config_word,
+      pci_conf2_read_config_dword,
+      pci_conf2_write_config_byte,
+      pci_conf2_write_config_word,
+      pci_conf2_write_config_dword
+};
+
+#endif
+
+struct pci_access *check_direct_pci(void)
+{
+    unsigned int tmp;
+
+    /*
+     * check if configuration type 1 works
+     */
+    outb (0x01, 0xCFB);
+    tmp = inl (0xCF8);
+    outl (0x80000000, 0xCF8);
+    if (inl (0xCF8) == 0x80000000) {
+	outl (tmp, 0xCF8);
+	printk("pcibios_init: Using configuration type 1\n");
+	return &pci_direct_conf1;
+    }
+    outl (tmp, 0xCF8);
+
+    /*
+     * check if configuration type 2 works
+     */
+    outb (0x00, 0xCFB);
+    outb (0x00, 0xCF8);
+    outb (0x00, 0xCFA);
+    if (inb (0xCF8) == 0x00 && inb (0xCFC) == 0x00) {
+	printk("pcibios_init: Using configuration type 2\n");
+	return &pci_direct_conf2;
+    }
+    printk("pcibios_init: Not supported chipset for direct PCI access !\n");
+    return NULL;
+}
+
+
+/*
+ * access defined pcibios functions via
+ * the function table
+ */
+
+int pcibios_present(void)
+{
+	return access_pci ? 1 : 0;
+}
+
+int pcibios_find_class (unsigned int class_code, unsigned short index,
+	unsigned char *bus, unsigned char *device_fn)
+{
+   if (access_pci && access_pci->find_class)
+      return access_pci->find_class(class_code, index, bus, device_fn);
+    
+    return PCIBIOS_FUNC_NOT_SUPPORTED;
+}
+
+int pcibios_find_device (unsigned short vendor, unsigned short device_id,
+	unsigned short index, unsigned char *bus, unsigned char *device_fn)
+{
+    if (access_pci && access_pci->find_device)
+      return access_pci->find_device(vendor, device_id, index, bus, device_fn);
+    
+    return PCIBIOS_FUNC_NOT_SUPPORTED;
+}
+
+int pcibios_read_config_byte (unsigned char bus,
+	unsigned char device_fn, unsigned char where, unsigned char *value)
+{
+    if (access_pci && access_pci->read_config_byte)
+      return access_pci->read_config_byte(bus, device_fn, where, value);
+    
+    return PCIBIOS_FUNC_NOT_SUPPORTED;
+}
+
+int pcibios_read_config_word (unsigned char bus,
+	unsigned char device_fn, unsigned char where, unsigned short *value)
+{
+    if (access_pci && access_pci->read_config_word)
+      return access_pci->read_config_word(bus, device_fn, where, value);
+    
+    return PCIBIOS_FUNC_NOT_SUPPORTED;
+}
+
+int pcibios_read_config_dword (unsigned char bus,
+	unsigned char device_fn, unsigned char where, unsigned int *value)
+{
+    if (access_pci && access_pci->read_config_dword)
+      return access_pci->read_config_dword(bus, device_fn, where, value);
+    
+    return PCIBIOS_FUNC_NOT_SUPPORTED;
+}
+
+int pcibios_write_config_byte (unsigned char bus,
+	unsigned char device_fn, unsigned char where, unsigned char value)
+{
+    if (access_pci && access_pci->write_config_byte)
+      return access_pci->write_config_byte(bus, device_fn, where, value);
+    
+    return PCIBIOS_FUNC_NOT_SUPPORTED;
+}
+
+int pcibios_write_config_word (unsigned char bus,
+	unsigned char device_fn, unsigned char where, unsigned short value)
+{
+    if (access_pci && access_pci->write_config_word)
+      return access_pci->write_config_word(bus, device_fn, where, value);
+    
+    return PCIBIOS_FUNC_NOT_SUPPORTED;    
+}
+
+int pcibios_write_config_dword (unsigned char bus,
+	unsigned char device_fn, unsigned char where, unsigned int value)
+{
+    if (access_pci && access_pci->write_config_dword)
+      return access_pci->write_config_dword(bus, device_fn, where, value);
+    
+    return PCIBIOS_FUNC_NOT_SUPPORTED;
+}
+
 const char *pcibios_strerror (int error)
 {
 	static char buf[80];
@@ -399,12 +770,10 @@
 
 unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
 {
-return mem_start;
+    return mem_start;
 }
 
 
-#endif
-
 unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
 {
 	union bios32 *check;
@@ -439,11 +808,13 @@
 		printk ("pcibios_init : BIOS32 Service Directory structure at 0x%p\n", check);
 		if (!bios32_entry) {
 			if (check->fields.entry >= 0x100000) {
-				printk("pcibios_init: entry in high memory, unable to access\n");
+				printk("pcibios_init: entry in high memory, trying direct PCI access\n");
+ 				access_pci = check_direct_pci();
 			} else {
 				bios32_entry = check->fields.entry;
 				printk ("pcibios_init : BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
 				bios32_indirect.address = bios32_entry + PAGE_OFFSET;
+ 				access_pci = &pci_bios_access;
 			}
 		}
 	}
diff -u --recursive --new-file v2.1.15/linux/arch/i386/kernel/ksyms.c linux/arch/i386/kernel/ksyms.c
--- v2.1.15/linux/arch/i386/kernel/ksyms.c	Thu Dec 12 19:36:57 1996
+++ linux/arch/i386/kernel/ksyms.c	Wed Dec 18 11:45:43 1996
@@ -17,6 +17,7 @@
 #include <linux/symtab_begin.h>
 	/* platform dependent support */
 	X(EISA_bus),
+	X(MCA_bus),
 	X(wp_works_ok),
 	X(__verify_write),
 	X(dump_thread),
diff -u --recursive --new-file v2.1.15/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.1.15/linux/arch/i386/kernel/smp.c	Thu Dec 12 19:36:58 1996
+++ linux/arch/i386/kernel/smp.c	Wed Dec 18 11:45:43 1996
@@ -601,11 +601,6 @@
 	smp_commenced=1;
 }
 
-void pointless_func(void)
-{
-	;
-}
- 
 void smp_callin(void)
 {
 	extern void calibrate_delay(void);
diff -u --recursive --new-file v2.1.15/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v2.1.15/linux/arch/i386/mm/fault.c	Thu Dec 12 19:36:58 1996
+++ linux/arch/i386/mm/fault.c	Mon Dec 16 13:06:27 1996
@@ -165,7 +165,7 @@
 
 	/* Are we prepared to handle this fault?  */
 	if ((fixup = search_exception_table(regs->eip)) != 0) {
-		printk(KERN_DEBUG "Exception at %lx (%lx)\n", regs->eip, fixup);
+		printk(KERN_DEBUG "Exception at [<%lx>] (%lx)\n", regs->eip, fixup);
 		regs->eip = fixup;
 		return;
 	}
diff -u --recursive --new-file v2.1.15/linux/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c
--- v2.1.15/linux/arch/m68k/mm/fault.c	Fri Nov 22 18:28:17 1996
+++ linux/arch/m68k/mm/fault.c	Mon Dec 16 13:06:27 1996
@@ -113,7 +113,7 @@
 		fault_pc = regs->pc;
 	if ((fixup = search_exception_table(fault_pc)) != 0) {
 		struct pt_regs *tregs;
-		printk("Exception at %lx (%lx)\n", fault_pc, fixup);
+		printk("Exception at [<%lx>] (%lx)\n", fault_pc, fixup);
 		/* Create a new four word stack frame, discarding the old
 		   one.  */
 		regs->stkadj = frame_extra_sizes[regs->format];
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/Makefile linux/arch/ppc/Makefile
--- v2.1.15/linux/arch/ppc/Makefile	Mon Jul  8 11:27:42 1996
+++ linux/arch/ppc/Makefile	Wed Dec 18 10:49:52 1996
@@ -12,43 +12,49 @@
 #
 # Copyright (C) 1994 by Linus Torvalds
 # Changes for PPC by Gary Thomas
+# Modified by Cort Dougan
 #
 
 # PowerPC (cross) tools
-SUFFIX		=.ppc
-#AS		= /u/cort/ppc/gcc/ppc-linux-elf/bin/as
+SUFFIX		= 
 AS		= as$(SUFFIX)
 ASFLAGS		= 
-#LD		= /u/cort/ppc/gcc/ppc-linux-elf/bin/ld
 LD		= ld$(SUFFIX)
 LINKFLAGS	= -T arch/ppc/ld.script -Ttext 0x90000000 
 HOSTCC		= gcc
-#CC		= /u/cort/ppc/gcc/bin/gcc
 CC		= gcc$(SUFFIX)
-#CC 		= /u/cort/ppc/gcc/bin/gcc.ppc
-CFLAGS		= -D__KERNEL__ -I$(TOPDIR)/include -D__powerpc__ \
+CFLAGSINC	= -D__KERNEL__ -I$(TOPDIR)/include -D__powerpc__
+CFLAGS		= $(CFLAGSINC) \
 		-Wstrict-prototypes \
 		-fomit-frame-pointer \
 		-fno-builtin \
-		-finhibit-size-directive \
-		-O2 -fsigned-char
+		-finhibit-size-directive -fno-strength-reduce\
+		-O2 -fsigned-char -pipe -mstring -mmultiple
 CPP		= $(CC) -E $(CFLAGS)
-#AR		= /u/cort/ppc/gcc/ppc-linux-elf/bin/ar
 AR		= ar$(SUFFIX)
-#RANLIB		= /u/cort/ppc/gcc/ppc-linux-elf/bin/ranlib
-RANLIB		= ar$(SUFFIX)
-#STRIP		= /u/cort/ppc/gcc/ppc-linux-elf/bin/strip
+RANLIB		= ranlib$(SUFFIX)
 STRIP		= strip$(SUFFIX)
-#NM		= /u/cort/ppc/gcc/ppc-linux-elf/bin/nm
 NM		= nm$(SUFFIX)
 
+ifdef CONFIG_603
+CFLAGS := $(CFLAGS) -mcpu=603 -DCPU=603
+endif
+
+ifdef CONFIG_603e
+CFLAGS := $(CFLAGS) -mcpu=603e -DCPU=603e
+endif
+
+ifdef CONFIG_604
+CFLAGS := $(CFLAGS) -mcpu=604 -DCPU=604
+endif
+
 #
 # NFS_ROOT_NAME specifies the default name of the directory to mount
 # as root via NFS, if the kernel does not get the "root=" option from
 # the boot loader. The "%s" will be replaced by the IP-number of the
 # local system.
 #
-NFS_ROOT = -DNFS_ROOT="\"/joplin/ppc/root/\""
+NFS_ROOT = -DNFS_ROOT="\"/joplin/ppc/root\""
 
 HEAD := arch/ppc/kernel/head.o
 
@@ -59,10 +65,20 @@
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
-tImage: vmlinux
-	@$(MAKEBOOT) tImage
+netboot: vmlinux
+	@$(MAKEBOOT) netboot
+
+znetboot: vmlinux
+	@$(MAKEBOOT) znetboot
+
+zImage: vmlinux
+	@$(MAKEBOOT) zImage
 
+floppy: vmlinux
+	@$(MAKEBOOT) floppy
 
+install: vmlinux
+	@$(MAKEBOOT) install
 
 arch/ppc/kernel: dummy
 	$(MAKE) linuxsubdirs SUBDIRS=arch/ppc/kernel
@@ -75,10 +91,10 @@
 
 
 archclean:
-	/bin/rm -f arch/ppc/*/*.o #arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h
-	/bin/rm -f arch/ppc/*~ arch/ppc/*/*~ include/asm-ppc/*~ arch/ppc/boot/mkboot
+	rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h TAGS
+	@$(MAKEBOOT) clean
 
 archdep:
 
 corttags :
-	etags arch/ppc/*/*.c include/asm-ppc/* drivers/*/*.c net/*.c */*.c
+	etags arch/ppc/*/*.c include/asm/* */*.c drivers/*/*.c net/*.c
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile
--- v2.1.15/linux/arch/ppc/boot/Makefile	Mon Jul  8 11:27:42 1996
+++ linux/arch/ppc/boot/Makefile	Wed Dec 18 10:49:52 1996
@@ -20,30 +20,61 @@
 .S.o:
 	$(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
 
-OBJECTS = head.o main.o
 
-all:	linux.boot mkboot
+ZLINKFLAGS = -T ../ld.script -Ttext 0x00800000
+GZIP_FLAGS = -9
 
-linux.boot: $(TOPDIR)/vmlinux mkboot
-	rsh charon /bin/rm -f /usr/tftpboot/vmlinux
-	/bin/rm -f /usr/tftpboot/vmlinux
-	./mkboot $(TOPDIR)/vmlinux /usr/tftpboot/vmlinux
-	rcp /usr/tftpboot/vmlinux charon:/usr/tftpboot/vmlinux
-	sync
-
-tImage: mk_type41 $(TOPDIR)/vmlinux mkboot
-	./mkboot $(TOPDIR)/vmlinux vmlinux 
-	mk_type41 vmlinux tImage
-	rm vmlinux
+SYSTEM = $(TOPDIR)/vmlinux
+
+OBJECTS = head.o inflate.o unzip.o misc.o vreset.o
+
+CFLAGS = -O2 -DSTDC_HEADERS -I$(TOPDIR)/include
+
+all:	$(TOPDIR)/zImage
 
 mkboot : cortstrip.c
-	$(HOSTCC) -o mkboot cortstrip.c
+	$(HOSTCC) $(CFLAGSINC) -Wl,-static -o mkboot cortstrip.c
 
 mk_type41: mk_type41.c
-	gcc -o mk_type41 mk_type41.c
+	$(HOSTCC) $(CFLAGSINC) -Wl,-static -o mk_type41 mk_type41.c
+
+floppy: zImage $(TOPDIR)/vmlinux
+	dd if=$(TOPDIR)/zImage of=/dev/fd0H1440 bs=64b
+
+netboot : $(TOPDIR)/vmlinux mkboot
+	mkboot $(TOPDIR)/vmlinux $(TOPDIR)/netboot
+#	rcp $(TOPDIR)/netboot charon:/usr/tftpboot/vmlinux
+
+znetboot : mkboot zvmlinux
+	mkboot zvmlinux $(TOPDIR)/znetboot
+	rcp $(TOPDIR)/znetboot charon:/usr/tftpboot/vmlinux
+
+zImage: mk_type41 zvmlinux
+# make znetboot ourselves since using the normal dep
+# will rcp it -- Cort
+	mkboot zvmlinux $(TOPDIR)/znetboot
+	mk_type41 $(TOPDIR)/znetboot $(TOPDIR)/zImage
+
+install: zImage
+	dd if=$(TOPDIR)/zImage of=/dev/sda4
+	ln -s /dev/sda4 $(INSTALL_PATH)/vmlinuz
+	cp $(TOPDIR)/System.map $(INSTALL_PATH)/	
+
+zvmlinux: $(OBJECTS) $(SYSTEM) piggyback netboot $(TOPDIR)/vmlinux
+	gzip ${GZIP_FLAGS} <$(TOPDIR)/netboot | ./piggyback | $(AS) -o piggy.o
+	$(LD) $(ZLINKFLAGS) -o zvmlinux $(OBJECTS) piggy.o
+	rm -f piggy.o xx_boot
+
+head.o:	head.s
+
+head.s: head.S $(TOPDIR)/include/linux/tasks.h
+	$(CPP) -traditional head.S -o head.s
+
+piggyback: piggyback.c
+	$(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
 
 clean:
-	rsh charon /bin/rm -f /usr/tftpboot/vmlinux
-	/bin/rm -f /usr/tftpboot/vmlinux
+	rm -f piggyback zvmlinux mk_type41 mkprep mkboot
+	rm -f $(TOPDIR)/{zImage,znetboot,netboot}
 
 dep:
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/compressed/Makefile linux/arch/ppc/boot/compressed/Makefile
--- v2.1.15/linux/arch/ppc/boot/compressed/Makefile	Mon Jul  8 11:27:42 1996
+++ linux/arch/ppc/boot/compressed/Makefile	Thu Jan  1 02:00:00 1970
@@ -1,53 +0,0 @@
-#
-# linux/arch/ppc/boot/compressed/Makefile
-#
-# create a compressed vmlinux image from the original vmlinux
-#
-
-TOPDIR = ../../../..
-CC = cc.ppc
-AS = as.ppc
-LD = ld.ppc
-ZLINKFLAGS = -T ../../ld.script -Ttext 0x00400000
-HOSTCC = cc
-#GZIP_FLAGS = -9
-GZIP_FLAGS =
-
-HEAD = head.o
-SYSTEM = $(TOPDIR)/vmlinux
-
-OBJECTS = $(HEAD) inflate.o unzip.o misc.o
-
-CFLAGS = -O2 -DSTDC_HEADERS
-
-.c.s:
-	$(CC) $(CFLAGS) -S $<
-.s.o:
-	$(AS) -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-
-all: vmlinux
-
-vmlinux: $(OBJECTS) $(SYSTEM) piggyback
-	mkboot $(TOPDIR)/vmlinux xx_boot 0
-	gzip ${GZIP_FLAGS} <xx_boot | ./piggyback | $(AS) -o piggy.o
-	$(LD) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.o
-	rm -f piggy.o xx_boot
-
-vmlinux.no_ramdisk: $(OBJECTS) piggyback
-	mkboot $(TOPDIR)/vmlinux.no_ramdisk xx_boot 0
-	gzip ${GZIP_FLAGS} <xx_boot | ./piggyback | $(AS) -o piggy.o
-	$(LD) $(ZLINKFLAGS) -o vmlinux.no_ramdisk $(OBJECTS) piggy.o
-	rm -f piggy.o xx_boot
-
-head.o:	head.s
-
-head.s: head.S $(TOPDIR)/include/linux/tasks.h
-	$(CPP) -traditional head.S -o head.s
-
-piggyback: piggyback.c
-	$(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
-
-clean:
-	rm -f piggyback vmlinux
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/compressed/crypt.h linux/arch/ppc/boot/compressed/crypt.h
--- v2.1.15/linux/arch/ppc/boot/compressed/crypt.h	Mon May 27 12:00:57 1996
+++ linux/arch/ppc/boot/compressed/crypt.h	Thu Jan  1 02:00:00 1970
@@ -1,12 +0,0 @@
-/* crypt.h (dummy version) -- do not perform encryption
- * Hardly worth copyrighting :-)
- */
-
-#ifdef CRYPT
-#  undef CRYPT      /* dummy version */
-#endif
-
-#define RAND_HEAD_LEN  12  /* length of encryption random header */
-
-#define zencode
-#define zdecode
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/compressed/gzip.h linux/arch/ppc/boot/compressed/gzip.h
--- v2.1.15/linux/arch/ppc/boot/compressed/gzip.h	Mon May 27 12:00:57 1996
+++ linux/arch/ppc/boot/compressed/gzip.h	Thu Jan  1 02:00:00 1970
@@ -1,284 +0,0 @@
-/* gzip.h -- common declarations for all gzip modules
- * Copyright (C) 1992-1993 Jean-loup Gailly.
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- */
-
-#if defined(__STDC__) || defined(PROTO)
-#  define OF(args)  args
-#else
-#  define OF(args)  ()
-#endif
-
-#ifdef __STDC__
-   typedef void *voidp;
-#else
-   typedef char *voidp;
-#endif
-
-/* I don't like nested includes, but the string functions are used too often */
-#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
-#  include <string.h>
-#  define memzero(s, n)     memset ((s), 0, (n))
-#else
-#  include <strings.h>
-#  define strchr            index 
-#  define strrchr           rindex
-#  define memcpy(d, s, n)   bcopy((s), (d), (n)) 
-#  define memcmp(s1, s2, n) bcmp((s1), (s2), (n)) 
-#  define memzero(s, n)     bzero((s), (n))
-#endif
-
-#if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H)
-#  include <memory.h>
-#endif
-
-#ifndef RETSIGTYPE
-#  define RETSIGTYPE void
-#endif
-
-#define local static
-
-typedef unsigned char  uch;
-typedef unsigned short ush;
-typedef unsigned long  ulg;
-
-/* Return codes from gzip */
-#define OK      0
-#define ERROR   1
-#define WARNING 2
-
-/* Compression methods (see algorithm.doc) */
-#define STORED     0
-#define COMPRESSED 1
-#define PACKED     2
-/* methods 3 to 7 reserved */
-#define DEFLATED   8
-extern int method;         /* compression method */
-
-/* To save memory for 16 bit systems, some arrays are overlayed between
- * the various modules:
- * deflate:  prev+head   window      d_buf  l_buf  outbuf
- * unlzw:    tab_prefix  tab_suffix  stack  inbuf  outbuf
- * inflate:              window             inbuf
- * unpack:               window             inbuf
- * For compression, input is done in window[]. For decompression, output
- * is done in window except for unlzw.
- */
-
-#ifndef	INBUFSIZ
-#  define INBUFSIZ  0x8000  /* input buffer size */
-#endif
-#define INBUF_EXTRA  64     /* required by unlzw() */
-
-#ifndef	OUTBUFSIZ
-#  define OUTBUFSIZ  16384  /* output buffer size */
-#endif
-#define OUTBUF_EXTRA 2048   /* required by unlzw() */
-
-#define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */
-
-#ifdef DYN_ALLOC
-#  define EXTERN(type, array)  extern type * near array
-#  define DECLARE(type, array, size)  type * near array
-#  define ALLOC(type, array, size) { \
-      array = (type*)fcalloc((unsigned)(((size)+1L)/2), 2*sizeof(type)); \
-      if (array == NULL) error("insufficient memory"); \
-   }
-#  define FREE(array) {if (array != NULL) fcfree(array), array=NULL;}
-#else
-#  define EXTERN(type, array)  extern type array[]
-#  define DECLARE(type, array, size)  type array[size]
-#  define ALLOC(type, array, size)
-#  define FREE(array)
-#endif
-
-EXTERN(uch, inbuf);          /* input buffer */
-EXTERN(uch, outbuf);         /* output buffer */
-EXTERN(ush, d_buf);          /* buffer for distances, see trees.c */
-EXTERN(uch, window);         /* Sliding window and suffix table (unlzw) */
-#define tab_suffix window
-#ifndef MAXSEG_64K
-#  define tab_prefix prev    /* hash link (see deflate.c) */
-#  define head (prev+WSIZE)  /* hash head (see deflate.c) */
-   EXTERN(ush, tab_prefix);  /* prefix code (see unlzw.c) */
-#else
-#  define tab_prefix0 prev
-#  define head tab_prefix1
-   EXTERN(ush, tab_prefix0); /* prefix for even codes */
-   EXTERN(ush, tab_prefix1); /* prefix for odd  codes */
-#endif
-
-extern unsigned insize; /* valid bytes in inbuf */
-extern unsigned inptr;  /* index of next byte to be processed in inbuf */
-extern unsigned outcnt; /* bytes in output buffer */
-
-extern long bytes_in;   /* number of input bytes */
-extern long bytes_out;  /* number of output bytes */
-extern long overhead;   /* number of bytes in gzip header */
-
-#define isize bytes_in
-/* for compatibility with old zip sources (to be cleaned) */
-
-extern int  ifd;        /* input file descriptor */
-extern int  ofd;        /* output file descriptor */
-extern char ifname[];   /* input filename or "stdin" */
-extern char ofname[];   /* output filename or "stdout" */
-
-extern ulg time_stamp;  /* original time stamp (modification time) */
-extern long ifile_size; /* input file size, -1 for devices (debug only) */
-
-extern int exit_code;   /* program exit code */
-
-typedef int file_t;     /* Do not use stdio */
-#define NO_FILE  (-1)   /* in memory compression */
-
-
-#define	GZIP_MAGIC     "\037\213" /* Magic header for gzip files, 1F 8B */
-#define	OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */
-#define	PKZIP_MAGIC  "PK\003\004" /* Magic header for pkzip files */
-#define	PACK_MAGIC     "\037\036" /* Magic header for packed files */
-
-/* gzip flag byte */
-#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
-#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
-#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
-#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
-#define COMMENT      0x10 /* bit 4 set: file comment present */
-#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
-#define RESERVED     0xC0 /* bit 6,7:   reserved */
-
-/* internal file attribute */
-#define UNKNOWN (-1)
-#define BINARY  0
-#define ASCII   1
-
-#ifndef WSIZE
-#  define WSIZE 0x8000     /* window size--must be a power of two, and */
-#endif                     /*  at least 32K for zip's deflate method */
-
-#define MIN_MATCH  3
-#define MAX_MATCH  258
-/* The minimum and maximum match lengths */
-
-#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
-/* Minimum amount of lookahead, except at the end of the input file.
- * See deflate.c for comments about the MIN_MATCH+1.
- */
-
-#define MAX_DIST  (WSIZE-MIN_LOOKAHEAD)
-/* In order to simplify the code, particularly on 16 bit machines, match
- * distances are limited to MAX_DIST instead of WSIZE.
- */
-
-extern int decrypt;        /* flag to turn on decryption */
-extern int save_orig_name; /* set if original name must be saved */
-extern int verbose;        /* be verbose (-v) */
-extern int level;          /* compression level */
-extern int test;           /* check .z file integrity */
-extern int to_stdout;      /* output to stdout (-c) */
-
-#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
-
-/* put_byte is used for the compressed output, put_char for the
- * uncompressed output. However unlzw() uses window for its
- * suffix table instead of its output buffer, so it does not use put_char.
- * (to be cleaned up).
- */
-#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
-   flush_outbuf();}
-#define put_char(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\
-   flush_window();}
-
-/* Output a 16 bit value, lsb first */
-#define put_short(w) \
-{ if (outcnt < OUTBUFSIZ-2) { \
-    outbuf[outcnt++] = (uch) ((w) & 0xff); \
-    outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \
-  } else { \
-    put_byte((uch)((w) & 0xff)); \
-    put_byte((uch)((ush)(w) >> 8)); \
-  } \
-}
-
-/* Output a 32 bit value to the bit stream, lsb first */
-#define put_long(n) { \
-    put_short((n) & 0xffff); \
-    put_short(((ulg)(n)) >> 16); \
-}
-
-#define seekable()    0  /* force sequential output */
-#define translate_eol 0  /* no option -a yet */
-
-#define tolow(c)  (isupper(c) ? (c)-'A'+'a' : (c))    /* force to lower case */
-
-/* Macros for getting two-byte and four-byte header values */
-#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8))
-#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16))
-
-/* Diagnostic functions */
-#ifdef DEBUG
-#  define Assert(cond,msg) {if(!(cond)) error(msg);}
-#  define Trace(x) fprintf x
-#  define Tracev(x) {if (verbose) fprintf x ;}
-#  define Tracevv(x) {if (verbose>1) fprintf x ;}
-#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
-#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
-#else
-#  define Assert(cond,msg)
-#  define Trace(x)
-#  define Tracev(x)
-#  define Tracevv(x)
-#  define Tracec(c,x)
-#  define Tracecv(c,x)
-#endif
-
-	/* in zip.c: */
-extern void zip    OF((int in, int out));
-extern int file_read  OF((char *buf,  unsigned size));
-
-	/* in unzip.c */
-extern void unzip        OF((int in, int out));
-extern int check_zipfile OF((int in));
-
-	/* in unpack.c */
-extern void unpack        OF((int in, int out));
-
-	/* in gzip.c */
-RETSIGTYPE abort_gzip   OF((void));
-
-        /* in deflate.c */
-void lm_init OF((int pack_level, ush *flags));
-ulg  deflate OF((void));
-
-        /* in trees.c */
-void ct_init     OF((ush *attr, int *method));
-int  ct_tally    OF((int dist, int lc));
-ulg  flush_block OF((char *buf, ulg stored_len, int eof));
-
-        /* in bits.c */
-void     bi_init    OF((file_t zipfile));
-void     send_bits  OF((int value, int length));
-unsigned bi_reverse OF((unsigned value, int length));
-void     bi_windup  OF((void));
-void     copy_block OF((char *buf, unsigned len, int header));
-extern   int (*read_buf) OF((char *buf, unsigned size));
-
-	/* in util.c: */
-extern ulg  updcrc        OF((uch *s, unsigned n));
-extern void clear_bufs    OF((void));
-extern int  fill_inbuf    OF((void));
-extern void flush_outbuf  OF((void));
-extern void flush_window  OF((void));
-extern char *strlwr       OF((char *s));
-extern char *basename     OF((char *fname));
-extern char *add_envopt   OF((int *argcp, char ***argvp, char *env));
-extern void error         OF((char *m));
-extern void warn          OF((char *a, char *b));
-extern void read_error    OF((void));
-extern void write_error   OF((void));
-extern void display_ratio OF((long num, long den));
-extern voidp xmalloc      OF((unsigned int size));
-
-	/* in inflate.c */
-extern int inflate OF((void));
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/compressed/head.S linux/arch/ppc/boot/compressed/head.S
--- v2.1.15/linux/arch/ppc/boot/compressed/head.S	Mon May 27 12:00:57 1996
+++ linux/arch/ppc/boot/compressed/head.S	Thu Jan  1 02:00:00 1970
@@ -1,33 +0,0 @@
-#include "ppc_defs.h"
-
-	.text
-/*
- * This code may be executed by a bootstrap process.  If so, the
- * purpose is to relocate the loaded image to it's final location
- * in memory.
- *    R3: End of image
- *    R4: Start of image - 0x400
- *
- */
-	.globl	start
-start:
-	addi	r4,r4,0x400	/* Point at start of image */
-	lis	r5,start@h	/* Load address */
-	ori	r5,r5,start@l
-	subi	r4,r4,4		/* Adjust for auto-increment */
-	subi	r5,r5,4
-	subi	r3,r3,4
-00:	lwzu	r0,4(r4)	/* Fast move */
-	stwu	r0,4(r5)
-	cmp	0,r3,r4
-	bne	00b
-	lis	r5,continue@h	/* Actual code starts here */
-	ori	r5,r5,continue@l
-	mtlr	r5
-	blr
-
-continue:
-	bl	decompress_kernel
-	li	r5,0x100	/* Kernel code starts here */
-	mtlr	r5
-	blr	
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/compressed/inflate.c linux/arch/ppc/boot/compressed/inflate.c
--- v2.1.15/linux/arch/ppc/boot/compressed/inflate.c	Mon May 27 12:00:57 1996
+++ linux/arch/ppc/boot/compressed/inflate.c	Thu Jan  1 02:00:00 1970
@@ -1,810 +0,0 @@
-#define DEBG(x)
-#define DEBG1(x)
-/* inflate.c -- Not copyrighted 1992 by Mark Adler
-   version c10p1, 10 January 1993 */
-
-/* 
- * Adapted for booting Linux by Hannu Savolainen 1993
- * based on gzip-1.0.3 
- */
-
-#ifndef lint
-static char rcsid[] = "$Id: inflate.c,v 0.10 1993/02/04 13:21:06 jloup Exp $";
-#endif
-
-#include "gzip.h"
-#define slide window
-
-#if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H)
-#  include <sys/types.h>
-#  include <stdlib.h>
-#endif
-
-struct huft {
-  uch e;                /* number of extra bits or operation */
-  uch b;                /* number of bits in this code or subcode */
-  union {
-    ush n;              /* literal, length base, or distance base */
-    struct huft *t;     /* pointer to next level of table */
-  } v;
-};
-
-
-/* Function prototypes */
-int huft_build OF((unsigned *, unsigned, unsigned, ush *, ush *,
-                   struct huft **, int *));
-int huft_free OF((struct huft *));
-int inflate_codes OF((struct huft *, struct huft *, int, int));
-int inflate_stored OF((void));
-int inflate_fixed OF((void));
-int inflate_dynamic OF((void));
-int inflate_block OF((int *));
-int inflate OF((void));
-
-
-#define wp outcnt
-#define flush_output(w) (wp=(w),flush_window())
-
-/* Tables for deflate from PKZIP's appnote.txt. */
-static unsigned border[] = {    /* Order of the bit length code lengths */
-        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
-static ush cplens[] = {         /* Copy lengths for literal codes 257..285 */
-        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
-        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
-        /* note: see note #13 above about the 258 in this list. */
-static ush cplext[] = {         /* Extra bits for literal codes 257..285 */
-        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
-        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
-static ush cpdist[] = {         /* Copy offsets for distance codes 0..29 */
-        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
-        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
-        8193, 12289, 16385, 24577};
-static ush cpdext[] = {         /* Extra bits for distance codes */
-        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
-        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
-        12, 12, 13, 13};
-
-
-ulg bb;                         /* bit buffer */
-unsigned bk;                    /* bits in bit buffer */
-
-ush mask_bits[] = {
-    0x0000,
-    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
-    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
-};
-
-#ifdef CRYPT
-  uch cc;
-#  define NEXTBYTE() \
-     (decrypt ? (cc = get_byte(), zdecode(cc), cc) : get_byte())
-#else
-#  define NEXTBYTE()  (uch)get_byte()
-#endif
-#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
-#define DUMPBITS(n) {b>>=(n);k-=(n);}
-
-int lbits = 9;          /* bits in base literal/length lookup table */
-int dbits = 6;          /* bits in base distance lookup table */
-
-
-/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
-#define BMAX 16         /* maximum bit length of any code (16 for explode) */
-#define N_MAX 288       /* maximum number of codes in any set */
-
-
-unsigned hufts;         /* track memory usage */
-
-
-int huft_build(b, n, s, d, e, t, m)
-unsigned *b;            /* code lengths in bits (all assumed <= BMAX) */
-unsigned n;             /* number of codes (assumed <= N_MAX) */
-unsigned s;             /* number of simple-valued codes (0..s-1) */
-ush *d;                 /* list of base values for non-simple codes */
-ush *e;                 /* list of extra bits for non-simple codes */
-struct huft **t;        /* result: starting table */
-int *m;                 /* maximum lookup bits, returns actual */
-/* Given a list of code lengths and a maximum table size, make a set of
-   tables to decode that set of codes.  Return zero on success, one if
-   the given code set is incomplete (the tables are still built in this
-   case), two if the input is invalid (all zero length codes or an
-   oversubscribed set of lengths), and three if not enough memory. */
-{
-  unsigned a;                   /* counter for codes of length k */
-  unsigned c[BMAX+1];           /* bit length count table */
-  unsigned f;                   /* i repeats in table every f entries */
-  int g;                        /* maximum code length */
-  int h;                        /* table level */
-  register unsigned i;          /* counter, current code */
-  register unsigned j;          /* counter */
-  register int k;               /* number of bits in current code */
-  int l;                        /* bits per table (returned in m) */
-  register unsigned *p;         /* pointer into c[], b[], or v[] */
-  register struct huft *q;      /* points to current table */
-  struct huft r;                /* table entry for structure assignment */
-  struct huft *u[BMAX];         /* table stack */
-  unsigned v[N_MAX];            /* values in order of bit length */
-  register int w;               /* bits before this table == (l * h) */
-  unsigned x[BMAX+1];           /* bit offsets, then code stack */
-  unsigned *xp;                 /* pointer into x */
-  int y;                        /* number of dummy codes added */
-  unsigned z;                   /* number of entries in current table */
-
-DEBG("huft1 ");
-
-  /* Generate counts for each bit length */
-  memzero(c, sizeof(c));
-  p = b;  i = n;
-  do {
-    c[*p++]++;                  /* assume all entries <= BMAX */
-  } while (--i);
-  if (c[0] == n)                /* null input--all zero length codes */
-  {
-    *t = (struct huft *)NULL;
-    *m = 0;
-    return 0;
-  }
-
-DEBG("huft2 ");
-
-  /* Find minimum and maximum length, bound *m by those */
-  l = *m;
-  for (j = 1; j <= BMAX; j++)
-    if (c[j])
-      break;
-  k = j;                        /* minimum code length */
-  if ((unsigned)l < j)
-    l = j;
-  for (i = BMAX; i; i--)
-    if (c[i])
-      break;
-  g = i;                        /* maximum code length */
-  if ((unsigned)l > i)
-    l = i;
-  *m = l;
-
-DEBG("huft3 ");
-
-  /* Adjust last length count to fill out codes, if needed */
-  for (y = 1 << j; j < i; j++, y <<= 1)
-    if ((y -= c[j]) < 0)
-      return 2;                 /* bad input: more codes than bits */
-  if ((y -= c[i]) < 0)
-    return 2;
-  c[i] += y;
-
-DEBG("huft4 ");
-
-  /* Generate starting offsets into the value table for each length */
-  x[1] = j = 0;
-  p = c + 1;  xp = x + 2;
-  while (--i) {                 /* note that i == g from above */
-    *xp++ = (j += *p++);
-  }
-
-DEBG("huft5 ");
-
-  /* Make a table of values in order of bit lengths */
-  p = b;  i = 0;
-  do {
-    if ((j = *p++) != 0)
-      v[x[j]++] = i;
-  } while (++i < n);
-
-DEBG("h6 ");
-
-  /* Generate the Huffman codes and for each, make the table entries */
-  x[0] = i = 0;                 /* first Huffman code is zero */
-  p = v;                        /* grab values in bit order */
-  h = -1;                       /* no tables yet--level -1 */
-  w = -l;                       /* bits decoded == (l * h) */
-  u[0] = (struct huft *)NULL;   /* just to keep compilers happy */
-  q = (struct huft *)NULL;      /* ditto */
-  z = 0;                        /* ditto */
-DEBG("h6a ");
-
-  /* go through the bit lengths (k already is bits in shortest code) */
-  for (; k <= g; k++)
-  {
-DEBG("h6b ");
-    a = c[k];
-    while (a--)
-    {
-DEBG("h6b1 ");
-      /* here i is the Huffman code of length k bits for value *p */
-      /* make tables up to required level */
-      while (k > w + l)
-      {
-DEBG1("1 ");
-        h++;
-        w += l;                 /* previous table always l bits */
-
-        /* compute minimum size table less than or equal to l bits */
-        z = (z = g - w) > (unsigned)l ? l : z;  /* upper limit on table size */
-        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
-        {                       /* too few codes for k-w bit table */
-DEBG1("2 ");
-          f -= a + 1;           /* deduct codes from patterns left */
-          xp = c + k;
-          while (++j < z)       /* try smaller tables up to z bits */
-          {
-            if ((f <<= 1) <= *++xp)
-              break;            /* enough codes to use up j bits */
-            f -= *xp;           /* else deduct codes from patterns */
-          }
-        }
-DEBG1("3 ");
-        z = 1 << j;             /* table entries for j-bit table */
-
-        /* allocate and link in new table */
-        q = (struct huft *)malloc((z + 1)*sizeof(struct huft));
-DEBG1("4 ");
-        hufts += z + 1;         /* track memory usage */
-        *t = q + 1;             /* link to list for huft_free() */
-        *(t = &(q->v.t)) = (struct huft *)NULL;
-        u[h] = ++q;             /* table starts after link */
-
-DEBG1("5 ");
-        /* connect to last table, if there is one */
-        if (h)
-        {
-          x[h] = i;             /* save pattern for backing up */
-          r.b = (uch)l;         /* bits to dump before this table */
-          r.e = (uch)(16 + j);  /* bits in this table */
-          r.v.t = q;            /* pointer to this table */
-          j = i >> (w - l);     /* (get around Turbo C bug) */
-          u[h-1][j] = r;        /* connect to last table */
-        }
-DEBG1("6 ");
-      }
-DEBG("h6c ");
-
-      /* set up table entry in r */
-      r.b = (uch)(k - w);
-      if (p >= v + n)
-        r.e = 99;               /* out of values--invalid code */
-      else if (*p < s)
-      {
-        r.e = (uch)(*p < 256 ? 16 : 15);    /* 256 is end-of-block code */
-        r.v.n = *p++;           /* simple code is just the value */
-      }
-      else
-      {
-        r.e = (uch)e[*p - s];   /* non-simple--look up in lists */
-        r.v.n = d[*p++ - s];
-      }
-DEBG("h6d ");
-
-      /* fill code-like entries with r */
-      f = 1 << (k - w);
-      for (j = i >> w; j < z; j += f)
-        q[j] = r;
-
-      /* backwards increment the k-bit code i */
-      for (j = 1 << (k - 1); i & j; j >>= 1)
-        i ^= j;
-      i ^= j;
-
-      /* backup over finished tables */
-      while ((i & ((1 << w) - 1)) != x[h])
-      {
-        h--;                    /* don't need to update q */
-        w -= l;
-      }
-DEBG("h6e ");
-    }
-DEBG("h6f ");
-  }
-
-DEBG("huft7 ");
-
-  /* Return true (1) if we were given an incomplete table */
-  return y != 0 && g != 1;
-}
-
-
-
-int huft_free(t)
-struct huft *t;         /* table to free */
-/* Free the malloc'ed tables built by huft_build(), which makes a linked
-   list of the tables it made, with the links in a dummy first entry of
-   each table. */
-{
-  register struct huft *p, *q;
-
-
-  /* Go through linked list, freeing from the malloced (t[-1]) address. */
-  p = t;
-  while (p != (struct huft *)NULL)
-  {
-    q = (--p)->v.t;
-    free(p);
-    p = q;
-  } 
-  return 0;
-}
-
-
-int inflate_codes(tl, td, bl, bd)
-struct huft *tl, *td;   /* literal/length and distance decoder tables */
-int bl, bd;             /* number of bits decoded by tl[] and td[] */
-/* inflate (decompress) the codes in a deflated (compressed) block.
-   Return an error code or zero if it all goes ok. */
-{
-  register unsigned e;  /* table entry flag/number of extra bits */
-  unsigned n, d;        /* length and index for copy */
-  unsigned w;           /* current window position */
-  struct huft *t;       /* pointer to table entry */
-  unsigned ml, md;      /* masks for bl and bd bits */
-  register ulg b;       /* bit buffer */
-  register unsigned k;  /* number of bits in bit buffer */
-
-
-  /* make local copies of globals */
-  b = bb;                       /* initialize bit buffer */
-  k = bk;
-  w = wp;                       /* initialize window position */
-
-  /* inflate the coded data */
-  ml = mask_bits[bl];           /* precompute masks for speed */
-  md = mask_bits[bd];
-  for (;;)                      /* do until end of block */
-  {
-    NEEDBITS((unsigned)bl)
-    if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
-      do {
-        if (e == 99)
-          return 1;
-        DUMPBITS(t->b)
-        e -= 16;
-        NEEDBITS(e)
-      } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
-    DUMPBITS(t->b)
-    if (e == 16)                /* then it's a literal */
-    {
-      slide[w++] = (uch)t->v.n;
-      if (w == WSIZE)
-      {
-        flush_output(w);
-        w = 0;
-      }
-    }
-    else                        /* it's an EOB or a length */
-    {
-      /* exit if end of block */
-      if (e == 15)
-        break;
-
-      /* get length of block to copy */
-      NEEDBITS(e)
-      n = t->v.n + ((unsigned)b & mask_bits[e]);
-      DUMPBITS(e);
-
-      /* decode distance of block to copy */
-      NEEDBITS((unsigned)bd)
-      if ((e = (t = td + ((unsigned)b & md))->e) > 16)
-        do {
-          if (e == 99)
-            return 1;
-          DUMPBITS(t->b)
-          e -= 16;
-          NEEDBITS(e)
-        } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
-      DUMPBITS(t->b)
-      NEEDBITS(e)
-      d = w - t->v.n - ((unsigned)b & mask_bits[e]);
-      DUMPBITS(e)
-
-      /* do the copy */
-      do {
-        n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
-#if !defined(NOMEMCPY) && !defined(DEBUG)
-        if (w - d >= e)         /* (this test assumes unsigned comparison) */
-        {
-          memcpy(slide + w, slide + d, e);
-          w += e;
-          d += e;
-        }
-        else                      /* do it slow to avoid memcpy() overlap */
-#endif /* !NOMEMCPY */
-          do {
-            slide[w++] = slide[d++];
-          } while (--e);
-        if (w == WSIZE)
-        {
-          flush_output(w);
-          w = 0;
-        }
-      } while (n);
-    }
-  }
-
-
-  /* restore the globals from the locals */
-  wp = w;                       /* restore global window pointer */
-  bb = b;                       /* restore global bit buffer */
-  bk = k;
-
-  /* done */
-  return 0;
-}
-
-
-
-int inflate_stored()
-/* "decompress" an inflated type 0 (stored) block. */
-{
-  unsigned n;           /* number of bytes in block */
-  unsigned w;           /* current window position */
-  register ulg b;       /* bit buffer */
-  register unsigned k;  /* number of bits in bit buffer */
-
-DEBG("<stor");
-
-  /* make local copies of globals */
-  b = bb;                       /* initialize bit buffer */
-  k = bk;
-  w = wp;                       /* initialize window position */
-
-
-  /* go to byte boundary */
-  n = k & 7;
-  DUMPBITS(n);
-
-
-  /* get the length and its complement */
-  NEEDBITS(16)
-  n = ((unsigned)b & 0xffff);
-  DUMPBITS(16)
-  NEEDBITS(16)
-  if (n != (unsigned)((~b) & 0xffff))
-    return 1;                   /* error in compressed data */
-  DUMPBITS(16)
-
-
-  /* read and output the compressed data */
-  while (n--)
-  {
-    NEEDBITS(8)
-    slide[w++] = (uch)b;
-    if (w == WSIZE)
-    {
-      flush_output(w);
-      w = 0;
-    }
-    DUMPBITS(8)
-  }
-
-
-  /* restore the globals from the locals */
-  wp = w;                       /* restore global window pointer */
-  bb = b;                       /* restore global bit buffer */
-  bk = k;
-
-  DEBG(">");
-  return 0;
-}
-
-
-
-int inflate_fixed()
-/* decompress an inflated type 1 (fixed Huffman codes) block.  We should
-   either replace this with a custom decoder, or at least precompute the
-   Huffman tables. */
-{
-  int i;                /* temporary variable */
-  struct huft *tl;      /* literal/length code table */
-  struct huft *td;      /* distance code table */
-  int bl;               /* lookup bits for tl */
-  int bd;               /* lookup bits for td */
-  unsigned l[288];      /* length list for huft_build */
-
-DEBG("<fix");
-
-  /* set up literal table */
-  for (i = 0; i < 144; i++)
-    l[i] = 8;
-  for (; i < 256; i++)
-    l[i] = 9;
-  for (; i < 280; i++)
-    l[i] = 7;
-  for (; i < 288; i++)          /* make a complete, but wrong code set */
-    l[i] = 8;
-  bl = 7;
-  if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
-    return i;
-
-
-  /* set up distance table */
-  for (i = 0; i < 30; i++)      /* make an incomplete code set */
-    l[i] = 5;
-  bd = 5;
-  if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
-  {
-    huft_free(tl);
-
-    DEBG(">");
-    return i;
-  }
-
-
-  /* decompress until an end-of-block code */
-  if (inflate_codes(tl, td, bl, bd))
-    return 1;
-
-
-  /* free the decoding tables, return */
-  huft_free(tl);
-  huft_free(td);
-  return 0;
-}
-
-
-
-int inflate_dynamic()
-/* decompress an inflated type 2 (dynamic Huffman codes) block. */
-{
-  int i;                /* temporary variables */
-  unsigned j;
-  unsigned l;           /* last length */
-  unsigned m;           /* mask for bit lengths table */
-  unsigned n;           /* number of lengths to get */
-  struct huft *tl;      /* literal/length code table */
-  struct huft *td;      /* distance code table */
-  int bl;               /* lookup bits for tl */
-  int bd;               /* lookup bits for td */
-  unsigned nb;          /* number of bit length codes */
-  unsigned nl;          /* number of literal/length codes */
-  unsigned nd;          /* number of distance codes */
-#ifdef PKZIP_BUG_WORKAROUND
-  unsigned ll[288+32];  /* literal/length and distance code lengths */
-#else
-  unsigned ll[286+30];  /* literal/length and distance code lengths */
-#endif
-  register ulg b;       /* bit buffer */
-  register unsigned k;  /* number of bits in bit buffer */
-
-DEBG("<dyn");
-
-  /* make local bit buffer */
-  b = bb;
-  k = bk;
-
-
-  /* read in table lengths */
-  NEEDBITS(5)
-  nl = 257 + ((unsigned)b & 0x1f);      /* number of literal/length codes */
-  DUMPBITS(5)
-  NEEDBITS(5)
-  nd = 1 + ((unsigned)b & 0x1f);        /* number of distance codes */
-  DUMPBITS(5)
-  NEEDBITS(4)
-  nb = 4 + ((unsigned)b & 0xf);         /* number of bit length codes */
-  DUMPBITS(4)
-#ifdef PKZIP_BUG_WORKAROUND
-  if (nl > 288 || nd > 32)
-#else
-  if (nl > 286 || nd > 30)
-#endif
-    return 1;                   /* bad lengths */
-
-DEBG("dyn1 ");
-
-  /* read in bit-length-code lengths */
-  for (j = 0; j < nb; j++)
-  {
-    NEEDBITS(3)
-    ll[border[j]] = (unsigned)b & 7;
-    DUMPBITS(3)
-  }
-  for (; j < 19; j++)
-    ll[border[j]] = 0;
-
-DEBG("dyn2 ");
-
-  /* build decoding table for trees--single level, 7 bit lookup */
-  bl = 7;
-  if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
-  {
-    if (i == 1)
-      huft_free(tl);
-    return i;                   /* incomplete code set */
-  }
-
-DEBG("dyn3 ");
-
-  /* read in literal and distance code lengths */
-  n = nl + nd;
-  m = mask_bits[bl];
-  i = l = 0;
-  while ((unsigned)i < n)
-  {
-    NEEDBITS((unsigned)bl)
-    j = (td = tl + ((unsigned)b & m))->b;
-    DUMPBITS(j)
-    j = td->v.n;
-    if (j < 16)                 /* length of code in bits (0..15) */
-      ll[i++] = l = j;          /* save last length in l */
-    else if (j == 16)           /* repeat last length 3 to 6 times */
-    {
-      NEEDBITS(2)
-      j = 3 + ((unsigned)b & 3);
-      DUMPBITS(2)
-      if ((unsigned)i + j > n)
-        return 1;
-      while (j--)
-        ll[i++] = l;
-    }
-    else if (j == 17)           /* 3 to 10 zero length codes */
-    {
-      NEEDBITS(3)
-      j = 3 + ((unsigned)b & 7);
-      DUMPBITS(3)
-      if ((unsigned)i + j > n)
-        return 1;
-      while (j--)
-        ll[i++] = 0;
-      l = 0;
-    }
-    else                        /* j == 18: 11 to 138 zero length codes */
-    {
-      NEEDBITS(7)
-      j = 11 + ((unsigned)b & 0x7f);
-      DUMPBITS(7)
-      if ((unsigned)i + j > n)
-        return 1;
-      while (j--)
-        ll[i++] = 0;
-      l = 0;
-    }
-  }
-
-DEBG("dyn4 ");
-
-  /* free decoding table for trees */
-  huft_free(tl);
-
-DEBG("dyn5 ");
-
-  /* restore the global bit buffer */
-  bb = b;
-  bk = k;
-
-DEBG("dyn5a ");
-
-  /* build the decoding tables for literal/length and distance codes */
-  bl = lbits;
-  if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
-  {
-DEBG("dyn5b ");
-    if (i == 1) {
-      error(" incomplete literal tree\n");
-      huft_free(tl);
-    }
-    return i;                   /* incomplete code set */
-  }
-DEBG("dyn5c ");
-  bd = dbits;
-  if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
-  {
-DEBG("dyn5d ");
-    if (i == 1) {
-      error(" incomplete distance tree\n");
-#ifdef PKZIP_BUG_WORKAROUND
-      i = 0;
-    }
-#else
-      huft_free(td);
-    }
-    huft_free(tl);
-    return i;                   /* incomplete code set */
-#endif
-  }
-
-DEBG("dyn6 ");
-
-  /* decompress until an end-of-block code */
-  if (inflate_codes(tl, td, bl, bd))
-    return 1;
-
-DEBG("dyn7 ");
-
-  /* free the decoding tables, return */
-  huft_free(tl);
-  huft_free(td);
-
-  DEBG(">");
-  return 0;
-}
-
-
-
-int inflate_block(e)
-int *e;                 /* last block flag */
-/* decompress an inflated block */
-{
-  unsigned t;           /* block type */
-  register ulg b;       /* bit buffer */
-  register unsigned k;  /* number of bits in bit buffer */
-
-  DEBG("<blk");
-
-  /* make local bit buffer */
-  b = bb;
-  k = bk;
-
-
-  /* read in last block bit */
-  NEEDBITS(1)
-  *e = (int)b & 1;
-  DUMPBITS(1)
-
-
-  /* read in block type */
-  NEEDBITS(2)
-  t = (unsigned)b & 3;
-  DUMPBITS(2)
-
-
-  /* restore the global bit buffer */
-  bb = b;
-  bk = k;
-
-  /* inflate that block type */
-  if (t == 2)
-    return inflate_dynamic();
-  if (t == 0)
-    return inflate_stored();
-  if (t == 1)
-    return inflate_fixed();
-
-  DEBG(">");
-
-  /* bad block type */
-  return 2;
-}
-
-
-
-int inflate()
-/* decompress an inflated entry */
-{
-  int e;                /* last block flag */
-  int r;                /* result code */
-  unsigned h;           /* maximum struct huft's malloc'ed */
-
-
-  /* initialize window, bit buffer */
-  wp = 0;
-  bk = 0;
-  bb = 0;
-
-
-  /* decompress until the last block */
-  h = 0;
-  do {
-    hufts = 0;
-    if ((r = inflate_block(&e)) != 0)
-      return r;
-    if (hufts > h)
-      h = hufts;
-  } while (!e);
-
-  /* Undo too much lookahead. The next read will be byte aligned so we
-   * can discard unused bits in the last meaningful byte.
-   */
-  while (bk >= 8) {
-    bk -= 8;
-    inptr--;
-  }
-
-  /* flush out slide */
-  flush_output(wp);
-
-
-  /* return success */
-#ifdef DEBUG
-  fprintf(stderr, "<%u> ", h);
-#endif /* DEBUG */
-  return 0;
-}
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/compressed/lzw.h linux/arch/ppc/boot/compressed/lzw.h
--- v2.1.15/linux/arch/ppc/boot/compressed/lzw.h	Mon May 27 12:00:57 1996
+++ linux/arch/ppc/boot/compressed/lzw.h	Thu Jan  1 02:00:00 1970
@@ -1,42 +0,0 @@
-/* lzw.h -- define the lzw functions.
- * Copyright (C) 1992-1993 Jean-loup Gailly.
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- */
-
-#if !defined(OF) && defined(lint)
-#  include "gzip.h"
-#endif
-
-#ifndef BITS
-#  define BITS 16
-#endif
-#define INIT_BITS 9              /* Initial number of bits per code */
-
-#define	LZW_MAGIC  "\037\235"   /* Magic header for lzw files, 1F 9D */
-
-#define BIT_MASK    0x1f /* Mask for 'number of compression bits' */
-/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
- * It's a pity that old uncompress does not check bit 0x20. That makes
- * extension of the format actually undesirable because old compress
- * would just crash on the new format instead of giving a meaningful
- * error message. It does check the number of bits, but it's more
- * helpful to say "unsupported format, get a new version" than
- * "can only handle 16 bits".
- */
-
-#define BLOCK_MODE  0x80
-/* Block compression: if table is full and compression rate is dropping,
- * clear the dictionary.
- */
-
-#define LZW_RESERVED 0x60 /* reserved bits */
-
-#define	CLEAR  256       /* flush the dictionary */
-#define FIRST  (CLEAR+1) /* first free entry */
-
-extern int maxbits;      /* max bits per code for LZW */
-extern int block_mode;   /* block compress mode -C compatible with 2.0 */
-
-extern void lzw    OF((int in, int out));
-extern void unlzw  OF((int in, int out));
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/compressed/misc.c linux/arch/ppc/boot/compressed/misc.c
--- v2.1.15/linux/arch/ppc/boot/compressed/misc.c	Mon May 27 12:00:57 1996
+++ linux/arch/ppc/boot/compressed/misc.c	Thu Jan  1 02:00:00 1970
@@ -1,430 +0,0 @@
-/*
- * misc.c
- * 
- * This is a collection of several routines from gzip-1.0.3 
- * adapted for Linux.
- *
- * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
- * puts by Nick Holloway 1993
- */
-
-#include "gzip.h"
-#include "lzw.h"
-
-
-#define EOF -1
-
-DECLARE(uch, inbuf, INBUFSIZ);
-DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
-DECLARE(uch, window, WSIZE);
-
-unsigned outcnt;
-unsigned insize;
-unsigned inptr;
-
-extern char input_data[];
-extern int input_len;
-
-int input_ptr;
-
-int method, exit_code, part_nb, last_member;
-int test = 0;
-int force = 0;
-int verbose = 1;
-long bytes_in, bytes_out;
-
-char *output_data;
-unsigned long output_ptr;
-
-extern int end;
-long free_mem_ptr = (long)&end;
-
-int to_stdout = 0;
-int hard_math = 0;
-
-void (*work)(int inf, int outf);
-void makecrc(void);
-
-local int get_method(int);
-
-char *vidmem = (char *)0xC00B8000;
-int lines, cols;
-int orig_x, orig_y;
-
-void puts(const char *);
-
-void *malloc(int size)
-{
-	void *p;
-
-	if (size <0) error("Malloc error\n");
-	if (free_mem_ptr <= 0) error("Memory error\n");
-
-   while(1) {
-	free_mem_ptr = (free_mem_ptr + 3) & ~3;	/* Align */
-
-	p = (void *)free_mem_ptr;
-	free_mem_ptr += size;
-
-	/*
-  	 * The part of the compressed kernel which has already been expanded
-	 * is no longer needed. Therefore we can reuse it for malloc.
-	 * With bigger kernels, this is necessary.
-	 */
-          
-	if (free_mem_ptr < (long)&end) {
-		if (free_mem_ptr > (long)&input_data[input_ptr])
-			error("\nOut of memory\n");
-
-		return p;
-	}
-#if 0	
-	if (free_mem_ptr < 0x90000)
-#endif	
-	return p;
-	puts("large kernel, low 1M tight...");
-	free_mem_ptr = (long)input_data;
-	}
-}
-
-void free(void *where)
-{	/* Don't care */
-}
-
-static void scroll()
-{
-	int i;
-
-	memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );
-	for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
-		vidmem[i] = ' ';
-}
-
-void puts(const char *s)
-{
-	int x,y;
-	char c;
-
-#if 0	
-	x = SCREEN_INFO.orig_x;
-	y = SCREEN_INFO.orig_y;
-#else
-	x = orig_x;
-	y = orig_y;
-#endif	
-
-	while ( ( c = *s++ ) != '\0' ) {
-		if ( c == '\n' ) {
-			x = 0;
-			if ( ++y >= lines ) {
-				scroll();
-				y--;
-			}
-		} else {
-			vidmem [ ( x + cols * y ) * 2 ] = c; 
-			if ( ++x >= cols ) {
-				x = 0;
-				if ( ++y >= lines ) {
-					scroll();
-					y--;
-				}
-			}
-		}
-	}
-
-#if 0	
-	SCREEN_INFO.orig_x = x;
-	SCREEN_INFO.orig_y = y;
-#else
-	orig_x = x;
-	orig_y = y;
-#endif	
-}
-
-__ptr_t memset(__ptr_t s, int c, size_t n)
-{
-	int i;
-	char *ss = (char*)s;
-
-	for (i=0;i<n;i++) ss[i] = c;
-}
-
-__ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src,
-			    size_t __n)
-{
-	int i;
-	char *d = (char *)__dest, *s = (char *)__src;
-
-	for (i=0;i<__n;i++) d[i] = s[i];
-}
-
-int memcmp(__ptr_t __dest, __const __ptr_t __src,
-			    size_t __n)
-{
-	int i;
-	char *d = (char *)__dest, *s = (char *)__src;
-
-	for (i=0;i<__n;i++, d++, s++)
-	{
-		if (*d != *s)
-		{
-			return (*s - *d);
-		}
-	}
-	return (0);
-}
-
-extern ulg crc_32_tab[];   /* crc table, defined below */
-
-/* ===========================================================================
- * Run a set of bytes through the crc shift register.  If s is a NULL
- * pointer, then initialize the crc shift register contents instead.
- * Return the current crc in either case.
- */
-ulg updcrc(s, n)
-    uch *s;                 /* pointer to bytes to pump through */
-    unsigned n;             /* number of bytes in s[] */
-{
-    register ulg c;         /* temporary variable */
-
-    static ulg crc = (ulg)0xffffffffL; /* shift register contents */
-
-    if (s == NULL) {
-	c = 0xffffffffL;
-    } else {
-	c = crc;
-	while (n--) {
-	    c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
-	}
-    }
-    crc = c;
-    return c ^ 0xffffffffL;       /* (instead of ~c for 64-bit machines) */
-}
-
-/* ===========================================================================
- * Clear input and output buffers
- */
-void clear_bufs()
-{
-    outcnt = 0;
-    insize = inptr = 0;
-    bytes_in = bytes_out = 0L;
-}
-
-/* ===========================================================================
- * Fill the input buffer. This is called only when the buffer is empty
- * and at least one byte is really needed.
- */
-int fill_inbuf()
-{
-    int len, i;
-
-    /* Read as much as possible */
-puts("*");    
-    insize = 0;
-    do {
-	len = INBUFSIZ-insize;
-	if (len > (input_len-input_ptr+1)) len=input_len-input_ptr+1;
-        if (len == 0 || len == EOF) break;
-
-        for (i=0;i<len;i++) inbuf[insize+i] = input_data[input_ptr+i];
-	insize += len;
-	input_ptr += len;
-    } while (insize < INBUFSIZ);
-
-    if (insize == 0) {
-	error("unable to fill buffer\n");
-    }
-    bytes_in += (ulg)insize;
-    inptr = 1;
-    return inbuf[0];
-}
-
-/* ===========================================================================
- * Write the output window window[0..outcnt-1] and update crc and bytes_out.
- * (Used for the decompressed data only.)
- */
-void flush_window()
-{
-    if (outcnt == 0) return;
-    updcrc(window, outcnt);
-
-    memcpy(&output_data[output_ptr], (char *)window, outcnt);
-
-    bytes_out += (ulg)outcnt;
-    output_ptr += (ulg)outcnt;
-    outcnt = 0;
-}
-
-/*
- * Code to compute the CRC-32 table. Borrowed from 
- * gzip-1.0.3/makecrc.c.
- */
-
-ulg crc_32_tab[256];
-
-void
-makecrc(void)
-{
-/* Not copyrighted 1990 Mark Adler	*/
-
-  unsigned long c;      /* crc shift register */
-  unsigned long e;      /* polynomial exclusive-or pattern */
-  int i;                /* counter for all possible eight bit values */
-  int k;                /* byte being shifted into crc apparatus */
-
-  /* terms of polynomial defining this crc (except x^32): */
-  static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
-
-  /* Make exclusive-or pattern from polynomial */
-  e = 0;
-  for (i = 0; i < sizeof(p)/sizeof(int); i++)
-    e |= 1L << (31 - p[i]);
-
-  crc_32_tab[0] = 0;
-
-  for (i = 1; i < 256; i++)
-  {
-    c = 0;
-    for (k = i | 256; k != 1; k >>= 1)
-    {
-      c = c & 1 ? (c >> 1) ^ e : c >> 1;
-      if (k & 1)
-        c ^= e;
-    }
-    crc_32_tab[i] = c;
-  }
-}
-
-void error(char *x)
-{
-	puts("\n\n");
-	puts(x);
-	puts("\n\n -- System halted");
-
-	while(1);	/* Halt */
-}
-
-#if 0
-#define STACK_SIZE (4096)
-
-long user_stack [STACK_SIZE];
-
-struct {
-	long * a;
-	short b;
-	} stack_start = { & user_stack [STACK_SIZE] , KERNEL_DS };
-#endif
-
-void decompress_kernel()
-{
-#if 0	
-	if (SCREEN_INFO.orig_video_mode == 7)
-		vidmem = (char *) 0xb0000;
-	else
-		vidmem = (char *) 0xb8000;
-
-	lines = SCREEN_INFO.orig_video_lines;
-	cols = SCREEN_INFO.orig_video_cols;
-
-	if (EXT_MEM_K < 1024) error("<2M of mem\n");
-	output_data = (char *)0x100000;	/* Points to 1M */
-#else
-	output_data = (char *)0x0;	/* Points to 0 */
-	lines = 25;
-	cols = 80;
-	orig_x = 0;
-	orig_y = 24;
-#endif	
-
-	output_ptr = 0;
-
-	exit_code = 0;
-	test = 0;
-	input_ptr = 0;
-	part_nb = 0;
-
-	clear_bufs();
-	makecrc();
-
-	puts("Uncompressing Linux...");
-
-	method = get_method(0);
-
-	work(0, 0);
-
-	puts("done.\n");
-
-	puts("Now booting the kernel\n");
-}
-
-/* ========================================================================
- * Check the magic number of the input file and update ofname if an
- * original name was given and to_stdout is not set.
- * Return the compression method, -1 for error, -2 for warning.
- * Set inptr to the offset of the next byte to be processed.
- * This function may be called repeatedly for an input file consisting
- * of several contiguous gzip'ed members.
- * IN assertions: there is at least one remaining compressed member.
- *   If the member is a zip file, it must be the only one.
- */
-local int get_method(in)
-    int in;        /* input file descriptor */
-{
-    uch flags;
-    char magic[2]; /* magic header */
-
-    magic[0] = (char)get_byte();
-    magic[1] = (char)get_byte();
-
-    method = -1;                 /* unknown yet */
-    part_nb++;                   /* number of parts in gzip file */
-    last_member = 0;
-    /* assume multiple members in gzip file except for record oriented I/O */
-
-    if (memcmp(magic, GZIP_MAGIC, 2) == 0
-        || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
-
-	work = unzip;
-	method = (int)get_byte();
-	flags  = (uch)get_byte();
-	if ((flags & ENCRYPTED) != 0)
-	    error("Input is encrypted\n");
-	if ((flags & CONTINUATION) != 0)
-	       error("Multi part input\n");
-	if ((flags & RESERVED) != 0) {
-	    error("Input has invalid flags\n");
-	    exit_code = ERROR;
-	    if (force <= 1) return -1;
-	}
-	(ulg)get_byte();	/* Get timestamp */
-	((ulg)get_byte()) << 8;
-	((ulg)get_byte()) << 16;
-	((ulg)get_byte()) << 24;
-
-	(void)get_byte();  /* Ignore extra flags for the moment */
-	(void)get_byte();  /* Ignore OS type for the moment */
-
-	if ((flags & EXTRA_FIELD) != 0) {
-	    unsigned len = (unsigned)get_byte();
-	    len |= ((unsigned)get_byte())<<8;
-	    while (len--) (void)get_byte();
-	}
-
-	/* Get original file name if it was truncated */
-	if ((flags & ORIG_NAME) != 0) {
-	    if (to_stdout || part_nb > 1) {
-		/* Discard the old name */
-		while (get_byte() != 0) /* null */ ;
-	    } else {
-	    } /* to_stdout */
-	} /* orig_name */
-
-	/* Discard file comment if any */
-	if ((flags & COMMENT) != 0) {
-	    while (get_byte() != 0) /* null */ ;
-	}
-    } else
-	error("unknown compression method");
-    return method;
-}
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/compressed/piggyback.c linux/arch/ppc/boot/compressed/piggyback.c
--- v2.1.15/linux/arch/ppc/boot/compressed/piggyback.c	Mon May 27 12:00:57 1996
+++ linux/arch/ppc/boot/compressed/piggyback.c	Thu Jan  1 02:00:00 1970
@@ -1,59 +0,0 @@
-#include <stdio.h>
-
-extern long ce_exec_config[];
-
-main(int argc, char *argv[])
-{
-	int i, cnt, pos, len;
-	unsigned char *lp;
-	unsigned char buf[8192];
-	if (argc != 1)
-	{
-		fprintf(stderr, "usage: %s <in-file >out-file\n", argv[0]);
-		exit(1);
-	}
-	fprintf(stdout, "#\n");
-	fprintf(stdout, "# Miscellaneous data structures:\n");
-	fprintf(stdout, "# WARNING - this file is automatically generated!\n");
-	fprintf(stdout, "#\n");
-	fprintf(stdout, "\n");
-	fprintf(stdout, "\t.data\n");
-	fprintf(stdout, "\t.globl input_data\n");
-	fprintf(stdout, "input_data:\n");
-	pos = 0;
-	while ((len = read(0, buf, sizeof(buf))) > 0)
-	{
-		cnt = 0;
-		lp = (unsigned char *)buf;
-		len = (len + 3) & ~3;  /* Round up to longwords */
-		for (i = 0;  i < len;  i += 4)
-		{
-			if (cnt == 0)
-			{
-				fprintf(stdout, "\t.long\t");
-			}
-			fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
-			lp += 4;
-			if (++cnt == 4)
-			{
-				cnt = 0;
-				fprintf(stdout, " # %x \n", pos+i-12);
-				fflush(stdout);
-			} else
-			{
-				fprintf(stdout, ",");
-			}
-		}
-		if (cnt)
-		{
-			fprintf(stdout, "0\n");
-		}
-		pos += len;
-	}
-	fprintf(stdout, "\t.globl input_len\n");
-	fprintf(stdout, "input_len:\t.long\t0x%x\n", pos);
-	fflush(stdout);
-	fclose(stdout);
-	exit(0);
-}
-
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/compressed/ppc_defs.h linux/arch/ppc/boot/compressed/ppc_defs.h
--- v2.1.15/linux/arch/ppc/boot/compressed/ppc_defs.h	Mon May 27 12:00:57 1996
+++ linux/arch/ppc/boot/compressed/ppc_defs.h	Thu Jan  1 02:00:00 1970
@@ -1,6 +0,0 @@
-#define r0 0
-#define r1 1
-#define r2 2
-#define r3 3
-#define r4 4
-#define r5 5
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/compressed/unzip.c linux/arch/ppc/boot/compressed/unzip.c
--- v2.1.15/linux/arch/ppc/boot/compressed/unzip.c	Mon May 27 12:00:57 1996
+++ linux/arch/ppc/boot/compressed/unzip.c	Thu Jan  1 02:00:00 1970
@@ -1,180 +0,0 @@
-/* unzip.c -- decompress files in gzip or pkzip format.
- * Copyright (C) 1992-1993 Jean-loup Gailly
- *
- * Adapted for Linux booting by Hannu Savolainen 1993
- *
- * This is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License, see the file COPYING.
- *
- * The code in this file is derived from the file funzip.c written
- * and put in the public domain by Mark Adler.
- */
-
-/*
-   This version can extract files in gzip or pkzip format.
-   For the latter, only the first entry is extracted, and it has to be
-   either deflated or stored.
- */
-
-#ifndef lint
-static char rcsid[] = "$Id: unzip.c,v 0.9 1993/02/10 16:07:22 jloup Exp $";
-#endif
-
-#include "gzip.h"
-#include "crypt.h"
-
-#include <stdio.h>
-
-/* PKZIP header definitions */
-#define LOCSIG 0x04034b50L      /* four-byte lead-in (lsb first) */
-#define LOCFLG 6                /* offset of bit flag */
-#define  CRPFLG 1               /*  bit for encrypted entry */
-#define  EXTFLG 8               /*  bit for extended local header */
-#define LOCHOW 8                /* offset of compression method */
-#define LOCTIM 10               /* file mod time (for decryption) */
-#define LOCCRC 14               /* offset of crc */
-#define LOCSIZ 18               /* offset of compressed size */
-#define LOCLEN 22               /* offset of uncompressed length */
-#define LOCFIL 26               /* offset of file name field length */
-#define LOCEXT 28               /* offset of extra field length */
-#define LOCHDR 30               /* size of local header, including sig */
-#define EXTHDR 16               /* size of extended local header, inc sig */
-
-
-/* Globals */
-
-int decrypt;      /* flag to turn on decryption */
-char *key;        /* not used--needed to link crypt.c */
-int pkzip = 0;    /* set for a pkzip file */
-int extended = 0; /* set if extended local header */
-
-/* ===========================================================================
- * Check zip file and advance inptr to the start of the compressed data.
- * Get ofname from the local header if necessary.
- */
-int check_zipfile(in)
-    int in;   /* input file descriptors */
-{
-    uch *h = inbuf + inptr; /* first local header */
-
-    /* ifd = in; */
-
-    /* Check validity of local header, and skip name and extra fields */
-    inptr += LOCHDR + SH(h + LOCFIL) + SH(h + LOCEXT);
-
-    if (inptr > insize || LG(h) != LOCSIG) {
-	error("input not a zip");
-    }
-    method = h[LOCHOW];
-    if (method != STORED && method != DEFLATED) {
-	error("first entry not deflated or stored--can't extract");
-    }
-
-    /* If entry encrypted, decrypt and validate encryption header */
-    if ((decrypt = h[LOCFLG] & CRPFLG) != 0) {
-	error("encrypted file\n");
-	exit_code = ERROR;
-	return -1;
-    }
-
-    /* Save flags for unzip() */
-    extended = (h[LOCFLG] & EXTFLG) != 0;
-    pkzip = 1;
-
-    /* Get ofname and time stamp from local header (to be done) */
-    return 0;
-}
-
-/* ===========================================================================
- * Unzip in to out.  This routine works on both gzip and pkzip files.
- *
- * IN assertions: the buffer inbuf contains already the beginning of
- *   the compressed data, from offsets inptr to insize-1 included.
- *   The magic header has already been checked. The output buffer is cleared.
- */
-void unzip(in, out)
-    int in, out;   /* input and output file descriptors */
-{
-    ulg orig_crc = 0;       /* original crc */
-    ulg orig_len = 0;       /* original uncompressed length */
-    int n;
-    uch buf[EXTHDR];        /* extended local header */
-
-    /* ifd = in;
-    ofd = out; */
-
-    updcrc(NULL, 0);           /* initialize crc */
-
-    if (pkzip && !extended) {  /* crc and length at the end otherwise */
-	orig_crc = LG(inbuf + LOCCRC);
-	orig_len = LG(inbuf + LOCLEN);
-    }
-
-    /* Decompress */
-    if (method == DEFLATED)  {
-
-	int res = inflate();
-
-	if (res == 3) {
-	    error("out of memory");
-	} else if (res != 0) {
-	    error("invalid compressed format");
-	}
-
-    } else if (pkzip && method == STORED) {
-
-	register ulg n = LG(inbuf + LOCLEN);
-
-	if (n != LG(inbuf + LOCSIZ) - (decrypt ? RAND_HEAD_LEN : 0)) {
-
-	    error("length mismatch");
-	}
-	while (n--) {
-	    uch c = (uch)get_byte();
-#ifdef CRYPT
-	    if (decrypt) zdecode(c);
-#endif
-	    if (!test) put_char(c);
-	}
-    } else {
-	error("internal error, invalid method");
-    }
-
-    /* Get the crc and original length */
-    if (!pkzip) {
-        /* crc32  (see algorithm.doc)
-	 * uncompressed input size modulo 2^32
-         */
-	for (n = 0; n < 8; n++) {
-	    buf[n] = (uch)get_byte(); /* may cause an error if EOF */
-	}
-	orig_crc = LG(buf);
-	orig_len = LG(buf+4);
-
-    } else if (extended) {  /* If extended header, check it */
-	/* signature - 4bytes: 0x50 0x4b 0x07 0x08
-	 * CRC-32 value
-         * compressed size 4-bytes
-         * uncompressed size 4-bytes
-	 */
-	for (n = 0; n < EXTHDR; n++) {
-	    buf[n] = (uch)get_byte(); /* may cause an error if EOF */
-	}
-	orig_crc = LG(buf+4);
-	orig_len = LG(buf+12);
-    }
-
-    /* Validate decompression */
-    if (orig_crc != updcrc(outbuf, 0)) {
-	error("crc error");
-    }
-    if (orig_len != bytes_out) {
-	error("length error");
-    }
-
-    /* Check if there are more entries in a pkzip file */
-    if (pkzip && inptr + 4 < insize && LG(inbuf+inptr) == LOCSIG) {
-	    error("zip file has more than one entry");
-    }
-    extended = pkzip = 0; /* for next file */
-}
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/cortstrip.c linux/arch/ppc/boot/cortstrip.c
--- v2.1.15/linux/arch/ppc/boot/cortstrip.c	Mon Jul  8 11:27:42 1996
+++ linux/arch/ppc/boot/cortstrip.c	Wed Dec 18 10:49:52 1996
@@ -7,7 +7,7 @@
 #define PLACE 65536
 
 /* size of read buffer */
-#define SIZE 0x200000
+#define SIZE 0x100000
 
 /* crude program to strip the elf header to make a bootable
    image via tftp
@@ -20,11 +20,13 @@
   unsigned char data[SIZE];
   int i, n, skip;
 
+#if 0
   if ( argc != 3 )
   {
     fprintf(stderr,"%s infile outfile\n", argv[0]);
     exit(-1);
   }
+#endif
 
 
   fd = open(argv[1], O_RDONLY);
@@ -49,7 +51,7 @@
   skip = PLACE;
 #endif
   i = lseek(fd, skip, SEEK_SET);
-  printf("lseek'd %d bytes\n", i);
+ /*printf("lseek'd %d bytes\n", i);*/
   if ( i == -1 )
   {
       perror("lseek()");
@@ -57,9 +59,9 @@
 
   while ( (n = read(fd, data, SIZE)) > 0 )
   {
-    printf("Read %d bytes\n", n);
+    /*printf("Read %d bytes\n", n);*/
     i = write(fdo, data, n);
-    printf("Wrote %d bytes\n", i);    
+    /*printf("Wrote %d bytes\n", i);    */
   }
 
 
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/crypt.h linux/arch/ppc/boot/crypt.h
--- v2.1.15/linux/arch/ppc/boot/crypt.h	Thu Jan  1 02:00:00 1970
+++ linux/arch/ppc/boot/crypt.h	Wed Dec 18 10:49:52 1996
@@ -0,0 +1,12 @@
+/* crypt.h (dummy version) -- do not perform encryption
+ * Hardly worth copyrighting :-)
+ */
+
+#ifdef CRYPT
+#  undef CRYPT      /* dummy version */
+#endif
+
+#define RAND_HEAD_LEN  12  /* length of encryption random header */
+
+#define zencode
+#define zdecode
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/gzip.h linux/arch/ppc/boot/gzip.h
--- v2.1.15/linux/arch/ppc/boot/gzip.h	Thu Jan  1 02:00:00 1970
+++ linux/arch/ppc/boot/gzip.h	Wed Dec 18 10:49:52 1996
@@ -0,0 +1,284 @@
+/* gzip.h -- common declarations for all gzip modules
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#if defined(__STDC__) || defined(PROTO)
+#  define OF(args)  args
+#else
+#  define OF(args)  ()
+#endif
+
+#ifdef __STDC__
+   typedef void *voidp;
+#else
+   typedef char *voidp;
+#endif
+
+/* I don't like nested includes, but the string functions are used too often */
+#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
+#  include <string.h>
+#  define memzero(s, n)     memset ((s), 0, (n))
+#else
+#  include <strings.h>
+#  define strchr            index 
+#  define strrchr           rindex
+#  define memcpy(d, s, n)   bcopy((s), (d), (n)) 
+#  define memcmp(s1, s2, n) bcmp((s1), (s2), (n)) 
+#  define memzero(s, n)     bzero((s), (n))
+#endif
+
+#if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H)
+#  include <memory.h>
+#endif
+
+#ifndef RETSIGTYPE
+#  define RETSIGTYPE void
+#endif
+
+#define local static
+
+typedef unsigned char  uch;
+typedef unsigned short ush;
+typedef unsigned long  ulg;
+
+/* Return codes from gzip */
+#define OK      0
+#define ERROR   1
+#define WARNING 2
+
+/* Compression methods (see algorithm.doc) */
+#define STORED     0
+#define COMPRESSED 1
+#define PACKED     2
+/* methods 3 to 7 reserved */
+#define DEFLATED   8
+extern int method;         /* compression method */
+
+/* To save memory for 16 bit systems, some arrays are overlayed between
+ * the various modules:
+ * deflate:  prev+head   window      d_buf  l_buf  outbuf
+ * unlzw:    tab_prefix  tab_suffix  stack  inbuf  outbuf
+ * inflate:              window             inbuf
+ * unpack:               window             inbuf
+ * For compression, input is done in window[]. For decompression, output
+ * is done in window except for unlzw.
+ */
+
+#ifndef	INBUFSIZ
+#  define INBUFSIZ  0x8000  /* input buffer size */
+#endif
+#define INBUF_EXTRA  64     /* required by unlzw() */
+
+#ifndef	OUTBUFSIZ
+#  define OUTBUFSIZ  16384  /* output buffer size */
+#endif
+#define OUTBUF_EXTRA 2048   /* required by unlzw() */
+
+#define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */
+
+#ifdef DYN_ALLOC
+#  define EXTERN(type, array)  extern type * near array
+#  define DECLARE(type, array, size)  type * near array
+#  define ALLOC(type, array, size) { \
+      array = (type*)fcalloc((unsigned)(((size)+1L)/2), 2*sizeof(type)); \
+      if (array == NULL) error("insufficient memory"); \
+   }
+#  define FREE(array) {if (array != NULL) fcfree(array), array=NULL;}
+#else
+#  define EXTERN(type, array)  extern type array[]
+#  define DECLARE(type, array, size)  type array[size]
+#  define ALLOC(type, array, size)
+#  define FREE(array)
+#endif
+
+EXTERN(uch, inbuf);          /* input buffer */
+EXTERN(uch, outbuf);         /* output buffer */
+EXTERN(ush, d_buf);          /* buffer for distances, see trees.c */
+EXTERN(uch, window);         /* Sliding window and suffix table (unlzw) */
+#define tab_suffix window
+#ifndef MAXSEG_64K
+#  define tab_prefix prev    /* hash link (see deflate.c) */
+#  define head (prev+WSIZE)  /* hash head (see deflate.c) */
+   EXTERN(ush, tab_prefix);  /* prefix code (see unlzw.c) */
+#else
+#  define tab_prefix0 prev
+#  define head tab_prefix1
+   EXTERN(ush, tab_prefix0); /* prefix for even codes */
+   EXTERN(ush, tab_prefix1); /* prefix for odd  codes */
+#endif
+
+extern unsigned insize; /* valid bytes in inbuf */
+extern unsigned inptr;  /* index of next byte to be processed in inbuf */
+extern unsigned outcnt; /* bytes in output buffer */
+
+extern long bytes_in;   /* number of input bytes */
+extern long bytes_out;  /* number of output bytes */
+extern long overhead;   /* number of bytes in gzip header */
+
+#define isize bytes_in
+/* for compatibility with old zip sources (to be cleaned) */
+
+extern int  ifd;        /* input file descriptor */
+extern int  ofd;        /* output file descriptor */
+extern char ifname[];   /* input filename or "stdin" */
+extern char ofname[];   /* output filename or "stdout" */
+
+extern ulg time_stamp;  /* original time stamp (modification time) */
+extern long ifile_size; /* input file size, -1 for devices (debug only) */
+
+extern int exit_code;   /* program exit code */
+
+typedef int file_t;     /* Do not use stdio */
+#define NO_FILE  (-1)   /* in memory compression */
+
+
+#define	GZIP_MAGIC     "\037\213" /* Magic header for gzip files, 1F 8B */
+#define	OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */
+#define	PKZIP_MAGIC  "PK\003\004" /* Magic header for pkzip files */
+#define	PACK_MAGIC     "\037\036" /* Magic header for packed files */
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
+#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define ENCRYPTED    0x20 /* bit 5 set: file is encrypted */
+#define RESERVED     0xC0 /* bit 6,7:   reserved */
+
+/* internal file attribute */
+#define UNKNOWN (-1)
+#define BINARY  0
+#define ASCII   1
+
+#ifndef WSIZE
+#  define WSIZE 0x8000     /* window size--must be a power of two, and */
+#endif                     /*  at least 32K for zip's deflate method */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST  (WSIZE-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+extern int decrypt;        /* flag to turn on decryption */
+extern int save_orig_name; /* set if original name must be saved */
+extern int verbose;        /* be verbose (-v) */
+extern int level;          /* compression level */
+extern int test;           /* check .z file integrity */
+extern int to_stdout;      /* output to stdout (-c) */
+
+#define get_byte()  (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+
+/* put_byte is used for the compressed output, put_char for the
+ * uncompressed output. However unlzw() uses window for its
+ * suffix table instead of its output buffer, so it does not use put_char.
+ * (to be cleaned up).
+ */
+#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\
+   flush_outbuf();}
+#define put_char(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\
+   flush_window();}
+
+/* Output a 16 bit value, lsb first */
+#define put_short(w) \
+{ if (outcnt < OUTBUFSIZ-2) { \
+    outbuf[outcnt++] = (uch) ((w) & 0xff); \
+    outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \
+  } else { \
+    put_byte((uch)((w) & 0xff)); \
+    put_byte((uch)((ush)(w) >> 8)); \
+  } \
+}
+
+/* Output a 32 bit value to the bit stream, lsb first */
+#define put_long(n) { \
+    put_short((n) & 0xffff); \
+    put_short(((ulg)(n)) >> 16); \
+}
+
+#define seekable()    0  /* force sequential output */
+#define translate_eol 0  /* no option -a yet */
+
+#define tolow(c)  (isupper(c) ? (c)-'A'+'a' : (c))    /* force to lower case */
+
+/* Macros for getting two-byte and four-byte header values */
+#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8))
+#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16))
+
+/* Diagnostic functions */
+#ifdef DEBUG
+#  define Assert(cond,msg) {if(!(cond)) error(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+	/* in zip.c: */
+extern void zip    OF((int in, int out));
+extern int file_read  OF((char *buf,  unsigned size));
+
+	/* in unzip.c */
+extern void unzip        OF((int in, int out));
+extern int check_zipfile OF((int in));
+
+	/* in unpack.c */
+extern void unpack        OF((int in, int out));
+
+	/* in gzip.c */
+RETSIGTYPE abort_gzip   OF((void));
+
+        /* in deflate.c */
+void lm_init OF((int pack_level, ush *flags));
+ulg  deflate OF((void));
+
+        /* in trees.c */
+void ct_init     OF((ush *attr, int *method));
+int  ct_tally    OF((int dist, int lc));
+ulg  flush_block OF((char *buf, ulg stored_len, int eof));
+
+        /* in bits.c */
+void     bi_init    OF((file_t zipfile));
+void     send_bits  OF((int value, int length));
+unsigned bi_reverse OF((unsigned value, int length));
+void     bi_windup  OF((void));
+void     copy_block OF((char *buf, unsigned len, int header));
+extern   int (*read_buf) OF((char *buf, unsigned size));
+
+	/* in util.c: */
+extern ulg  updcrc        OF((uch *s, unsigned n));
+extern void clear_bufs    OF((void));
+extern int  fill_inbuf    OF((void));
+extern void flush_outbuf  OF((void));
+extern void flush_window  OF((void));
+extern char *strlwr       OF((char *s));
+extern char *basename     OF((char *fname));
+extern char *add_envopt   OF((int *argcp, char ***argvp, char *env));
+extern void error         OF((char *m));
+extern void warn          OF((char *a, char *b));
+extern void read_error    OF((void));
+extern void write_error   OF((void));
+extern void display_ratio OF((long num, long den));
+extern voidp xmalloc      OF((unsigned int size));
+
+	/* in inflate.c */
+extern int inflate OF((void));
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/head.S linux/arch/ppc/boot/head.S
--- v2.1.15/linux/arch/ppc/boot/head.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/ppc/boot/head.S	Wed Dec 18 10:49:52 1996
@@ -0,0 +1,237 @@
+#include "../kernel/ppc_defs.h"
+#include "../kernel/ppc_asm.tmpl"
+
+	.text
+
+/*
+ * This code is loaded by the ROM loader at some arbitrary location.
+ * Move it to high memory so that it can load the kernel at 0x0000.
+ */
+
+	.globl	start
+start:
+	bl	start_
+start_:
+/* TEMP - No residual data on BeBox (yet) */
+#if 0	
+#define IS_BE_BOX	0x42654278	/* 'BeBx' */
+	lis	r2,IS_BE_BOX>>16
+	ori	r2,r2,IS_BE_BOX&0xFFFF
+	cmp	0,r30,r2
+	bne	notBeBox
+	li	r3,0
+#endif	
+notBeBox:
+/* TEMP */
+	mr	r11,r3		/* Save pointer to residual data */
+	mfmsr	r3		/* Turn off interrupts */
+	li	r4,0
+	ori	r4,r4,MSR_EE
+	andc	r3,r3,r4
+	mtmsr	r3
+/* Copy relocation code down to location 0x0100 (where we hope it's safe!) */
+	mflr	r3
+	addi	r5,r3,start_ldr-start_
+	addi	r3,r3,relocate-start_
+	li	r4,0x0100
+	mtctr	r4
+	subi	r3,r3,4
+	subi	r4,r4,4
+00:	lwzu	r6,4(r3)
+	stwu	r6,4(r4)
+	cmp	0,r3,r5
+	bne	00b
+	mflr	r21
+	mfctr	r22
+	bl	flush_instruction_cache
+	mtlr	r21
+	mtctr	r22
+	bctr			/* Jump to code */
+/* Relocate code to final resting spot */
+relocate:
+	mflr	r3		/* Compute code bias */
+	subi	r3,r3,4
+	mr	r8,r3
+	lis	r4,start@h
+	ori	r4,r4,start@l
+	lis	r5,edata@h
+	ori	r5,r5,edata@l
+	addi	r5,r5,3			/* Round up - just in case */
+	sub	r5,r5,r4		/* Compute # longwords to move */
+	srwi	r5,r5,2
+	mtctr	r5
+	mr	r7,r5
+	li	r6,0
+	subi	r3,r3,4			/* Set up for loop */
+	subi	r4,r4,4
+00:	lwzu	r5,4(r3)
+	stwu	r5,4(r4)
+	xor	r6,r6,r5
+	bdnz	00b
+	lis	r3,start_ldr@h
+	ori	r3,r3,start_ldr@l
+	mtlr	r3			/* Easiest way to do an absolute jump */
+	blr
+start_ldr:	
+/* Clear all of BSS */
+	lis	r3,edata@h
+	ori	r3,r3,edata@l
+	lis	r4,end@h
+	ori	r4,r4,end@l
+	subi	r3,r3,4
+	subi	r4,r4,4
+	li	r0,0
+50:	stwu	r0,4(r3)
+	cmp	0,r3,r4
+	bne	50b
+90:	mr	r9,r1			/* Save old stack pointer (in case it matters) */
+	lis	r1,.stack@h
+	ori	r1,r1,.stack@l
+	addi	r1,r1,4096*2
+	subi	r1,r1,256
+	li	r2,0x000F		/* Mask pointer to 16-byte boundary */
+	andc	r1,r1,r2
+/* Run loader */
+	mr	r3,r8			/* Load point */
+	mr	r4,r7			/* Program length */
+	mr	r5,r6			/* Checksum */
+	mr	r6,r11			/* Residual data */
+	bl	decompress_kernel
+	/*mr	r29,r3*/			/* R3 = TotalMemory */
+	/*lis	r28,hold_residual@h
+	ori	r28,r28,hold_residual@l*/
+	/* changed to use r3 (as firmware does) for kernel
+	   as ptr to residual -- Cort*/
+	li	r5,0x100		/* Kernel code starts here */
+	mtlr	r5
+	blr	
+hang:
+	b	hang	
+
+	.globl	_get_SP
+_get_SP:
+	mr	r3,r1
+	blr
+
+	.globl	_get_PVR
+_get_PVR:
+	mfspr	r3,PVR
+	blr
+
+	.globl	_get_MSR
+_get_MSR:
+	mfmsr	r3
+	blr
+
+	.globl	_put_MSR
+_put_MSR:
+	sync
+	mtmsr	r3
+	blr
+
+	.globl	_get_HID0
+_get_HID0:
+	mfspr	r3,HID0
+	blr
+	
+	.globl	_put_HID0
+_put_HID0:
+	sync
+	mtspr	HID0,r3
+	blr
+
+/*
+ * This space [buffer] is used to forceably flush the data cache when
+ * running in copyback mode.  This is necessary IFF the data cache could
+ * contain instructions for which the instruction cache has stale data.
+ * Since the instruction cache NEVER snoops the data cache, memory must
+ * be made coherent with the data cache to insure that the instruction
+ * cache gets a valid instruction stream.  Note that this flushing is
+ * only performed when switching from system to user mode since this is
+ * the only juncture [as far as the OS goes] where the data cache may
+ * contain instructions, e.g. after a disk read.
+ */
+#define NUM_CACHE_LINES 128*8
+#define CACHE_LINE_SIZE 32 
+#if 0
+cache_flush_buffer:
+	.space	NUM_CACHE_LINES*CACHE_LINE_SIZE	/* CAUTION! these need to match hardware */
+#else
+#define cache_flush_buffer 0x1000
+#endif
+
+
+/*
+ * Flush instruction cache
+ * *** I'm really paranoid here!
+ */
+_GLOBAL(flush_instruction_cache)
+	mflr	r5
+	bl	flush_data_cache
+	mfspr	r3,HID0	/* Caches are controlled by this register */
+	li	r4,0
+	ori	r4,r4,(HID0_ICE|HID0_ICFI)
+	or	r3,r3,r4	/* Need to enable+invalidate to clear */
+	mtspr	HID0,r3
+	andc	r3,r3,r4
+	ori	r3,r3,HID0_ICE	/* Enable cache */
+	mtspr	HID0,r3
+	mtlr	r5
+	blr
+
+/*
+ * Flush data cache
+ * *** I'm really paranoid here!
+ */
+_GLOBAL(flush_data_cache)
+	lis	r3,cache_flush_buffer@h
+	ori	r3,r3,cache_flush_buffer@l
+	li	r4,NUM_CACHE_LINES
+	mtctr	r4
+#if 0
+00:	dcbz	0,r3			/* Flush cache line with minimal BUS traffic */
+#else
+00:	lwz	r4,0(r3)
+#endif
+	addi	r3,r3,CACHE_LINE_SIZE	/* Next line, please */
+	bdnz	00b	
+10:	blr
+
+/*
+ * Flush a particular page from the DATA cache
+ * Note: this is necessary because the instruction cache does *not*
+ * snoop from the data cache.
+ *	void flush_page(void *page)
+ */
+_GLOBAL(flush_page)
+	li	r4,0x0FFF
+	andc	r3,r3,r4		/* Get page base address */
+	li	r4,4096/CACHE_LINE_SIZE	/* Number of lines in a page */
+	mtctr	r4
+00:	dcbf	0,r3			/* Clear line */
+	icbi	0,r3
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	00b
+	blr
+
+/*
+ * Execute a [foreign] function
+ *
+ * run(p1, p2, cp, ep, entry)
+ *
+ */
+ 	.globl	run
+run:
+	mtctr	r7			/* Entry point */
+#define IS_PreP 0x50726550		/* 'PreP' */	
+	lis	r30,IS_PreP>>16
+	ori	r30,r30,IS_PreP&0xFFFF
+	mr	11,r5
+	mr	12,r6
+	mr	r28,r5
+	mr	r29,r6
+	mr	11,r5
+	mr	12,r6
+	bctr
+
+	.comm	.stack,4096*2,4
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/inflate.c linux/arch/ppc/boot/inflate.c
--- v2.1.15/linux/arch/ppc/boot/inflate.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/ppc/boot/inflate.c	Wed Dec 18 10:49:52 1996
@@ -0,0 +1,810 @@
+#define DEBG(x)
+#define DEBG1(x)
+/* inflate.c -- Not copyrighted 1992 by Mark Adler
+   version c10p1, 10 January 1993 */
+
+/* 
+ * Adapted for booting Linux by Hannu Savolainen 1993
+ * based on gzip-1.0.3 
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: inflate.c,v 0.10 1993/02/04 13:21:06 jloup Exp $";
+#endif
+
+#include "gzip.h"
+#define slide window
+
+#if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H)
+#  include <sys/types.h>
+#  include <stdlib.h>
+#endif
+
+struct huft {
+  uch e;                /* number of extra bits or operation */
+  uch b;                /* number of bits in this code or subcode */
+  union {
+    ush n;              /* literal, length base, or distance base */
+    struct huft *t;     /* pointer to next level of table */
+  } v;
+};
+
+
+/* Function prototypes */
+int huft_build OF((unsigned *, unsigned, unsigned, ush *, ush *,
+                   struct huft **, int *));
+int huft_free OF((struct huft *));
+int inflate_codes OF((struct huft *, struct huft *, int, int));
+int inflate_stored OF((void));
+int inflate_fixed OF((void));
+int inflate_dynamic OF((void));
+int inflate_block OF((int *));
+int inflate OF((void));
+
+
+#define wp outcnt
+#define flush_output(w) (wp=(w),flush_window())
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+static unsigned border[] = {    /* Order of the bit length code lengths */
+        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+static ush cplens[] = {         /* Copy lengths for literal codes 257..285 */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+        /* note: see note #13 above about the 258 in this list. */
+static ush cplext[] = {         /* Extra bits for literal codes 257..285 */
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */
+static ush cpdist[] = {         /* Copy offsets for distance codes 0..29 */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577};
+static ush cpdext[] = {         /* Extra bits for distance codes */
+        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13};
+
+
+ulg bb;                         /* bit buffer */
+unsigned bk;                    /* bits in bit buffer */
+
+ush mask_bits[] = {
+    0x0000,
+    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+#ifdef CRYPT
+  uch cc;
+#  define NEXTBYTE() \
+     (decrypt ? (cc = get_byte(), zdecode(cc), cc) : get_byte())
+#else
+#  define NEXTBYTE()  (uch)get_byte()
+#endif
+#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<<k;k+=8;}}
+#define DUMPBITS(n) {b>>=(n);k-=(n);}
+
+int lbits = 9;          /* bits in base literal/length lookup table */
+int dbits = 6;          /* bits in base distance lookup table */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
+#define BMAX 16         /* maximum bit length of any code (16 for explode) */
+#define N_MAX 288       /* maximum number of codes in any set */
+
+
+unsigned hufts;         /* track memory usage */
+
+
+int huft_build(b, n, s, d, e, t, m)
+unsigned *b;            /* code lengths in bits (all assumed <= BMAX) */
+unsigned n;             /* number of codes (assumed <= N_MAX) */
+unsigned s;             /* number of simple-valued codes (0..s-1) */
+ush *d;                 /* list of base values for non-simple codes */
+ush *e;                 /* list of extra bits for non-simple codes */
+struct huft **t;        /* result: starting table */
+int *m;                 /* maximum lookup bits, returns actual */
+/* Given a list of code lengths and a maximum table size, make a set of
+   tables to decode that set of codes.  Return zero on success, one if
+   the given code set is incomplete (the tables are still built in this
+   case), two if the input is invalid (all zero length codes or an
+   oversubscribed set of lengths), and three if not enough memory. */
+{
+  unsigned a;                   /* counter for codes of length k */
+  unsigned c[BMAX+1];           /* bit length count table */
+  unsigned f;                   /* i repeats in table every f entries */
+  int g;                        /* maximum code length */
+  int h;                        /* table level */
+  register unsigned i;          /* counter, current code */
+  register unsigned j;          /* counter */
+  register int k;               /* number of bits in current code */
+  int l;                        /* bits per table (returned in m) */
+  register unsigned *p;         /* pointer into c[], b[], or v[] */
+  register struct huft *q;      /* points to current table */
+  struct huft r;                /* table entry for structure assignment */
+  struct huft *u[BMAX];         /* table stack */
+  unsigned v[N_MAX];            /* values in order of bit length */
+  register int w;               /* bits before this table == (l * h) */
+  unsigned x[BMAX+1];           /* bit offsets, then code stack */
+  unsigned *xp;                 /* pointer into x */
+  int y;                        /* number of dummy codes added */
+  unsigned z;                   /* number of entries in current table */
+
+DEBG("huft1 ");
+
+  /* Generate counts for each bit length */
+  memzero(c, sizeof(c));
+  p = b;  i = n;
+  do {
+    c[*p++]++;                  /* assume all entries <= BMAX */
+  } while (--i);
+  if (c[0] == n)                /* null input--all zero length codes */
+  {
+    *t = (struct huft *)NULL;
+    *m = 0;
+    return 0;
+  }
+
+DEBG("huft2 ");
+
+  /* Find minimum and maximum length, bound *m by those */
+  l = *m;
+  for (j = 1; j <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((unsigned)l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((unsigned)l > i)
+    l = i;
+  *m = l;
+
+DEBG("huft3 ");
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0)
+      return 2;                 /* bad input: more codes than bits */
+  if ((y -= c[i]) < 0)
+    return 2;
+  c[i] += y;
+
+DEBG("huft4 ");
+
+  /* Generate starting offsets into the value table for each length */
+  x[1] = j = 0;
+  p = c + 1;  xp = x + 2;
+  while (--i) {                 /* note that i == g from above */
+    *xp++ = (j += *p++);
+  }
+
+DEBG("huft5 ");
+
+  /* Make a table of values in order of bit lengths */
+  p = b;  i = 0;
+  do {
+    if ((j = *p++) != 0)
+      v[x[j]++] = i;
+  } while (++i < n);
+
+DEBG("h6 ");
+
+  /* Generate the Huffman codes and for each, make the table entries */
+  x[0] = i = 0;                 /* first Huffman code is zero */
+  p = v;                        /* grab values in bit order */
+  h = -1;                       /* no tables yet--level -1 */
+  w = -l;                       /* bits decoded == (l * h) */
+  u[0] = (struct huft *)NULL;   /* just to keep compilers happy */
+  q = (struct huft *)NULL;      /* ditto */
+  z = 0;                        /* ditto */
+DEBG("h6a ");
+
+  /* go through the bit lengths (k already is bits in shortest code) */
+  for (; k <= g; k++)
+  {
+DEBG("h6b ");
+    a = c[k];
+    while (a--)
+    {
+DEBG("h6b1 ");
+      /* here i is the Huffman code of length k bits for value *p */
+      /* make tables up to required level */
+      while (k > w + l)
+      {
+DEBG1("1 ");
+        h++;
+        w += l;                 /* previous table always l bits */
+
+        /* compute minimum size table less than or equal to l bits */
+        z = (z = g - w) > (unsigned)l ? l : z;  /* upper limit on table size */
+        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
+        {                       /* too few codes for k-w bit table */
+DEBG1("2 ");
+          f -= a + 1;           /* deduct codes from patterns left */
+          xp = c + k;
+          while (++j < z)       /* try smaller tables up to z bits */
+          {
+            if ((f <<= 1) <= *++xp)
+              break;            /* enough codes to use up j bits */
+            f -= *xp;           /* else deduct codes from patterns */
+          }
+        }
+DEBG1("3 ");
+        z = 1 << j;             /* table entries for j-bit table */
+
+        /* allocate and link in new table */
+        q = (struct huft *)malloc((z + 1)*sizeof(struct huft));
+DEBG1("4 ");
+        hufts += z + 1;         /* track memory usage */
+        *t = q + 1;             /* link to list for huft_free() */
+        *(t = &(q->v.t)) = (struct huft *)NULL;
+        u[h] = ++q;             /* table starts after link */
+
+DEBG1("5 ");
+        /* connect to last table, if there is one */
+        if (h)
+        {
+          x[h] = i;             /* save pattern for backing up */
+          r.b = (uch)l;         /* bits to dump before this table */
+          r.e = (uch)(16 + j);  /* bits in this table */
+          r.v.t = q;            /* pointer to this table */
+          j = i >> (w - l);     /* (get around Turbo C bug) */
+          u[h-1][j] = r;        /* connect to last table */
+        }
+DEBG1("6 ");
+      }
+DEBG("h6c ");
+
+      /* set up table entry in r */
+      r.b = (uch)(k - w);
+      if (p >= v + n)
+        r.e = 99;               /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.e = (uch)(*p < 256 ? 16 : 15);    /* 256 is end-of-block code */
+        r.v.n = *p++;           /* simple code is just the value */
+      }
+      else
+      {
+        r.e = (uch)e[*p - s];   /* non-simple--look up in lists */
+        r.v.n = d[*p++ - s];
+      }
+DEBG("h6d ");
+
+      /* fill code-like entries with r */
+      f = 1 << (k - w);
+      for (j = i >> w; j < z; j += f)
+        q[j] = r;
+
+      /* backwards increment the k-bit code i */
+      for (j = 1 << (k - 1); i & j; j >>= 1)
+        i ^= j;
+      i ^= j;
+
+      /* backup over finished tables */
+      while ((i & ((1 << w) - 1)) != x[h])
+      {
+        h--;                    /* don't need to update q */
+        w -= l;
+      }
+DEBG("h6e ");
+    }
+DEBG("h6f ");
+  }
+
+DEBG("huft7 ");
+
+  /* Return true (1) if we were given an incomplete table */
+  return y != 0 && g != 1;
+}
+
+
+
+int huft_free(t)
+struct huft *t;         /* table to free */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+   list of the tables it made, with the links in a dummy first entry of
+   each table. */
+{
+  register struct huft *p, *q;
+
+
+  /* Go through linked list, freeing from the malloced (t[-1]) address. */
+  p = t;
+  while (p != (struct huft *)NULL)
+  {
+    q = (--p)->v.t;
+    free(p);
+    p = q;
+  } 
+  return 0;
+}
+
+
+int inflate_codes(tl, td, bl, bd)
+struct huft *tl, *td;   /* literal/length and distance decoder tables */
+int bl, bd;             /* number of bits decoded by tl[] and td[] */
+/* inflate (decompress) the codes in a deflated (compressed) block.
+   Return an error code or zero if it all goes ok. */
+{
+  register unsigned e;  /* table entry flag/number of extra bits */
+  unsigned n, d;        /* length and index for copy */
+  unsigned w;           /* current window position */
+  struct huft *t;       /* pointer to table entry */
+  unsigned ml, md;      /* masks for bl and bd bits */
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+
+
+  /* make local copies of globals */
+  b = bb;                       /* initialize bit buffer */
+  k = bk;
+  w = wp;                       /* initialize window position */
+
+  /* inflate the coded data */
+  ml = mask_bits[bl];           /* precompute masks for speed */
+  md = mask_bits[bd];
+  for (;;)                      /* do until end of block */
+  {
+    NEEDBITS((unsigned)bl)
+    if ((e = (t = tl + ((unsigned)b & ml))->e) > 16)
+      do {
+        if (e == 99)
+          return 1;
+        DUMPBITS(t->b)
+        e -= 16;
+        NEEDBITS(e)
+      } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+    DUMPBITS(t->b)
+    if (e == 16)                /* then it's a literal */
+    {
+      slide[w++] = (uch)t->v.n;
+      if (w == WSIZE)
+      {
+        flush_output(w);
+        w = 0;
+      }
+    }
+    else                        /* it's an EOB or a length */
+    {
+      /* exit if end of block */
+      if (e == 15)
+        break;
+
+      /* get length of block to copy */
+      NEEDBITS(e)
+      n = t->v.n + ((unsigned)b & mask_bits[e]);
+      DUMPBITS(e);
+
+      /* decode distance of block to copy */
+      NEEDBITS((unsigned)bd)
+      if ((e = (t = td + ((unsigned)b & md))->e) > 16)
+        do {
+          if (e == 99)
+            return 1;
+          DUMPBITS(t->b)
+          e -= 16;
+          NEEDBITS(e)
+        } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16);
+      DUMPBITS(t->b)
+      NEEDBITS(e)
+      d = w - t->v.n - ((unsigned)b & mask_bits[e]);
+      DUMPBITS(e)
+
+      /* do the copy */
+      do {
+        n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e);
+#if !defined(NOMEMCPY) && !defined(DEBUG)
+        if (w - d >= e)         /* (this test assumes unsigned comparison) */
+        {
+          memcpy(slide + w, slide + d, e);
+          w += e;
+          d += e;
+        }
+        else                      /* do it slow to avoid memcpy() overlap */
+#endif /* !NOMEMCPY */
+          do {
+            slide[w++] = slide[d++];
+          } while (--e);
+        if (w == WSIZE)
+        {
+          flush_output(w);
+          w = 0;
+        }
+      } while (n);
+    }
+  }
+
+
+  /* restore the globals from the locals */
+  wp = w;                       /* restore global window pointer */
+  bb = b;                       /* restore global bit buffer */
+  bk = k;
+
+  /* done */
+  return 0;
+}
+
+
+
+int inflate_stored()
+/* "decompress" an inflated type 0 (stored) block. */
+{
+  unsigned n;           /* number of bytes in block */
+  unsigned w;           /* current window position */
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+
+DEBG("<stor");
+
+  /* make local copies of globals */
+  b = bb;                       /* initialize bit buffer */
+  k = bk;
+  w = wp;                       /* initialize window position */
+
+
+  /* go to byte boundary */
+  n = k & 7;
+  DUMPBITS(n);
+
+
+  /* get the length and its complement */
+  NEEDBITS(16)
+  n = ((unsigned)b & 0xffff);
+  DUMPBITS(16)
+  NEEDBITS(16)
+  if (n != (unsigned)((~b) & 0xffff))
+    return 1;                   /* error in compressed data */
+  DUMPBITS(16)
+
+
+  /* read and output the compressed data */
+  while (n--)
+  {
+    NEEDBITS(8)
+    slide[w++] = (uch)b;
+    if (w == WSIZE)
+    {
+      flush_output(w);
+      w = 0;
+    }
+    DUMPBITS(8)
+  }
+
+
+  /* restore the globals from the locals */
+  wp = w;                       /* restore global window pointer */
+  bb = b;                       /* restore global bit buffer */
+  bk = k;
+
+  DEBG(">");
+  return 0;
+}
+
+
+
+int inflate_fixed()
+/* decompress an inflated type 1 (fixed Huffman codes) block.  We should
+   either replace this with a custom decoder, or at least precompute the
+   Huffman tables. */
+{
+  int i;                /* temporary variable */
+  struct huft *tl;      /* literal/length code table */
+  struct huft *td;      /* distance code table */
+  int bl;               /* lookup bits for tl */
+  int bd;               /* lookup bits for td */
+  unsigned l[288];      /* length list for huft_build */
+
+DEBG("<fix");
+
+  /* set up literal table */
+  for (i = 0; i < 144; i++)
+    l[i] = 8;
+  for (; i < 256; i++)
+    l[i] = 9;
+  for (; i < 280; i++)
+    l[i] = 7;
+  for (; i < 288; i++)          /* make a complete, but wrong code set */
+    l[i] = 8;
+  bl = 7;
+  if ((i = huft_build(l, 288, 257, cplens, cplext, &tl, &bl)) != 0)
+    return i;
+
+
+  /* set up distance table */
+  for (i = 0; i < 30; i++)      /* make an incomplete code set */
+    l[i] = 5;
+  bd = 5;
+  if ((i = huft_build(l, 30, 0, cpdist, cpdext, &td, &bd)) > 1)
+  {
+    huft_free(tl);
+
+    DEBG(">");
+    return i;
+  }
+
+
+  /* decompress until an end-of-block code */
+  if (inflate_codes(tl, td, bl, bd))
+    return 1;
+
+
+  /* free the decoding tables, return */
+  huft_free(tl);
+  huft_free(td);
+  return 0;
+}
+
+
+
+int inflate_dynamic()
+/* decompress an inflated type 2 (dynamic Huffman codes) block. */
+{
+  int i;                /* temporary variables */
+  unsigned j;
+  unsigned l;           /* last length */
+  unsigned m;           /* mask for bit lengths table */
+  unsigned n;           /* number of lengths to get */
+  struct huft *tl;      /* literal/length code table */
+  struct huft *td;      /* distance code table */
+  int bl;               /* lookup bits for tl */
+  int bd;               /* lookup bits for td */
+  unsigned nb;          /* number of bit length codes */
+  unsigned nl;          /* number of literal/length codes */
+  unsigned nd;          /* number of distance codes */
+#ifdef PKZIP_BUG_WORKAROUND
+  unsigned ll[288+32];  /* literal/length and distance code lengths */
+#else
+  unsigned ll[286+30];  /* literal/length and distance code lengths */
+#endif
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+
+DEBG("<dyn");
+
+  /* make local bit buffer */
+  b = bb;
+  k = bk;
+
+
+  /* read in table lengths */
+  NEEDBITS(5)
+  nl = 257 + ((unsigned)b & 0x1f);      /* number of literal/length codes */
+  DUMPBITS(5)
+  NEEDBITS(5)
+  nd = 1 + ((unsigned)b & 0x1f);        /* number of distance codes */
+  DUMPBITS(5)
+  NEEDBITS(4)
+  nb = 4 + ((unsigned)b & 0xf);         /* number of bit length codes */
+  DUMPBITS(4)
+#ifdef PKZIP_BUG_WORKAROUND
+  if (nl > 288 || nd > 32)
+#else
+  if (nl > 286 || nd > 30)
+#endif
+    return 1;                   /* bad lengths */
+
+DEBG("dyn1 ");
+
+  /* read in bit-length-code lengths */
+  for (j = 0; j < nb; j++)
+  {
+    NEEDBITS(3)
+    ll[border[j]] = (unsigned)b & 7;
+    DUMPBITS(3)
+  }
+  for (; j < 19; j++)
+    ll[border[j]] = 0;
+
+DEBG("dyn2 ");
+
+  /* build decoding table for trees--single level, 7 bit lookup */
+  bl = 7;
+  if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0)
+  {
+    if (i == 1)
+      huft_free(tl);
+    return i;                   /* incomplete code set */
+  }
+
+DEBG("dyn3 ");
+
+  /* read in literal and distance code lengths */
+  n = nl + nd;
+  m = mask_bits[bl];
+  i = l = 0;
+  while ((unsigned)i < n)
+  {
+    NEEDBITS((unsigned)bl)
+    j = (td = tl + ((unsigned)b & m))->b;
+    DUMPBITS(j)
+    j = td->v.n;
+    if (j < 16)                 /* length of code in bits (0..15) */
+      ll[i++] = l = j;          /* save last length in l */
+    else if (j == 16)           /* repeat last length 3 to 6 times */
+    {
+      NEEDBITS(2)
+      j = 3 + ((unsigned)b & 3);
+      DUMPBITS(2)
+      if ((unsigned)i + j > n)
+        return 1;
+      while (j--)
+        ll[i++] = l;
+    }
+    else if (j == 17)           /* 3 to 10 zero length codes */
+    {
+      NEEDBITS(3)
+      j = 3 + ((unsigned)b & 7);
+      DUMPBITS(3)
+      if ((unsigned)i + j > n)
+        return 1;
+      while (j--)
+        ll[i++] = 0;
+      l = 0;
+    }
+    else                        /* j == 18: 11 to 138 zero length codes */
+    {
+      NEEDBITS(7)
+      j = 11 + ((unsigned)b & 0x7f);
+      DUMPBITS(7)
+      if ((unsigned)i + j > n)
+        return 1;
+      while (j--)
+        ll[i++] = 0;
+      l = 0;
+    }
+  }
+
+DEBG("dyn4 ");
+
+  /* free decoding table for trees */
+  huft_free(tl);
+
+DEBG("dyn5 ");
+
+  /* restore the global bit buffer */
+  bb = b;
+  bk = k;
+
+DEBG("dyn5a ");
+
+  /* build the decoding tables for literal/length and distance codes */
+  bl = lbits;
+  if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0)
+  {
+DEBG("dyn5b ");
+    if (i == 1) {
+      error(" incomplete literal tree\n");
+      huft_free(tl);
+    }
+    return i;                   /* incomplete code set */
+  }
+DEBG("dyn5c ");
+  bd = dbits;
+  if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0)
+  {
+DEBG("dyn5d ");
+    if (i == 1) {
+      error(" incomplete distance tree\n");
+#ifdef PKZIP_BUG_WORKAROUND
+      i = 0;
+    }
+#else
+      huft_free(td);
+    }
+    huft_free(tl);
+    return i;                   /* incomplete code set */
+#endif
+  }
+
+DEBG("dyn6 ");
+
+  /* decompress until an end-of-block code */
+  if (inflate_codes(tl, td, bl, bd))
+    return 1;
+
+DEBG("dyn7 ");
+
+  /* free the decoding tables, return */
+  huft_free(tl);
+  huft_free(td);
+
+  DEBG(">");
+  return 0;
+}
+
+
+
+int inflate_block(e)
+int *e;                 /* last block flag */
+/* decompress an inflated block */
+{
+  unsigned t;           /* block type */
+  register ulg b;       /* bit buffer */
+  register unsigned k;  /* number of bits in bit buffer */
+
+  DEBG("<blk");
+
+  /* make local bit buffer */
+  b = bb;
+  k = bk;
+
+
+  /* read in last block bit */
+  NEEDBITS(1)
+  *e = (int)b & 1;
+  DUMPBITS(1)
+
+
+  /* read in block type */
+  NEEDBITS(2)
+  t = (unsigned)b & 3;
+  DUMPBITS(2)
+
+
+  /* restore the global bit buffer */
+  bb = b;
+  bk = k;
+
+  /* inflate that block type */
+  if (t == 2)
+    return inflate_dynamic();
+  if (t == 0)
+    return inflate_stored();
+  if (t == 1)
+    return inflate_fixed();
+
+  DEBG(">");
+
+  /* bad block type */
+  return 2;
+}
+
+
+
+int inflate()
+/* decompress an inflated entry */
+{
+  int e;                /* last block flag */
+  int r;                /* result code */
+  unsigned h;           /* maximum struct huft's malloc'ed */
+
+
+  /* initialize window, bit buffer */
+  wp = 0;
+  bk = 0;
+  bb = 0;
+
+
+  /* decompress until the last block */
+  h = 0;
+  do {
+    hufts = 0;
+    if ((r = inflate_block(&e)) != 0)
+      return r;
+    if (hufts > h)
+      h = hufts;
+  } while (!e);
+
+  /* Undo too much lookahead. The next read will be byte aligned so we
+   * can discard unused bits in the last meaningful byte.
+   */
+  while (bk >= 8) {
+    bk -= 8;
+    inptr--;
+  }
+
+  /* flush out slide */
+  flush_output(wp);
+
+
+  /* return success */
+#ifdef DEBUG
+  fprintf(stderr, "<%u> ", h);
+#endif /* DEBUG */
+  return 0;
+}
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/iso_font.h linux/arch/ppc/boot/iso_font.h
--- v2.1.15/linux/arch/ppc/boot/iso_font.h	Thu Jan  1 02:00:00 1970
+++ linux/arch/ppc/boot/iso_font.h	Wed Dec 18 10:49:52 1996
@@ -0,0 +1,257 @@
+static const unsigned char font[] = {
+/* 0x00 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x01 */ 0x00,0x00,0x7E,0x81,0xA5,0x81,0x81,0xBD,0x99,0x81,0x81,0x7E,0x00,0x00,0x00,0x00,
+/* 0x02 */ 0x00,0x00,0x7E,0xFF,0xDB,0xFF,0xFF,0xC3,0xC3,0xE7,0xFF,0x7E,0x00,0x00,0x00,0x00,
+/* 0x03 */ 0x00,0x00,0x00,0x00,0x6C,0xFE,0xFE,0xFE,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,
+/* 0x04 */ 0x00,0x00,0x00,0x00,0x10,0x38,0x7C,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00,
+/* 0x05 */ 0x00,0x00,0x00,0x18,0x3C,0x3C,0xE7,0xE7,0xE7,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x06 */ 0x00,0x00,0x00,0x18,0x3C,0x7E,0xFF,0xFF,0x7E,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x07 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x08 */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE7,0xC3,0xC3,0xE7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+/* 0x09 */ 0x00,0x00,0x00,0x00,0x00,0x3C,0x66,0x42,0x42,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,
+/* 0x0A */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xC3,0x99,0xBD,0xBD,0x99,0xC3,0xFF,0xFF,0xFF,0xFF,0xFF,
+/* 0x0B */ 0x00,0x00,0x3E,0x0E,0x1A,0x32,0x78,0xCC,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,
+/* 0x0C */ 0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0x0D */ 0x00,0x00,0x30,0x38,0x3C,0x36,0x33,0x30,0x30,0x70,0xF0,0xE0,0x00,0x00,0x00,0x00,
+/* 0x0E */ 0x00,0x00,0x7F,0x63,0x7F,0x63,0x63,0x63,0x63,0x67,0xE7,0xE6,0xC0,0x00,0x00,0x00,
+/* 0x0F */ 0x00,0x00,0x00,0x18,0x18,0xDB,0x3C,0xE7,0x3C,0xDB,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0x10 */ 0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFE,0xF8,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,
+/* 0x11 */ 0x00,0x02,0x06,0x0E,0x1E,0x3E,0xFE,0x3E,0x1E,0x0E,0x06,0x02,0x00,0x00,0x00,0x00,
+/* 0x12 */ 0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,
+/* 0x13 */ 0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x66,0x00,0x00,0x00,0x00,
+/* 0x14 */ 0x00,0x00,0x7F,0xDB,0xDB,0xDB,0x7B,0x1B,0x1B,0x1B,0x1B,0x1B,0x00,0x00,0x00,0x00,
+/* 0x15 */ 0x00,0x7C,0xC6,0x60,0x38,0x6C,0xC6,0xC6,0x6C,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,
+/* 0x16 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFE,0xFE,0xFE,0x00,0x00,0x00,0x00,
+/* 0x17 */ 0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00,
+/* 0x18 */ 0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0x19 */ 0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,
+/* 0x1A */ 0x00,0x00,0x00,0x00,0x00,0x18,0x0C,0xFE,0x0C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x1B */ 0x00,0x00,0x00,0x00,0x00,0x30,0x60,0xFE,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x1C */ 0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0xC0,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x1D */ 0x00,0x00,0x00,0x00,0x00,0x28,0x6C,0xFE,0x6C,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x1E */ 0x00,0x00,0x00,0x00,0x10,0x38,0x38,0x7C,0x7C,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00,
+/* 0x1F */ 0x00,0x00,0x00,0x00,0xFE,0xFE,0x7C,0x7C,0x38,0x38,0x10,0x00,0x00,0x00,0x00,0x00,
+/* 0x20 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x21 */ 0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0x22 */ 0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x23 */ 0x00,0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00,
+/* 0x24 */ 0x18,0x18,0x7C,0xC6,0xC2,0xC0,0x7C,0x06,0x06,0x86,0xC6,0x7C,0x18,0x18,0x00,0x00,
+/* 0x25 */ 0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00,
+/* 0x26 */ 0x00,0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x27 */ 0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x28 */ 0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00,
+/* 0x29 */ 0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00,
+/* 0x2A */ 0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x2B */ 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x2C */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00,
+/* 0x2D */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x2E */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0x2F */ 0x00,0x00,0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00,
+/* 0x30 */ 0x00,0x00,0x38,0x6C,0xC6,0xC6,0xD6,0xD6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00,
+/* 0x31 */ 0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00,
+/* 0x32 */ 0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00,
+/* 0x33 */ 0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x34 */ 0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00,
+/* 0x35 */ 0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x36 */ 0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x37 */ 0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00,
+/* 0x38 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x39 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00,
+/* 0x3A */ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
+/* 0x3B */ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00,
+/* 0x3C */ 0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00,
+/* 0x3D */ 0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x3E */ 0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00,
+/* 0x3F */ 0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0x40 */ 0x00,0x00,0x00,0x7C,0xC6,0xC6,0xDE,0xDE,0xDE,0xDC,0xC0,0x7C,0x00,0x00,0x00,0x00,
+/* 0x41 */ 0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0x42 */ 0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00,
+/* 0x43 */ 0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00,
+/* 0x44 */ 0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00,
+/* 0x45 */ 0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,
+/* 0x46 */ 0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
+/* 0x47 */ 0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xDE,0xC6,0xC6,0x66,0x3A,0x00,0x00,0x00,0x00,
+/* 0x48 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0x49 */ 0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x4A */ 0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,
+/* 0x4B */ 0x00,0x00,0xE6,0x66,0x66,0x6C,0x78,0x78,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,
+/* 0x4C */ 0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00,
+/* 0x4D */ 0x00,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0x4E */ 0x00,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0x4F */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x50 */ 0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
+/* 0x51 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00,
+/* 0x52 */ 0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,
+/* 0x53 */ 0x00,0x00,0x7C,0xC6,0xC6,0x60,0x38,0x0C,0x06,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x54 */ 0x00,0x00,0x7E,0x7E,0x5A,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x55 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x56 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00,
+/* 0x57 */ 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0xEE,0x6C,0x00,0x00,0x00,0x00,
+/* 0x58 */ 0x00,0x00,0xC6,0xC6,0x6C,0x7C,0x38,0x38,0x7C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0x59 */ 0x00,0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x5A */ 0x00,0x00,0xFE,0xC6,0x86,0x0C,0x18,0x30,0x60,0xC2,0xC6,0xFE,0x00,0x00,0x00,0x00,
+/* 0x5B */ 0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00,
+/* 0x5C */ 0x00,0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x06,0x02,0x00,0x00,0x00,0x00,
+/* 0x5D */ 0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00,
+/* 0x5E */ 0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x5F */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,
+/* 0x60 */ 0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x61 */ 0x00,0x00,0x00,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x62 */ 0x00,0x00,0xE0,0x60,0x60,0x78,0x6C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00,
+/* 0x63 */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x64 */ 0x00,0x00,0x1C,0x0C,0x0C,0x3C,0x6C,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x65 */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x66 */ 0x00,0x00,0x38,0x6C,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
+/* 0x67 */ 0x00,0x00,0x00,0x00,0x00,0x3E,0x66,0x66,0x66,0x66,0x66,0x3E,0x06,0x66,0x3C,0x00,
+/* 0x68 */ 0x00,0x00,0xE0,0x60,0x60,0x6C,0x76,0x66,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00,
+/* 0x69 */ 0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x6A */ 0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00,
+/* 0x6B */ 0x00,0x00,0xE0,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0xE6,0x00,0x00,0x00,0x00,
+/* 0x6C */ 0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x6D */ 0x00,0x00,0x00,0x00,0x00,0x6C,0xFE,0xD6,0xD6,0xD6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0x6E */ 0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,
+/* 0x6F */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x70 */ 0x00,0x00,0x00,0x00,0x00,0xFC,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00,
+/* 0x71 */ 0x00,0x00,0x00,0x00,0x00,0x7E,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C,0x1E,0x00,
+/* 0x72 */ 0x00,0x00,0x00,0x00,0x00,0xDC,0x76,0x66,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00,
+/* 0x73 */ 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0x60,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x74 */ 0x00,0x00,0x10,0x30,0x30,0xFC,0x30,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00,
+/* 0x75 */ 0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x76 */ 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00,
+/* 0x77 */ 0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0x6C,0x00,0x00,0x00,0x00,
+/* 0x78 */ 0x00,0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x38,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,
+/* 0x79 */ 0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00,
+/* 0x7A */ 0x00,0x00,0x00,0x00,0x00,0xFE,0xCC,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00,
+/* 0x7B */ 0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00,
+/* 0x7C */ 0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0x7D */ 0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00,
+/* 0x7E */ 0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0x7F */ 0x00,0x00,0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00,
+/* 0x80 */ 0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x0C,0x06,0x7C,0x00,0x00,
+/* 0x81 */ 0x00,0x00,0xCC,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x82 */ 0x00,0x0C,0x18,0x30,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x83 */ 0x00,0x10,0x38,0x6C,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x84 */ 0x00,0x00,0xCC,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x85 */ 0x00,0x60,0x30,0x18,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x86 */ 0x00,0x38,0x6C,0x38,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x87 */ 0x00,0x00,0x00,0x00,0x3C,0x66,0x60,0x60,0x66,0x3C,0x0C,0x06,0x3C,0x00,0x00,0x00,
+/* 0x88 */ 0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x89 */ 0x00,0x00,0xC6,0x00,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x8A */ 0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xFE,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x8B */ 0x00,0x00,0x66,0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x8C */ 0x00,0x18,0x3C,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x8D */ 0x00,0x60,0x30,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0x8E */ 0x00,0xC6,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0x8F */ 0x38,0x6C,0x38,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0x90 */ 0x18,0x30,0x60,0x00,0xFE,0x66,0x60,0x7C,0x60,0x60,0x66,0xFE,0x00,0x00,0x00,0x00,
+/* 0x91 */ 0x00,0x00,0x00,0x00,0x00,0xCC,0x76,0x36,0x7E,0xD8,0xD8,0x6E,0x00,0x00,0x00,0x00,
+/* 0x92 */ 0x00,0x00,0x3E,0x6C,0xCC,0xCC,0xFE,0xCC,0xCC,0xCC,0xCC,0xCE,0x00,0x00,0x00,0x00,
+/* 0x93 */ 0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x94 */ 0x00,0x00,0xC6,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x95 */ 0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x96 */ 0x00,0x30,0x78,0xCC,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x97 */ 0x00,0x60,0x30,0x18,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0x98 */ 0x00,0x00,0xC6,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00,
+/* 0x99 */ 0x00,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x9A */ 0x00,0xC6,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0x9B */ 0x00,0x18,0x18,0x3C,0x66,0x60,0x60,0x60,0x66,0x3C,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0x9C */ 0x00,0x38,0x6C,0x64,0x60,0xF8,0x60,0x60,0x60,0x60,0xE6,0xFC,0x00,0x00,0x00,0x00,
+/* 0x9D */ 0x00,0x00,0x66,0x66,0x3C,0x18,0x7E,0x18,0x7E,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0x9E */ 0x00,0xF8,0xCC,0xCC,0xF8,0xC4,0xCC,0xDE,0xCC,0xCC,0xCC,0xC6,0x00,0x00,0x00,0x00,
+/* 0x9F */ 0x00,0x0E,0x1B,0x18,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x18,0xD8,0x70,0x00,0x00,
+/* 0xA0 */ 0x00,0x18,0x30,0x60,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0xA1 */ 0x00,0x0C,0x18,0x30,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
+/* 0xA2 */ 0x00,0x18,0x30,0x60,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0xA3 */ 0x00,0x18,0x30,0x60,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00,
+/* 0xA4 */ 0x00,0x00,0x76,0xDC,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,
+/* 0xA5 */ 0x76,0xDC,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0xA6 */ 0x00,0x3C,0x6C,0x6C,0x3E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xA7 */ 0x00,0x38,0x6C,0x6C,0x38,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xA8 */ 0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x60,0xC0,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00,
+/* 0xA9 */ 0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,
+/* 0xAA */ 0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,
+/* 0xAB */ 0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x60,0xDC,0x86,0x0C,0x18,0x3E,0x00,0x00,
+/* 0xAC */ 0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x66,0xCE,0x9E,0x3E,0x06,0x06,0x00,0x00,
+/* 0xAD */ 0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x18,0x3C,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,
+/* 0xAE */ 0x00,0x00,0x00,0x00,0x00,0x36,0x6C,0xD8,0x6C,0x36,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xAF */ 0x00,0x00,0x00,0x00,0x00,0xD8,0x6C,0x36,0x6C,0xD8,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xB0 */ 0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,
+/* 0xB1 */ 0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,
+/* 0xB2 */ 0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,
+/* 0xB3 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xB4 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xB5 */ 0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xB6 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xB7 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xB8 */ 0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xB9 */ 0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xBA */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xBB */ 0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xBC */ 0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xBD */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xBE */ 0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xBF */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xC0 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xC1 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xC2 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xC3 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xC4 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xC5 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xC6 */ 0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xC7 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xC8 */ 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xC9 */ 0x00,0x00,0x00,0x00,0x00,0x3F,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xCA */ 0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xCB */ 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xCC */ 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xCD */ 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xCE */ 0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xCF */ 0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xD0 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xD1 */ 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xD2 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xD3 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xD4 */ 0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xD5 */ 0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xD6 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xD7 */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* 0xD8 */ 0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xD9 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xDA */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xDB */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+/* 0xDC */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+/* 0xDD */ 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,
+/* 0xDE */ 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,
+/* 0xDF */ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xE0 */ 0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0xD8,0xD8,0xD8,0xDC,0x76,0x00,0x00,0x00,0x00,
+/* 0xE1 */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xFC,0xC6,0xC6,0xC6,0xC6,0xDC,0xC0,0xC0,0x00,0x00,
+/* 0xE2 */ 0x00,0x00,0xFE,0xC6,0xC6,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,
+/* 0xE3 */ 0x00,0x00,0x00,0x00,0x00,0xFE,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,
+/* 0xE4 */ 0x00,0x00,0xFE,0xC6,0x60,0x30,0x18,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00,
+/* 0xE5 */ 0x00,0x00,0x00,0x00,0x00,0x7E,0xD8,0xD8,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,
+/* 0xE6 */ 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0xC0,0x00,0x00,0x00,
+/* 0xE7 */ 0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/* 0xE8 */ 0x00,0x00,0x7E,0x18,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00,
+/* 0xE9 */ 0x00,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00,
+/* 0xEA */ 0x00,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0x6C,0x6C,0x6C,0x6C,0xEE,0x00,0x00,0x00,0x00,
+/* 0xEB */ 0x00,0x00,0x1E,0x30,0x18,0x0C,0x3E,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,
+/* 0xEC */ 0x00,0x00,0x00,0x00,0x00,0x7E,0xDB,0xDB,0xDB,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xED */ 0x00,0x00,0x00,0x03,0x06,0x7E,0xDB,0xDB,0xF3,0x7E,0x60,0xC0,0x00,0x00,0x00,0x00,
+/* 0xEE */ 0x00,0x00,0x1C,0x30,0x60,0x60,0x7C,0x60,0x60,0x60,0x30,0x1C,0x00,0x00,0x00,0x00,
+/* 0xEF */ 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00,
+/* 0xF0 */ 0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,
+/* 0xF1 */ 0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,
+/* 0xF2 */ 0x00,0x00,0x00,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00,0x7E,0x00,0x00,0x00,0x00,
+/* 0xF3 */ 0x00,0x00,0x00,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00,0x7E,0x00,0x00,0x00,0x00,
+/* 0xF4 */ 0x00,0x0E,0x1B,0x1B,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* 0xF5 */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00,
+/* 0xF6 */ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x7E,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
+/* 0xF7 */ 0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xF8 */ 0x00,0x38,0x6C,0x6C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xF9 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xFA */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xFB */ 0x00,0x0F,0x0C,0x0C,0x0C,0x0C,0x0C,0xEC,0x6C,0x6C,0x3C,0x1C,0x00,0x00,0x00,0x00,
+/* 0xFC */ 0x00,0xD8,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xFD */ 0x00,0x70,0xD8,0x30,0x60,0xC8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* 0xFE */ 0x00,0x00,0x00,0x00,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x00,0x00,0x00,0x00,0x00,
+};
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/lzw.h linux/arch/ppc/boot/lzw.h
--- v2.1.15/linux/arch/ppc/boot/lzw.h	Thu Jan  1 02:00:00 1970
+++ linux/arch/ppc/boot/lzw.h	Wed Dec 18 10:49:52 1996
@@ -0,0 +1,42 @@
+/* lzw.h -- define the lzw functions.
+ * Copyright (C) 1992-1993 Jean-loup Gailly.
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ */
+
+#if !defined(OF) && defined(lint)
+#  include "gzip.h"
+#endif
+
+#ifndef BITS
+#  define BITS 16
+#endif
+#define INIT_BITS 9              /* Initial number of bits per code */
+
+#define	LZW_MAGIC  "\037\235"   /* Magic header for lzw files, 1F 9D */
+
+#define BIT_MASK    0x1f /* Mask for 'number of compression bits' */
+/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free.
+ * It's a pity that old uncompress does not check bit 0x20. That makes
+ * extension of the format actually undesirable because old compress
+ * would just crash on the new format instead of giving a meaningful
+ * error message. It does check the number of bits, but it's more
+ * helpful to say "unsupported format, get a new version" than
+ * "can only handle 16 bits".
+ */
+
+#define BLOCK_MODE  0x80
+/* Block compression: if table is full and compression rate is dropping,
+ * clear the dictionary.
+ */
+
+#define LZW_RESERVED 0x60 /* reserved bits */
+
+#define	CLEAR  256       /* flush the dictionary */
+#define FIRST  (CLEAR+1) /* first free entry */
+
+extern int maxbits;      /* max bits per code for LZW */
+extern int block_mode;   /* block compress mode -C compatible with 2.0 */
+
+extern void lzw    OF((int in, int out));
+extern void unlzw  OF((int in, int out));
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/misc.c linux/arch/ppc/boot/misc.c
--- v2.1.15/linux/arch/ppc/boot/misc.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/ppc/boot/misc.c	Wed Dec 18 10:49:52 1996
@@ -0,0 +1,762 @@
+/*
+ * misc.c
+ * 
+ * This is a collection of several routines from gzip-1.0.3 
+ * adapted for Linux.
+ *
+ * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
+ * puts by Nick Holloway 1993
+ *
+ * Adapted for PowerPC by Gary Thomas
+ */
+
+#include "gzip.h"
+#include "lzw.h"
+#include "asm/residual.h"
+
+RESIDUAL hold_residual;
+void dump_buf(unsigned char *p, int s);
+#define EOF -1
+
+DECLARE(uch, inbuf, INBUFSIZ);
+DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
+DECLARE(uch, window, WSIZE);
+
+unsigned outcnt;
+unsigned insize;
+unsigned inptr;
+
+extern char input_data[];
+extern int input_len;
+
+int input_ptr;
+
+int method, exit_code, part_nb, last_member;
+int test = 0;
+int force = 0;
+int verbose = 1;
+long bytes_in, bytes_out;
+
+char *output_data;
+unsigned long output_ptr;
+
+extern int end;
+long free_mem_ptr = (long)&end;
+
+int to_stdout = 0;
+int hard_math = 0;
+
+void (*work)(int inf, int outf);
+void makecrc(void);
+
+local int get_method(int);
+
+char *vidmem = (char *)0xC00B8000;
+int lines, cols;
+int orig_x, orig_y;
+
+void puts(const char *);
+
+void *malloc(int size)
+{
+	void *p;
+
+	if (size <0) error("Malloc error\n");
+	if (free_mem_ptr <= 0) error("Memory error\n");
+
+   while(1) {
+	free_mem_ptr = (free_mem_ptr + 3) & ~3;	/* Align */
+
+	p = (void *)free_mem_ptr;
+	free_mem_ptr += size;
+
+	/*
+  	 * The part of the compressed kernel which has already been expanded
+	 * is no longer needed. Therefore we can reuse it for malloc.
+	 * With bigger kernels, this is necessary.
+	 */
+          
+	if (free_mem_ptr < (long)&end) {
+		if (free_mem_ptr > (long)&input_data[input_ptr])
+			error("\nOut of memory\n");
+
+		return p;
+	}
+#if 0	
+	if (free_mem_ptr < 0x90000)
+#endif	
+	return p;
+	puts("large kernel, low 1M tight...");
+	free_mem_ptr = (long)input_data;
+	}
+}
+
+void free(void *where)
+{	/* Don't care */
+}
+
+static void clear_screen()
+{
+	int i, j;
+	for (i = 0;  i < lines;  i++) {
+	  for (j = 0;  j < cols;  j++) {
+	    vidmem[((i*cols)+j)*2] = ' ';
+	    vidmem[((i*cols)+j)*2+1] = 0x07;
+	  }
+	}
+}
+
+static void scroll()
+{
+	int i;
+
+	memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );
+	for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
+		vidmem[i] = ' ';
+}
+
+void puts(const char *s)
+{
+	int x,y;
+	char c;
+
+	x = orig_x;
+	y = orig_y;
+
+	while ( ( c = *s++ ) != '\0' ) {
+		if ( c == '\n' ) {
+			x = 0;
+			if ( ++y >= lines ) {
+				scroll();
+				y--;
+			}
+		} else {
+			vidmem [ ( x + cols * y ) * 2 ] = c; 
+			if ( ++x >= cols ) {
+				x = 0;
+				if ( ++y >= lines ) {
+					scroll();
+					y--;
+				}
+			}
+		}
+	}
+
+	orig_x = x;
+	orig_y = y;
+}
+
+__ptr_t memset(__ptr_t s, int c, size_t n)
+{
+	int i;
+	char *ss = (char*)s;
+
+	for (i=0;i<n;i++) ss[i] = c;
+}
+
+__ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src,
+			    size_t __n)
+{
+	int i;
+	char *d = (char *)__dest, *s = (char *)__src;
+
+	for (i=0;i<__n;i++) d[i] = s[i];
+}
+
+int memcmp(__ptr_t __dest, __const __ptr_t __src,
+			    size_t __n)
+{
+	int i;
+	char *d = (char *)__dest, *s = (char *)__src;
+
+	for (i=0;i<__n;i++, d++, s++)
+	{
+		if (*d != *s)
+		{
+			return (*s - *d);
+		}
+	}
+	return (0);
+}
+
+extern ulg crc_32_tab[];   /* crc table, defined below */
+
+/* ===========================================================================
+ * Run a set of bytes through the crc shift register.  If s is a NULL
+ * pointer, then initialize the crc shift register contents instead.
+ * Return the current crc in either case.
+ */
+ulg updcrc(s, n)
+    uch *s;                 /* pointer to bytes to pump through */
+    unsigned n;             /* number of bytes in s[] */
+{
+    register ulg c;         /* temporary variable */
+
+    static ulg crc = (ulg)0xffffffffL; /* shift register contents */
+
+    if (s == NULL) {
+	c = 0xffffffffL;
+    } else {
+	c = crc;
+	while (n--) {
+	    c = crc_32_tab[((int)c ^ (*s++)) & 0xff] ^ (c >> 8);
+	}
+    }
+    crc = c;
+    return c ^ 0xffffffffL;       /* (instead of ~c for 64-bit machines) */
+}
+
+/* ===========================================================================
+ * Clear input and output buffers
+ */
+void clear_bufs()
+{
+    outcnt = 0;
+    insize = inptr = 0;
+    bytes_in = bytes_out = 0L;
+}
+
+/* ===========================================================================
+ * Fill the input buffer. This is called only when the buffer is empty
+ * and at least one byte is really needed.
+ */
+int fill_inbuf()
+{
+    int len, i;
+
+    /* Read as much as possible */
+puts("*");    
+    insize = 0;
+    do {
+	len = INBUFSIZ-insize;
+	if (len > (input_len-input_ptr+1)) len=input_len-input_ptr+1;
+        if (len == 0 || len == EOF) break;
+
+        for (i=0;i<len;i++) inbuf[insize+i] = input_data[input_ptr+i];
+	insize += len;
+	input_ptr += len;
+    } while (insize < INBUFSIZ);
+
+    if (insize == 0) {
+	error("unable to fill buffer\n");
+    }
+    bytes_in += (ulg)insize;
+    inptr = 1;
+    return inbuf[0];
+}
+
+/* ===========================================================================
+ * Write the output window window[0..outcnt-1] and update crc and bytes_out.
+ * (Used for the decompressed data only.)
+ */
+void flush_window()
+{
+    if (outcnt == 0) return;
+    updcrc(window, outcnt);
+
+    memcpy(&output_data[output_ptr], (char *)window, outcnt);
+
+    bytes_out += (ulg)outcnt;
+    output_ptr += (ulg)outcnt;
+    outcnt = 0;
+}
+
+/*
+ * Code to compute the CRC-32 table. Borrowed from 
+ * gzip-1.0.3/makecrc.c.
+ */
+
+ulg crc_32_tab[256];
+
+void
+makecrc(void)
+{
+/* Not copyrighted 1990 Mark Adler	*/
+
+  unsigned long c;      /* crc shift register */
+  unsigned long e;      /* polynomial exclusive-or pattern */
+  int i;                /* counter for all possible eight bit values */
+  int k;                /* byte being shifted into crc apparatus */
+
+  /* terms of polynomial defining this crc (except x^32): */
+  static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+  /* Make exclusive-or pattern from polynomial */
+  e = 0;
+  for (i = 0; i < sizeof(p)/sizeof(int); i++)
+    e |= 1L << (31 - p[i]);
+
+  crc_32_tab[0] = 0;
+
+  for (i = 1; i < 256; i++)
+  {
+    c = 0;
+    for (k = i | 256; k != 1; k >>= 1)
+    {
+      c = c & 1 ? (c >> 1) ^ e : c >> 1;
+      if (k & 1)
+        c ^= e;
+    }
+    crc_32_tab[i] = c;
+  }
+}
+
+void error(char *x)
+{
+	puts("\n\n");
+	puts(x);
+	puts("\n\n -- System halted");
+
+	while(1);	/* Halt */
+}
+
+unsigned long
+decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, RESIDUAL *residual)
+{
+  unsigned long TotalMemory;
+  output_data = (char *)0x0;	/* Points to 0 */
+  lines = 25;
+  cols = 80;
+  orig_x = 0;
+  orig_y = 24;
+
+  
+  /* Turn off MMU.  Since we are mapped 1-1, this is OK. */
+  flush_instruction_cache();
+  _put_HID0(_get_HID0() & ~0x0000C000);
+  _put_MSR(_get_MSR() & ~0x0030);
+
+  vga_init(0xC0000000);
+  clear_screen();
+
+  output_ptr = 0;
+
+  exit_code = 0;
+  test = 0;
+  input_ptr = 0;
+  part_nb = 0;
+
+  clear_bufs();
+  makecrc();
+
+  puts("Loaded at ");  puthex(load_addr);  puts(", ");  puthex(num_words);  puts(" words");
+  puts(", cksum = ");  puthex(cksum);  puts("\n");
+  if (residual) {
+    _bcopy(residual, &hold_residual, sizeof(hold_residual));
+    puts("Residual data at ");  puthex(residual);  puts("\n");
+    show_residual_data(residual);
+    TotalMemory = residual->TotalMemory;
+  } else {
+    TotalMemory = 0x01000000;
+  }
+
+  puts("Uncompressing Linux...");
+
+  method = get_method(0);
+
+  work(0, 0);
+
+  puts("done.\n");
+  puts("Now booting the kernel\n");
+  /*return (TotalMemory);*/              /* Later this can be a pointer to saved residual data */
+  return &hold_residual;
+}
+
+show_residual_data(RESIDUAL *res)
+{
+  puts("Residual data: ");  puthex(res->ResidualLength);  puts(" bytes\n");
+  puts("Total memory: ");  puthex(res->TotalMemory);  puts("\n");
+#if 0
+  puts("Residual structure = ");  puthex(sizeof(*res));  puts(" bytes\n");
+  dump_buf(&hold_residual, 32);
+  dump_buf(res, 32);
+#endif
+}
+
+#if 0
+verify_ram()
+{
+  unsigned long loc;
+  puts("Clearing memory:");
+  for (loc = 0;  loc <= 0x400000;  loc += 4);
+  {
+    *(unsigned long *)loc = 0x0;
+  }
+  for (loc = 0;  loc <= 0x400000;  loc += 4);
+  {
+    if (*(unsigned long *)loc != 0x0)
+      {
+	puts(" - failed at ");
+	puthex(loc);
+	puts(": ");
+	puthex(*(unsigned long *)loc);
+	while (1);
+      }
+  }
+  puts("0");
+  for (loc = 0;  loc <= 0x400000;  loc += 4);
+  {
+    *(unsigned long *)loc = 0xFFFFFFFF;
+  }
+  for (loc = 0;  loc <= 0x400000;  loc += 4);
+  {
+    if (*(unsigned long *)loc != 0xFFFFFFFF)
+      {
+	puts(" - failed at ");
+	puthex(loc);
+	puts(": ");
+	puthex(*(unsigned long *)loc);
+	while (1);
+      }
+  }
+  puts("1");
+  for (loc = 0;  loc <= 0x400000;  loc += 4);
+  {
+    *(unsigned long *)loc = loc;
+  }
+  for (loc = 0;  loc <= 0x400000;  loc += 4);
+  {
+    if (*(unsigned long *)loc != loc)
+      {
+	puts(" - failed at ");
+	puthex(loc);
+	puts(": ");
+	puthex(*(unsigned long *)loc);
+	while (1);
+      }
+  }
+  puts("?");
+  for (loc = 0;  loc <= 0x400000;  loc += 4);
+  {
+    *(unsigned long *)loc = 0xDEADB00B;
+  }
+  for (loc = 0;  loc <= 0x400000;  loc += 4);
+  {
+    if (*(unsigned long *)loc != 0xDEADB00B)
+      {
+	puts(" - failed at ");
+	puthex(loc);
+	puts(": ");
+	puthex(*(unsigned long *)loc);
+	while (1);
+      }
+  }
+  puts(">");
+  for (loc = 0;  loc <= 0x400000;  loc += 4);
+  {
+    *(unsigned long *)loc = 0x0;
+  }
+  for (loc = 0;  loc <= 0x400000;  loc += 4);
+  {
+    if (*(unsigned long *)loc != 0x0)
+      {
+	puts(" - failed at ");
+	puthex(loc);
+	puts(": ");
+	puthex(*(unsigned long *)loc);
+	while (1);
+      }
+  }
+  puts("\n");
+}
+
+do_cksum(unsigned long loc)
+{
+  unsigned int ptr, cksum;
+  puts("cksum[");  puthex(loc);  puts("] = ");  
+  cksum = 0;
+  for (ptr = loc;  ptr < (loc+0x40000);  ptr += 4)
+    {
+      cksum ^= *(unsigned long *)ptr;
+    }
+  puthex(cksum);  puts("  ");
+  cksum = 0;  loc += 0x40000;
+  for (ptr = loc;  ptr < (loc+0x40000);  ptr += 4)
+    {
+      cksum ^= *(unsigned long *)ptr;
+    }
+  puthex(cksum);  puts("  ");
+  cksum = 0;  loc += 0x40000;
+  for (ptr = loc;  ptr < (loc+0x40000);  ptr += 4)
+    {
+      cksum ^= *(unsigned long *)ptr;
+    }
+  puthex(cksum);  puts("  ");
+  cksum = 0;  loc += 0x40000;
+  for (ptr = loc;  ptr < (loc+0x40000);  ptr += 4)
+    {
+      cksum ^= *(unsigned long *)ptr;
+    }
+  puthex(cksum);  puts("\n");
+}
+
+cksum_data()
+{
+  unsigned int *ptr, len, cksum, cnt;
+  cksum = cnt = 0;
+  ptr = input_data;
+  puts("Checksums: ");
+  for (len = 0;  len < input_len;  len += 4) {
+    cksum ^= *ptr++;
+    if (len && ((len & 0x0FFF) == 0)) {
+      if (cnt == 0) {
+	puts("\n  [");
+	puthex(ptr-1);
+	puts("] ");
+      }
+      puthex(cksum);
+      if (++cnt == 6) {
+	cnt = 0;
+      } else {
+	puts(" ");
+      }
+    }
+  }
+  puts("\n");
+  puts("Data cksum = ");  puthex(cksum);  puts("\n");
+}
+
+cksum_text()
+{
+  extern int start, etext;
+  unsigned int *ptr, len, text_len, cksum, cnt;
+  cksum = cnt = 0;
+  ptr = &start;
+  text_len = (unsigned int)&etext - (unsigned int)&start;
+  puts("Checksums: ");
+  for (len = 0;  len < text_len;  len += 4) {
+    cksum ^= *ptr++;
+    if (len && ((len & 0x0FFF) == 0)) {
+      if (cnt == 0) {
+	puts("\n  [");
+	puthex(ptr-1);
+	puts("] ");
+      }
+      puthex(cksum);
+      if (++cnt == 6) {
+	cnt = 0;
+      } else {
+	puts(" ");
+      }
+    }
+  }
+  puts("\n");
+  puts("TEXT cksum = ");  puthex(cksum);  puts("\n");
+}
+
+verify_data(unsigned long load_addr)
+{
+  extern int start, etext;
+  unsigned int *orig_ptr, *copy_ptr, len, errors;
+  errors = 0;
+  copy_ptr = input_data;
+  orig_ptr = (unsigned int *)(load_addr + ((unsigned int)input_data - (unsigned int)&start));
+  for (len = 0;  len < input_len;  len += 4) {
+    if (*copy_ptr++ != *orig_ptr++) {
+      errors++;
+    }    
+  }
+  copy_ptr = input_data;
+  orig_ptr = (unsigned int *)(load_addr + ((unsigned int)input_data - (unsigned int)&start));
+  for (len = 0;  len < input_len;  len += 4) {
+    if (*copy_ptr++ != *orig_ptr++) {
+      dump_buf(copy_ptr-1, 128);
+      dump_buf(orig_ptr-1, 128);
+      puts("Total errors = ");  puthex(errors*4);  puts("\n");
+      while (1) ;
+    }    
+  }
+}
+
+test_data(unsigned long load_addr)
+{
+  extern int start, etext;
+  unsigned int *orig_ptr, *copy_ptr, len, errors;
+  errors = 0;
+  copy_ptr = input_data;
+  orig_ptr = (unsigned int *)(load_addr + ((unsigned int)input_data - (unsigned int)&start));
+  for (len = 0;  len < input_len;  len += 4) {
+    if (*copy_ptr++ != *orig_ptr++) {
+      errors++;
+    }    
+  }
+  return (errors == 0);
+}
+#endif
+
+void puthex(unsigned long val)
+{
+  unsigned char buf[10];
+  int i;
+  for (i = 7;  i >= 0;  i--)
+    {
+      buf[i] = "0123456789ABCDEF"[val & 0x0F];
+      val >>= 4;
+    }
+  buf[8] = '\0';
+  puts(buf);
+}
+
+#if 1
+void puthex2(unsigned long val)
+{
+  unsigned char buf[4];
+  int i;
+  for (i = 1;  i >= 0;  i--)
+    {
+      buf[i] = "0123456789ABCDEF"[val & 0x0F];
+      val >>= 4;
+    }
+  buf[2] = '\0';
+  puts(buf);
+}
+
+void dump_buf(unsigned char *p, int s)
+{
+   int i, c;
+   if ((unsigned int)s > (unsigned int)p)
+   {
+   	s = (unsigned int)s - (unsigned int)p;
+   }
+   while (s > 0)
+   {
+      puthex(p);  puts(": ");
+      for (i = 0;  i < 16;  i++)
+      {
+         if (i < s)
+         {
+            puthex2(p[i] & 0xFF);
+         } else
+         {
+            puts("  ");
+         }
+         if ((i % 2) == 1) puts(" ");
+         if ((i % 8) == 7) puts(" ");
+      }
+      puts(" |");
+      for (i = 0;  i < 16;  i++)
+      {
+	 char buf[2];
+         if (i < s)
+         {
+            c = p[i] & 0xFF;
+            if ((c < 0x20) || (c >= 0x7F)) c = '.';
+         } else
+         {
+            c = ' ';
+         }
+	 buf[0] = c;  buf[1] = '\0';
+         puts(buf);
+      }
+      puts("|\n");
+      s -= 16;
+      p += 16;
+   }
+}
+#endif
+
+/*
+ * PCI/ISA I/O support
+ */
+
+volatile unsigned char *ISA_io  = (unsigned char *)0x80000000;
+volatile unsigned char *ISA_mem = (unsigned char *)0xC0000000;
+
+void
+outb(int port, char val)
+{
+	/* Ensure I/O operations complete */
+	__asm__ volatile("eieio");
+	ISA_io[port] = val;
+}
+
+unsigned char
+inb(int port)
+{
+	/* Ensure I/O operations complete */
+	__asm__ volatile("eieio");
+	return (ISA_io[port]);
+}
+
+unsigned long
+local_to_PCI(unsigned long addr)
+{
+	return ((addr & 0x7FFFFFFF) | 0x80000000);
+}
+
+/* ========================================================================
+ * Check the magic number of the input file and update ofname if an
+ * original name was given and to_stdout is not set.
+ * Return the compression method, -1 for error, -2 for warning.
+ * Set inptr to the offset of the next byte to be processed.
+ * This function may be called repeatedly for an input file consisting
+ * of several contiguous gzip'ed members.
+ * IN assertions: there is at least one remaining compressed member.
+ *   If the member is a zip file, it must be the only one.
+ */
+local int get_method(in)
+    int in;        /* input file descriptor */
+{
+    uch flags;
+    char magic[2]; /* magic header */
+
+    magic[0] = (char)get_byte();
+    magic[1] = (char)get_byte();
+
+    method = -1;                 /* unknown yet */
+    part_nb++;                   /* number of parts in gzip file */
+    last_member = 0;
+    /* assume multiple members in gzip file except for record oriented I/O */
+
+    if (memcmp(magic, GZIP_MAGIC, 2) == 0
+        || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) {
+
+	work = unzip;
+	method = (int)get_byte();
+	flags  = (uch)get_byte();
+	if ((flags & ENCRYPTED) != 0)
+	    error("Input is encrypted\n");
+	if ((flags & CONTINUATION) != 0)
+	       error("Multi part input\n");
+	if ((flags & RESERVED) != 0) {
+	    error("Input has invalid flags\n");
+	    exit_code = ERROR;
+	    if (force <= 1) return -1;
+	}
+	(ulg)get_byte();	/* Get timestamp */
+	((ulg)get_byte()) << 8;
+	((ulg)get_byte()) << 16;
+	((ulg)get_byte()) << 24;
+
+	(void)get_byte();  /* Ignore extra flags for the moment */
+	(void)get_byte();  /* Ignore OS type for the moment */
+
+	if ((flags & EXTRA_FIELD) != 0) {
+	    unsigned len = (unsigned)get_byte();
+	    len |= ((unsigned)get_byte())<<8;
+	    while (len--) (void)get_byte();
+	}
+
+	/* Get original file name if it was truncated */
+	if ((flags & ORIG_NAME) != 0) {
+	    if (to_stdout || part_nb > 1) {
+		/* Discard the old name */
+		while (get_byte() != 0) /* null */ ;
+	    } else {
+	    } /* to_stdout */
+	} /* orig_name */
+
+	/* Discard file comment if any */
+	if ((flags & COMMENT) != 0) {
+	    while (get_byte() != 0) /* null */ ;
+	}
+    } else
+	error("unknown compression method");
+    return method;
+}
+
+void
+_bcopy(char *src, char *dst, int len)
+{
+  while (len--) *dst++ = *src++;
+}
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/mk_type41.c linux/arch/ppc/boot/mk_type41.c
--- v2.1.15/linux/arch/ppc/boot/mk_type41.c	Tue May 28 07:46:04 1996
+++ linux/arch/ppc/boot/mk_type41.c	Wed Dec 18 10:49:52 1996
@@ -8,7 +8,11 @@
 
 #include <stdio.h>
 #include <errno.h>
+#ifdef linux
+#include <asm/stat.h>
+#else
 #include <sys/stat.h>
+#endif
 
 _LE(long val, unsigned char *le)
 {
@@ -187,7 +191,7 @@
      *     (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette)
      *   - unlike the above sector numbers, the beginning sector is zero-based!
      */
-#if 0     
+#if 0
     pe->beginning_sector  = LeDword(1);
 #else
     /* This has to be 0 on the PowerStack? */   
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/mkprep.c linux/arch/ppc/boot/mkprep.c
--- v2.1.15/linux/arch/ppc/boot/mkprep.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/ppc/boot/mkprep.c	Wed Dec 18 10:49:52 1996
@@ -0,0 +1,139 @@
+/*
+ * This program will make a type 0x41 load image from an
+ * executable file.  Note:  assumes that the executable has
+ * already been "flattened" by 'mkboot'.
+ *
+ * usage: mk_type41 flat-file image
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#ifdef linux
+#include <asm/stat.h>
+#else
+#include <sys/stat.h>
+#endif
+#include <asm/byteorder.h> /* use same as kernel -- Cort */
+
+typedef unsigned long dword_t;
+typedef unsigned short word_t;
+typedef unsigned char byte_t;
+typedef byte_t block_t[512];
+typedef byte_t page_t[4096];
+
+_LE(long val, unsigned char *le)
+{
+	le[0] = val;
+	le[1] = val >> 8;
+	le[2] = val >> 16;
+	le[3] = val >> 24;
+}
+
+/*
+ * Partition table entry
+ *  - from the PReP spec
+ */
+typedef struct partition_entry {
+    byte_t	boot_indicator;
+    byte_t	starting_head;
+    byte_t	starting_sector;
+    byte_t	starting_cylinder;
+
+    byte_t	system_indicator;
+    byte_t	ending_head;
+    byte_t	ending_sector;
+    byte_t	ending_cylinder;
+
+    dword_t	beginning_sector;
+    dword_t	number_of_sectors;
+} partition_entry_t;
+
+#define BootActive	0x80
+#define SystemPrep	0x41
+
+
+int main(int argc, char *argv[])
+{
+  struct stat info;
+  char buf[8192];
+  int in_fd, out_fd,len;
+  unsigned char block[512];
+  partition_entry_t *pe = (partition_entry_t *)&block[0x1BE];
+  dword_t *entry  = (dword_t *)&block[0x50];
+  dword_t *length = (dword_t *)&block[0x51];
+  
+  if (argc != 3)
+    {
+      fprintf(stderr, "usage: mk_type41 <boot-file> <image>\n");
+      exit(1);
+    }
+  if ((in_fd = open(argv[1], 0)) < 0)
+    {
+      exit(2);
+    }
+  if ((out_fd = creat(argv[2], 0755)) < 0)
+    {
+      exit(2);
+    }
+
+  bzero( &block, sizeof block );
+    
+
+  /*
+   * Magic marker
+   */
+  block[510] = 0x55;
+  block[511] = 0xAA;
+  
+  pe->boot_indicator   = BootActive;
+  pe->system_indicator = SystemPrep;
+    pe->starting_head     = 0;		/* zero-based			     */
+    pe->starting_sector   = 2;		/* one-based			     */
+    pe->starting_cylinder = 0;		/* zero-based			     */
+
+    pe->ending_head       = 1;		/* assumes two heads		     */
+    pe->ending_sector     = 18;		/* assumes 18 sectors/track	     */
+    pe->ending_cylinder   = 79;		/* assumes 80 cylinders/diskette     */
+
+#if 0
+#if 0    
+  pe->beginning_sector  = LeDword(1);
+#else
+  /* This has to be 0 on the PowerStack? */
+  pe->beginning_sector  = LeDword(0);
+#endif
+  pe->number_of_sectors = LeDword(2*18*80-1);
+#endif
+  
+  if (fstat(in_fd, &info) < 0)
+    {
+      exit(4);
+    }
+  /* begin execution at 0x400 */
+  _LE(0x400,(unsigned char *)entry);
+  _LE(info.st_size+0x400,length);
+  
+  lseek( out_fd, 0, 0 );
+  /* write out 1st block */
+  write( out_fd, block, sizeof block );
+  
+  /* copy image */
+#if 1 
+	lseek(out_fd, 0x400, 0);
+	while ((len = read(in_fd, buf, sizeof(buf))) > 0)
+	{
+		if (write(out_fd, buf, len) != len)
+		{
+			exit(5);
+		}
+	}
+	if (len < 0)
+	{
+		exit(6);
+	}
+	close(in_fd);
+	close(out_fd);
+#endif	
+  return 0;
+}
+
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/piggyback.c linux/arch/ppc/boot/piggyback.c
--- v2.1.15/linux/arch/ppc/boot/piggyback.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/ppc/boot/piggyback.c	Wed Dec 18 10:49:52 1996
@@ -0,0 +1,64 @@
+#include <stdio.h>
+
+extern long ce_exec_config[];
+
+main(int argc, char *argv[])
+{
+	int i, cnt, pos, len;
+	unsigned int cksum, val;
+	unsigned char *lp;
+	unsigned char buf[8192];
+	if (argc != 1)
+	{
+		fprintf(stderr, "usage: %s <in-file >out-file\n", argv[0]);
+		exit(1);
+	}
+	fprintf(stdout, "#\n");
+	fprintf(stdout, "# Miscellaneous data structures:\n");
+	fprintf(stdout, "# WARNING - this file is automatically generated!\n");
+	fprintf(stdout, "#\n");
+	fprintf(stdout, "\n");
+	fprintf(stdout, "\t.data\n");
+	fprintf(stdout, "\t.globl input_data\n");
+	fprintf(stdout, "input_data:\n");
+	pos = 0;
+	cksum = 0;
+	while ((len = read(0, buf, sizeof(buf))) > 0)
+	{
+		cnt = 0;
+		lp = (unsigned char *)buf;
+		len = (len + 3) & ~3;  /* Round up to longwords */
+		for (i = 0;  i < len;  i += 4)
+		{
+			if (cnt == 0)
+			{
+				fprintf(stdout, "\t.long\t");
+			}
+			fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
+			val = *(unsigned long *)lp;
+			cksum ^= val;
+			lp += 4;
+			if (++cnt == 4)
+			{
+				cnt = 0;
+				fprintf(stdout, " # %x \n", pos+i-12);
+				fflush(stdout);
+			} else
+			{
+				fprintf(stdout, ",");
+			}
+		}
+		if (cnt)
+		{
+			fprintf(stdout, "0\n");
+		}
+		pos += len;
+	}
+	fprintf(stdout, "\t.globl input_len\n");
+	fprintf(stdout, "input_len:\t.long\t0x%x\n", pos);
+	fflush(stdout);
+	fclose(stdout);
+	fprintf(stderr, "cksum = %x\n", cksum);
+	exit(0);
+}
+
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/unzip.c linux/arch/ppc/boot/unzip.c
--- v2.1.15/linux/arch/ppc/boot/unzip.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/ppc/boot/unzip.c	Wed Dec 18 10:49:52 1996
@@ -0,0 +1,182 @@
+/* unzip.c -- decompress files in gzip or pkzip format.
+ * Copyright (C) 1992-1993 Jean-loup Gailly
+ *
+ * Adapted for Linux booting by Hannu Savolainen 1993
+ *
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License, see the file COPYING.
+ *
+ * The code in this file is derived from the file funzip.c written
+ * and put in the public domain by Mark Adler.
+ */
+
+/*
+   This version can extract files in gzip or pkzip format.
+   For the latter, only the first entry is extracted, and it has to be
+   either deflated or stored.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: unzip.c,v 0.9 1993/02/10 16:07:22 jloup Exp $";
+#endif
+
+#include "gzip.h"
+#include "crypt.h"
+
+#include <stdio.h>
+
+/* PKZIP header definitions */
+#define LOCSIG 0x04034b50L      /* four-byte lead-in (lsb first) */
+#define LOCFLG 6                /* offset of bit flag */
+#define  CRPFLG 1               /*  bit for encrypted entry */
+#define  EXTFLG 8               /*  bit for extended local header */
+#define LOCHOW 8                /* offset of compression method */
+#define LOCTIM 10               /* file mod time (for decryption) */
+#define LOCCRC 14               /* offset of crc */
+#define LOCSIZ 18               /* offset of compressed size */
+#define LOCLEN 22               /* offset of uncompressed length */
+#define LOCFIL 26               /* offset of file name field length */
+#define LOCEXT 28               /* offset of extra field length */
+#define LOCHDR 30               /* size of local header, including sig */
+#define EXTHDR 16               /* size of extended local header, inc sig */
+
+
+/* Globals */
+
+int decrypt;      /* flag to turn on decryption */
+char *key;        /* not used--needed to link crypt.c */
+int pkzip = 0;    /* set for a pkzip file */
+int extended = 0; /* set if extended local header */
+
+/* ===========================================================================
+ * Check zip file and advance inptr to the start of the compressed data.
+ * Get ofname from the local header if necessary.
+ */
+int check_zipfile(in)
+    int in;   /* input file descriptors */
+{
+    uch *h = inbuf + inptr; /* first local header */
+
+    /* ifd = in; */
+
+    /* Check validity of local header, and skip name and extra fields */
+    inptr += LOCHDR + SH(h + LOCFIL) + SH(h + LOCEXT);
+
+    if (inptr > insize || LG(h) != LOCSIG) {
+	error("input not a zip");
+    }
+    method = h[LOCHOW];
+    if (method != STORED && method != DEFLATED) {
+	error("first entry not deflated or stored--can't extract");
+    }
+
+    /* If entry encrypted, decrypt and validate encryption header */
+    if ((decrypt = h[LOCFLG] & CRPFLG) != 0) {
+	error("encrypted file\n");
+	exit_code = ERROR;
+	return -1;
+    }
+
+    /* Save flags for unzip() */
+    extended = (h[LOCFLG] & EXTFLG) != 0;
+    pkzip = 1;
+
+    /* Get ofname and time stamp from local header (to be done) */
+    return 0;
+}
+
+/* ===========================================================================
+ * Unzip in to out.  This routine works on both gzip and pkzip files.
+ *
+ * IN assertions: the buffer inbuf contains already the beginning of
+ *   the compressed data, from offsets inptr to insize-1 included.
+ *   The magic header has already been checked. The output buffer is cleared.
+ */
+void unzip(in, out)
+    int in, out;   /* input and output file descriptors */
+{
+    ulg orig_crc = 0;       /* original crc */
+    ulg orig_len = 0;       /* original uncompressed length */
+    ulg _crc, _len;
+    int n;
+    uch buf[EXTHDR];        /* extended local header */
+
+    /* ifd = in;
+    ofd = out; */
+
+    updcrc(NULL, 0);           /* initialize crc */
+
+    if (pkzip && !extended) {  /* crc and length at the end otherwise */
+	orig_crc = LG(inbuf + LOCCRC);
+	orig_len = LG(inbuf + LOCLEN);
+    }
+
+    /* Decompress */
+    if (method == DEFLATED)  {
+
+	int res = inflate();
+
+	if (res == 3) {
+	    error("out of memory");
+	} else if (res != 0) {
+	    error("invalid compressed format");
+	}
+
+    } else if (pkzip && method == STORED) {
+
+	register ulg n = LG(inbuf + LOCLEN);
+
+	if (n != LG(inbuf + LOCSIZ) - (decrypt ? RAND_HEAD_LEN : 0)) {
+
+	    error("length mismatch");
+	}
+	while (n--) {
+	    uch c = (uch)get_byte();
+#ifdef CRYPT
+	    if (decrypt) zdecode(c);
+#endif
+	    if (!test) put_char(c);
+	}
+    } else {
+	error("internal error, invalid method");
+    }
+
+    /* Get the crc and original length */
+    if (!pkzip) {
+        /* crc32  (see algorithm.doc)
+	 * uncompressed input size modulo 2^32
+         */
+	for (n = 0; n < 8; n++) {
+	    buf[n] = (uch)get_byte(); /* may cause an error if EOF */
+	}
+	orig_crc = LG(buf);
+	orig_len = LG(buf+4);
+
+    } else if (extended) {  /* If extended header, check it */
+	/* signature - 4bytes: 0x50 0x4b 0x07 0x08
+	 * CRC-32 value
+         * compressed size 4-bytes
+         * uncompressed size 4-bytes
+	 */
+	for (n = 0; n < EXTHDR; n++) {
+	    buf[n] = (uch)get_byte(); /* may cause an error if EOF */
+	}
+	orig_crc = LG(buf+4);
+	orig_len = LG(buf+12);
+    }
+
+    /* Validate decompression */
+    if (orig_crc != (_crc = updcrc(outbuf, 0))) {
+      extern char input_data[];
+	error("crc error");
+    }
+    if (orig_len != bytes_out) {
+	error("length error");
+    }
+
+    /* Check if there are more entries in a pkzip file */
+    if (pkzip && inptr + 4 < insize && LG(inbuf+inptr) == LOCSIG) {
+	    error("zip file has more than one entry");
+    }
+    extended = pkzip = 0; /* for next file */
+}
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/boot/vreset.c linux/arch/ppc/boot/vreset.c
--- v2.1.15/linux/arch/ppc/boot/vreset.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/ppc/boot/vreset.c	Wed Dec 18 10:49:52 1996
@@ -0,0 +1,164 @@
+/*
+ * vreset.c
+ *
+ * Initialize the VGA control registers to 80x25 text mode.
+ *
+ * Adapted from a program by:
+ *                                      Steve Sellgren
+ *                                      San Francisco Indigo Company
+ *                                      sfindigo!sellgren@uunet.uu.net
+ */
+ 
+unsigned char CRTC[24] = {
+    0x5F, 0x4F, 0x50, 0x82, 0x55, 0x81, 0xBF, 0x1F, 
+    0x00, 0x4F, 0x0D, 0x0E, 0x00, 0x00, 0x00, 0x00, /*0x07, 0x80, */
+    0x9C, 0xAE, 0x8F, 0x28, 0x1F, 0x96, 0xB9, 0xA3};
+unsigned char SEQ[5] = {0x3, 0x0, 0x3, 0x0, 0x2};
+unsigned char GC[9] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0xE, 0x0, 0xFF};
+unsigned char AC[21] = {
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 
+    0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 
+    0x0C, 0x00, 0x0F, 0x08, 0x00};
+
+#include "iso_font.h"
+
+static const unsigned char color_LUT[] =
+   {
+	0x00, 0x00, 0x00, /* 0 - black */
+	0x00, 0x00, 0x2A, /* 1 - blue */
+	0x00, 0x2A, 0x00, /* 2 - green */
+	0x00, 0x2A, 0x2A, /* 3 - cyan */
+	0x2A, 0x00, 0x00, /* 4 - red */
+	0x2A, 0x00, 0x2A, /* 5 - magenta */
+	0x2A, 0x2A, 0x00, /* 6 - brown */
+	0x2A, 0x2A, 0x2A, /* 7 - white */
+	0x00, 0x00, 0x15, /* 8 - gray */
+	0x00, 0x00, 0x3F, /* 9 - light blue */
+	0x00, 0x2A, 0x15, /* 10 - light green */
+	0x00, 0x2A, 0x3F, /* 11 - light cyan */
+	0x2A, 0x00, 0x15, /* 12 - light red */
+	0x2A, 0x00, 0x3F, /* 13 - light magenta */
+	0x2A, 0x2A, 0x15, /* 14 - yellow */
+	0x2A, 0x2A, 0x3F, /* 15 - bright white */
+   };
+
+static inline
+outw(int port, unsigned short val)
+{
+	outb(port, val >> 8);
+	outb(port+1, val);
+}
+ 
+vga_init(unsigned char *ISA_mem)
+{
+  int i, j;
+  int value;
+  unsigned char *font_page = (unsigned char *) &ISA_mem[0xA0000];
+
+  /* See if VGA already in TEXT mode - exit if so! */
+  outb(0x3CE, 0x06);
+  if ((inb(0x3CF) & 0x01) == 0) return;
+    
+  /* From the S3 manual */
+  outb(0x46E8, 0x10);  /* Put into setup mode */
+  outb(0x3C3, 0x10);
+  outb(0x102, 0x01);   /* Enable registers */
+  outb(0x46E8, 0x08);  /* Enable video */
+  outb(0x3C3, 0x08);
+  outb(0x4AE8, 0x00);
+
+  outb(0x42E8, 0x80);  /* Reset graphics engine? */
+
+  outb(0x3D4, 0x38);  /* Unlock all registers */
+  outb(0x3D5, 0x48);
+  outb(0x3D4, 0x39);
+  outb(0x3D5, 0xA5);
+  outb(0x3D4, 0x40);
+  outb(0x3D5, inb(0x3D5)|0x01);
+  outb(0x3D4, 0x33);
+  outb(0x3D5, inb(0x3D5)&~0x52);
+  outb(0x3D4, 0x35);
+  outb(0x3D5, inb(0x3D5)&~0x30);
+  outb(0x3D4, 0x3A);
+  outb(0x3D5, 0x00);
+  outb(0x3D4, 0x53);
+  outb(0x3D5, 0x00);
+  outb(0x3D4, 0x31);
+  outb(0x3D5, inb(0x3D5)&~0x4B);
+  outb(0x3D4, 0x58);
+  outb(0x3D5, 0);
+
+  outb(0x3D4, 0x54);
+  outb(0x3D5, 0x38);
+  outb(0x3D4, 0x60);
+  outb(0x3D5, 0x07);
+  outb(0x3D4, 0x61);
+  outb(0x3D5, 0x80);
+  outb(0x3D4, 0x62);
+  outb(0x3D5, 0xA1);
+  outb(0x3D4, 0x69);  /* High order bits for cursor address */
+  outb(0x3D5, 0);
+  
+  outb(0x3D4, 0x32);
+  outb(0x3D5, inb(0x3D5)&~0x10);
+
+  outb(0x3C2, 0x67);
+
+  /* Initialize DAC */
+  outb(0x3C6,0xFF);
+  inb(0x3C7);
+  outb(0x3C8,0x00);
+  inb(0x3C7);
+  for (i=0; i<sizeof(color_LUT); i++) {
+    outb(0x3C9, color_LUT[i]);
+  }
+  for (i; i<768; i += 3) {
+    outb(0x3C9, 0x3F); /* White? */
+    outb(0x3C9, 0x3F); /* White? */
+    outb(0x3C9, 0x3F); /* White? */
+  }
+
+  /* Load font */
+  NOP(inb(0x3DA));  /* Reset Address/Data FlipFlop for Attribute ctlr */
+  outb(0x3C0,0x30); outb(0x3C0, 0x01); /* graphics mode */
+  outw(0x3C4, 0x0001);    /* reset sequencer */
+  outw(0x3C4, 0x0204);    /* write to plane 2 */
+  outw(0x3C4, 0x0407);    /* enable plane graphics */
+  outw(0x3C4, 0x0003);    /* reset sequencer */
+  outw(0x3CE, 0x0402);    /* read plane 2 */
+  outw(0x3CE, 0x0500);    /* write mode 0, read mode 0 */
+  outw(0x3CE, 0x0600);    /* set graphics */
+  for (i = 0;  i < sizeof(font);  i += 16) {
+    for (j = 0;  j < 16;  j++) {
+      font_page[(2*i)+j] = font[i+j];
+    }
+  }
+
+  for (i = 0; i < 24; i++) {
+    outb(0x3D4, i);
+    outb(0x3D5, CRTC[i]);
+  }
+  for (i = 0; i < 5; i++) {
+    outb(0x3C4, i);
+    outb(0x3C5, SEQ[i]);
+  }
+  for (i = 0; i < 9; i++) {
+    outb(0x3CE, i);
+    outb(0x3CF, GC[i]);
+  }
+  value = inb(0x3DA);         /* reset flip-flop */
+  for (i = 0; i < 16; i++) {
+    outb(0x3C0, i);
+    outb(0x3C0, AC[i]);
+  }
+  for (i = 16; i < 21; i++) {
+    outb(0x3C0, i | 0x20);
+    outb(0x3C0, AC[i]);
+  }
+  outb(0x3C2, 0x23);
+}
+
+static int
+NOP(int x)
+{
+}
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- v2.1.15/linux/arch/ppc/kernel/Makefile	Mon Jul  8 11:27:42 1996
+++ linux/arch/ppc/kernel/Makefile	Wed Dec 18 10:49:52 1996
@@ -14,10 +14,8 @@
 .c.o:
 	$(CC) $(CFLAGS) -c $<
 .S.s:
-#	$(CPP) $(CFLAGS) -D__ASSEMBLY__ -traditional $< -o $*.s
 	$(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
 .S.o:
-#	$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
 	$(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
 	$(AS) $(ASFLAGS) -o $*.o $*.s
 	rm $*.s
@@ -25,39 +23,24 @@
 HOST_CC = gcc
 
 OBJS  = misc.o setup.o port_io.o irq.o pci.o traps.o stubs.o process.o \
-	signal.o ksyms.o time.o syscalls.o \
-	support.o ptrace.o # ramdisk_drvr.o
+	signal.o ksyms.o time.o syscalls.o usercpy.o\
+	support.o ptrace.o 
 
-all: head.o kernel.o #no_ramdisk.o ramdisk.o
+all: head.o kernel.o
 
 head.o: head.s
 head.s: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h
 
 ppc_defs.h: mk_defs
-#	simppc mk_defs -- $@
 	mk_defs $@
 
-#no_ramdisk.o: no_ramdisk.S
-
-#ramdisk.o: ramdisk.image mk_ramdisk
-#	mk_ramdisk ramdisk.image $*.s
-#	$(AS) -o $@ $*.s
-#	rm $*.s
-
-#mk_ramdisk: mk_ramdisk.c
-#	${HOST_CC} -o mk_ramdisk mk_ramdisk.c	
-
-mk_defs: mk_defs.c $(TOPDIR)/include/asm/mmu.h $(TOPDIR)/include/asm/processor.h $(TOPDIR)/include/asm/pgtable.h $(TOPDIR)/include/asm/ptrace.h
-#	cc.ppc ${CFLAGS} -o mk_defs -T ld.script-user -Ttext 0x1000 mk_defs.c
-	gcc.ppc ${CFLAGS} -o mk_defs mk_defs.c
+mk_defs: mk_defs.c
+	$(HOSTCC) $(CFLAGSINC) -Wl,-static ${CFLAGS} -o mk_defs mk_defs.c
 
 
 kernel.o: $(OBJS)
 	$(LD) -r -o kernel.o $(OBJS)
 	sync
-
-#mkboot: mkboot.c
-#	${HOST_CC} -o $@ -Iinclude mkboot.c
 
 dep:
 	$(CPP) -M *.c > .depend
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- v2.1.15/linux/arch/ppc/kernel/head.S	Mon Jul  8 11:27:42 1996
+++ linux/arch/ppc/kernel/head.S	Wed Dec 18 10:49:52 1996
@@ -1,16 +1,15 @@
 #include "ppc_asm.tmpl"
 #include "ppc_defs.h"
 #include <linux/errno.h>
-#define NEWMM
+#include <linux/sys.h>
+#include <asm/ppc_machine.h>
+	
+#define NEWMM 1
 #define SYNC() \
 	isync; \
 	sync
 
-/* #define TLB_STATS */
-
-/* Keep track of low-level exceptions - rather crude, but informative */  
 #define STATS
-
 /*
  * Increment a [64 bit] statistic counter
  * Uses R2, R3
@@ -40,179 +39,9 @@
 	mtspr	XER,r0; \
 	stw	r3,0(r2)
 
-/* These macros can be used to generate very raw traces of low-level */
-/* operations (where printf, etc. can't help).  All they provide is */
-/* some after-the-fact documentation of what took place.  Since [in */
-/* most instances] they have no registers to work with, they use the */
-/* hardware "special" registers SPRx for storage.  Because of this, */
-/* defining more than one of them simultaneously will yield incorrect */
-/* results and a non-functional system.  Note: the trick here is to */
-/* gather some data without disturbing anything - Heisenberg are you watching? */
-
-/* CAUTION! Don't turn on more than one of these at once! */	
-/* #define DO_TRAP_TRACE   */ 
-/* #define DO_TLB_TRACE    */
-/* #define DO_RFI_TRACE    */
-
-#ifdef DO_RFI_TRACE
-#define DO_RFI_TRACE_UNMAPPED(mark) \
-	mtspr	SPR0,r1; \
-	mtspr	SPR1,r2; \
-	mtspr	SPR2,r3; \
-	mfcr	r3; \
-	mtspr	SPR3,r3; \
-	lis	r1,_RFI_ptr@h; \
-	ori	r1,r1,_RFI_ptr@l; \
-	lis	r3,0xF000; \
-	andc	r1,r1,r3; \
-	lwz	r1,0(r1); \
-	andc	r1,r1,r3; \
-	subi	r1,r1,4; \
-	lis	r2,(mark>>16); \
-	ori	r2,r2,(mark&0xFFFF); \
-	stwu	r2,4(r1); \
-	mfspr	r2,SRR0; \
-	stwu	r2,4(r1); \
-	mfspr	r2,SRR1; \
-	stwu	r2,4(r1); \
-	addi	r1,r1,4+4; \
-	lis	r2,_RFI_ptr@h; \
-	ori	r2,r2,_RFI_ptr@l; \
-	andc	r2,r2,r3; \
-	stw	r1,0(r2); \
-	mfspr	r3,SPR3; \
-	mtcrf	0xFF,r3; \
-	mfspr	r1,SPR0; \
-	mfspr	r2,SPR1; \
-	mfspr	r3,SPR2
-#define DO_RFI_TRACE_MAPPED(mark) \
-	mtspr	SPR0,r1; \
-	mtspr	SPR1,r2; \
-	mtspr	SPR2,r3; \
-	mfcr	r3; \
-	mtspr	SPR3,r3; \
-	lis	r1,_RFI_ptr@h; \
-	ori	r1,r1,_RFI_ptr@l; \
-	lwz	r1,0(r1); \
-	lis	r3,0x9000; \
-	or	r1,r1,r3; \
-	subi	r1,r1,4; \
-	lis	r2,(mark>>16); \
-	ori	r2,r2,(mark&0xFFFF); \
-	stwu	r2,4(r1); \
-	mfspr	r2,SRR0; \
-	stwu	r2,4(r1); \
-	mfspr	r2,SRR1; \
-	stwu	r2,4(r1); \
-	addi	r1,r1,4+4; \
-	lis	r2,_RFI_ptr@h; \
-	ori	r2,r2,_RFI_ptr@l; \
-	stw	r1,0(r2); \
-	mfspr	r3,SPR3; \
-	mtcrf	0xFF,r3; \
-	mfspr	r1,SPR0; \
-	mfspr	r2,SPR1; \
-	mfspr	r3,SPR2
-#else
 #define DO_RFI_TRACE_UNMAPPED(mark)
 #define DO_RFI_TRACE_MAPPED(mark)
-#endif
 
-#ifdef DO_TRAP_TRACE
-#define DEFAULT_TRAP(offset) \
-	mtspr	SPR0,r1; \
-	mtspr	SPR1,r2; \
-	mtspr	SPR2,r3; \
-	lis	r1,_TRAP_ptr@h; \
-	ori	r1,r1,_TRAP_ptr@l; \
-	lis	r3,0xF000; \
-	andc	r1,r1,r3; \
-	lwz	r1,0(r1); \
-	andc	r1,r1,r3; \
-	subi	r1,r1,4; \
-	lis	r2,0xCACA; \
-	ori	r2,r2,offset; \
-	stwu	r2,4(r1); \
-	mfspr	r2,SRR0; \
-	stwu	r2,4(r1); \
-	mfspr	r2,SRR1; \
-	stwu	r2,4(r1); \
-	mfspr	r2,SPR0; \
-	stwu	r2,4(r1); \
-	addi	r1,r1,4; \
-	lis	r2,_TRAP_ptr@h; \
-	ori	r2,r2,_TRAP_ptr@l; \
-	andc	r2,r2,r3; \
-	stw	r1,0(r2); \
-	mfspr	r1,SPR0; \
-	mfspr	r2,SPR1; \
-	mfspr	r3,SPR2; \
-	li	r13,0; \
-	ori	r13,r13,HID0_ICE; \
-	mtspr	HID0,r13; \
-	lis	r13,0xFFF00000>>16; \
-	ori	r13,r13,offset; \
-	mtlr	r13; \
-	b	hang
-#define TRACE_TRAP(offset) \
-	mtspr	SPR0,r1; \
-	mtspr	SPR1,r2; \
-	mtspr	SPR2,r3; \
-	mfcr	r3; \
-	mtspr	SPR3,r3; \
-	lis	r1,_TRAP_ptr@h; \
-	ori	r1,r1,_TRAP_ptr@l; \
-	lis	r3,0xF000; \
-	andc	r1,r1,r3; \
-	lwz	r1,0(r1); \
-	andc	r1,r1,r3; \
-	subi	r1,r1,4; \
-	lis	r2,0xCABB; \
-	ori	r2,r2,offset; \
-	stwu	r2,4(r1); \
-	dcbst	0,r1; \
-	mfspr	r2,SRR0; \
-	stwu	r2,4(r1); \
-	dcbst	0,r1; \
-	mfspr	r2,SRR1; \
-	stwu	r2,4(r1); \
-	dcbst	0,r1; \
-	li	r2,offset; \
-	cmpi	0,r2,0x0C00; \
-	beq	01f; \
-	cmpi	0,r2,0x0300; \
-	beq	00f; \
-	cmpi	0,r2,0x0400; \
-	beq	00f; \
-	mfspr	r2,SPR0; \
-	b	02f; \
-00:	mfspr	r2,DAR; \
-	b	02f; \
-01:	mr	r2,r0; \
-02:	stwu	r2,4(r1); \
-	dcbst	0,r1; \
-	addi	r1,r1,4; \
-	mflr	r2; \
-	stw	r2,0(r1); \
-	bl	check_trace; \
-	lwz	r2,0(r1); \
-	mtlr	r2; \
-02:	lis	r2,_TRAP_ptr@h; \
-	ori	r2,r2,_TRAP_ptr@l; \
-	oris	r1,r1,0x9000; \
-	cmp	0,r1,r2; \
-	bne	00f; \
-	lis	r1,_TRAP_TRACE@h; \
-	ori	r1,r1,_TRAP_TRACE@l; \
-00:	lis	r3,0xF000; \
-	andc	r2,r2,r3; \
-	stw	r1,0(r2); \
-	mfspr	r1,SPR0; \
-	mfspr	r2,SPR1; \
-	mfspr	r3,SPR3; \
-	mtcrf	0xFF,r3; \
-	mfspr	r3,SPR2
-#else
 #define DEFAULT_TRAP(offset) \
 	li	r13,0; \
 	ori	r13,r13,HID0_ICE; \
@@ -222,7 +51,6 @@
 	mtlr	r13; \
 	blr
 #define TRACE_TRAP(offset)	
-#endif
 
 #define DATA_CACHE_OFF() \
 	mfspr	r2,HID0; \
@@ -246,27 +74,147 @@
 	bdnz	0b
 
 /* Validate kernel stack - check for overflow */
-#define CHECK_STACK()
+/* all regs are considered scratch since the C function will stomp them */
+#define CHECK_STACK() \
+	/*lis	r3,current_set@ha; \
+	lwz	r3,current_set@l(r3); \
+	bl	_EXTERN(check_stack)*/
+#if 0
 #define _CHECK_STACK() \
 	mtspr	SPR0,r3; \
+	mtspr	SPR1,r4;    /* use r3,4 as scratch */ \
 	lis	r2,current_set@ha; \
 	lwz	r2,current_set@l(r2); \
 	lwz	r2,KERNEL_STACK_PAGE(r2); \
-	lis	r3,sys_stack@h; \
+	/* if kernel stack is sys_stack skip check */ \
+	/*lis	r3,sys_stack@h; \
 	ori	r3,r3,sys_stack@l; \
-	cmpl	0,r1,r3; \
-	ble	02f; \
-	li	r3,0x0FFF; \
+	cmpl	0,r1,r3;*/ \
+	/* check for STACK_MAGIC on kernel stack page */ \
+	lis	r3, 0xdead; /* STACK_MAGIC */ \
+	ori	r3,r3,0xbeef; \
+	lwz	r4,0(r2);      /* get *kernel_stack_page */ \
+	cmpl	0,r4,r3; \
+	bne	01f; \
+	/* check that ksp is > kernel page */ \
+	/*li	r3,0x0FFF; \
 	andc	r2,r2,r3; \
 	andc	r3,r1,r3; \
 	cmp	0,r3,r2; \
-	beq	02f; \
-	mr	r3,r1; \
+	beq	02f;*/ \
+	/* check that ksp and kernel stack page are on same page */ \
+	cmp	0,r1,r2; \
+	bge	02f; \
+01:	mr	r6,r1; /* setup info for call to bad_stack() */ \
+	mr	r5,r2; \
 	bl	_EXTERN(bad_stack); \
-02:	mfspr	r3,SPR0
+02:	mfspr	r4,SPR1; \
+	mfspr	r3,SPR0
+#endif
+	
+/* save fp regs if fp is used */
+/* assumes that r1 contains ptr to regs of task and r2 is scratch 
+	  -- Cort  */
+#define SAVE_FP_REGS() \
+       	/* check if fp has been used by checking msr_fp bit */ \
+	lwz	r2,_MSR(r1);  \
+	andi.	r2,r2,MSR_FP; \
+	bne	00f; \
+	/* floating point has been used -- save fp regs */ \
+	lis	r2,current_set@h; \
+	ori	r2,r2,current_set@l; \
+	addi	r2,r2,TSS; \
+	/*mr	r2,r1;*/ \
+	stfd	fr0,TSS_FPR0(r2); \
+	stfd	fr1,TSS_FPR1(r2); \
+	stfd	fr2,TSS_FPR2(r2); \
+	stfd	fr3,TSS_FPR3(r2); \
+	stfd	fr4,TSS_FPR4(r2); \
+	stfd	fr5,TSS_FPR5(r2); \
+	stfd	fr6,TSS_FPR6(r2); \
+	stfd	fr7,TSS_FPR7(r2); \
+	stfd	fr8,TSS_FPR8(r2); \
+	stfd	fr9,TSS_FPR9(r2); \
+	stfd	fr10,TSS_FPR10(r2); \
+	stfd	fr11,TSS_FPR11(r2); \
+	stfd	fr12,TSS_FPR12(r2); \
+	stfd	fr13,TSS_FPR13(r2); \
+	stfd	fr14,TSS_FPR14(r2); \
+	stfd	fr15,TSS_FPR15(r2); \
+	stfd	fr16,TSS_FPR16(r2); \
+	stfd	fr17,TSS_FPR17(r2); \
+	stfd	fr18,TSS_FPR18(r2); \
+	stfd	fr19,TSS_FPR19(r2); \
+	stfd	fr20,TSS_FPR20(r2); \
+	stfd	fr21,TSS_FPR21(r2); \
+	stfd	fr22,TSS_FPR22(r2); \
+	stfd	fr23,TSS_FPR23(r2); \
+	stfd	fr24,TSS_FPR24(r2); \
+	stfd	fr25,TSS_FPR25(r2); \
+	stfd	fr26,TSS_FPR26(r2); \
+	stfd	fr27,TSS_FPR27(r2); \
+	stfd	fr28,TSS_FPR28(r2); \
+	stfd	fr29,TSS_FPR29(r2); \
+	stfd	fr30,TSS_FPR30(r2); \
+	stfd	fr31,TSS_FPR31(r2); \
+00:
+
 
-/* Save all registers on kernel stack during an exception */	
-#define SAVE_REGS(mark) \
+/* restores fp regs if fp has been used -- always restores fpscr */
+/* assumes that r1 contains ptr to regs, r2 is scratch and srr1 holds
+   what will become the msr when this process executes 	-- Cort*/
+#define RESTORE_FP_REGS(mark) \
+	/* check if restoring from _switch() */ \
+	li	r2, mark; \
+	cmpi	0,r2,0x0f0f; \
+	bne	00f; /* only need to save if called from _switch() with 0x0f0f */\
+       	/* check if fp has been used by checking msr_fp bit */ \
+	/* srr1 contains msr */ \
+	mfspr	r2,SRR1; \
+	andi.	r2,r2,MSR_FP; \
+	bne	00f; \
+	/* floating point has been used -- restore fp regs */ \
+	/* Hey, Rocky!  Watch me pull fp regs from my stack! */ \
+	lis	r2,current_set@h; \
+	ori	r2,r2,current_set@l; \
+	addi	r2,r2,TSS; \
+	/*mr	r2,r1;*/\
+	lfd	fr0,TSS_FPR0(r2); \
+	lfd	fr1,TSS_FPR1(r2); \
+	lfd	fr2,TSS_FPR2(r2); \
+	lfd	fr3,TSS_FPR3(r2); \
+	lfd	fr4,TSS_FPR4(r2); \
+	lfd	fr5,TSS_FPR5(r2); \
+	lfd	fr6,TSS_FPR6(r2); \
+	lfd	fr7,TSS_FPR7(r2); \
+	lfd	fr8,TSS_FPR8(r2); \
+	lfd	fr9,TSS_FPR9(r2); \
+	lfd	fr10,TSS_FPR10(r2); \
+	lfd	fr11,TSS_FPR11(r2); \
+	lfd	fr12,TSS_FPR12(r2); \
+	lfd	fr13,TSS_FPR13(r2); \
+	lfd	fr14,TSS_FPR14(r2); \
+	lfd	fr15,TSS_FPR15(r2); \
+	lfd	fr16,TSS_FPR16(r2); \
+	lfd	fr17,TSS_FPR17(r2); \
+	lfd	fr18,TSS_FPR18(r2); \
+	lfd	fr19,TSS_FPR19(r2); \
+	lfd	fr20,TSS_FPR20(r2); \
+	lfd	fr21,TSS_FPR21(r2); \
+	lfd	fr22,TSS_FPR22(r2); \
+	lfd	fr23,TSS_FPR23(r2); \
+	lfd	fr24,TSS_FPR24(r2); \
+	lfd	fr25,TSS_FPR25(r2); \
+	lfd	fr26,TSS_FPR26(r2); \
+	lfd	fr27,TSS_FPR27(r2); \
+	lfd	fr28,TSS_FPR28(r2); \
+	lfd	fr29,TSS_FPR29(r2); \
+	lfd	fr30,TSS_FPR30(r2); \
+	lfd	fr31,TSS_FPR31(r2); \
+00:
+
+/* save all registers */
+#define SAVE_ALL_REGS(mark) \
 	subi	r1,r1,INT_FRAME_SIZE;	/* Make room for frame */ \
 	stmw	r3,GPR3(r1);	/* Save R3..R31 */ \
 	stw	r3,ORIG_GPR3(r1); \
@@ -287,10 +235,6 @@
 	stw	r2,_CCR(r1); \
 	mfspr	r2,XER; \
 	stw	r2,_XER(r1); \
-	stfd	fr0,FPR0(r1); \
-	stfd	fr1,FPR1(r1); \
-	stfd	fr2,FPR2(r1); \
-	stfd	fr3,FPR3(r1); \
 	mffs	fr0; \
 	stfd	fr0,FPCSR(r1); \
 	lis	r2,_break_lwarx@h; \
@@ -304,9 +248,11 @@
 	li	r2,0; \
 	stw	r2,RESULT(r1)
 
+
+/* save registers clobbered by a page fault handler */
 #define SAVE_PAGE_FAULT_REGS(offset) \
 	mfspr	r2,DAR; \
-	stw	r2,_DAR(r1); \
+ 	stw	r2,_DAR(r1); \
 	mfspr	r2,DSISR; \
 	stw	r2,_DSISR(r1); \
 	mfspr	r2,PVR;			/* Check for 603/603e */ \
@@ -328,7 +274,7 @@
 	mfspr	r2,DCMP; \
 	stw	r2,_DCMP(r1); \
 24:	
-	
+
 #define SAVE_INT_REGS(mark) \
 	mtspr	SPR0,r1;	/* Save current stack pointer */ \
 	mtspr	SPR1,r2;	/* Scratch */ \
@@ -375,7 +321,7 @@
 	mtspr	SRR1,r2; \
 	SYNC(); \
 	rfi; \
-20:	SAVE_REGS(mark); \
+20:	SAVE_ALL_REGS(mark); \
 	CHECK_STACK()
 
 #define RETURN_FROM_INT(mark) \
@@ -412,7 +358,10 @@
 	bl	_EXTERN(flush_instruction_cache); */ \
 05:	lis	r3,current_set@ha;	/* need to save kernel stack pointer */ \
 	lwz	r3,current_set@l(r3); \
-	addi	r4,r1,INT_FRAME_SIZE;	/* size of frame */ \
+	/*addi	r4,r1,INT_FRAME_SIZE*/;	/* size of frame */ \
+	lwz	r4, KERNEL_STACK_PAGE(r3); \
+	addi	r4,r4,KERNEL_STACK_SIZE; /* reset stack pointer to top of stack page */ \
+	/* stack isn't 0'd so show_task():sched.c shows highwater of stack */ \
 	stw	r4,TSS+KSP(r3); \
 	lwz	r4,STATE(r3);	/* If state != 0, can't run */ \
 	cmpi	0,r4,0; \
@@ -442,20 +391,18 @@
 	mtlr	r2; \
 	lwz	r2,_XER(r1); \
 	mtspr	XER,r2; \
-	lwz	r2,_CCR(r1); \
-	mtcrf	0xFF,r2; \
 	lfd	fr0,FPCSR(r1); \
 	mtfsf	0xFF,fr0; \
-	lfd	fr0,FPR0(r1); \
-	lfd	fr1,FPR1(r1); \
-	lfd	fr2,FPR2(r1); \
-	lfd	fr3,FPR3(r1); \
+	RESTORE_FP_REGS(mark) ; \
+	lwz	r2,_CCR(r1); \
+	mtcrf	0xFF,r2; \
 	lwz	r0,GPR0(r1); \
 	lwz	r2,GPR2(r1); \
 	lwz	r1,GPR1(r1); \
 	SYNC(); \
 	rfi
 
+	
 _TEXT()
 /*
  * This code may be executed by a bootstrap process.  If so, the
@@ -578,35 +525,6 @@
 /* Note: It is *unsafe* to use the TRACE TRAP macro here since there */
 /* could be a 'trace' in progress when the TLB miss occurs.          */
 /* TRACE_TRAP(0x1000) */
-#ifdef TLB_STATS
-	lis	r2,DataLoadTLB_trace_ptr@h
-	ori	r2,r2,DataLoadTLB_trace_ptr@l
-	lis	r3,0xF000
-	andc	r2,r2,r3
-	lwz	r1,0(r2)
-	andc	r1,r1,r3
-	li	r0,0x1000
-	stw	r0,0(r1)
-	mftbu	r0
-	stw	r0,4(r1)
-	mftb	r0
-	stw	r0,8(r1)
-	mfspr	r0,IMISS
-	mfspr	r3,SRR1
-	extrwi	r3,r3,1,14
-	or	r0,r0,r3
-	stw	r0,12(r1)
-	addi	r1,r1,16
-	mfcr	r0
-	cmpl	0,r1,r2
-	blt	00f
-	lis	r1,DataLoadTLB_trace_buf@h
-	ori	r1,r1,DataLoadTLB_trace_buf@l
-	lis	r3,0xF000
-	andc	r1,r1,r3
-00:	mtcrf	0xFF,r0
-	stw	r1,0(r2)
-#endif	
 	b	InstructionTLBMiss
 
 /*
@@ -614,41 +532,6 @@
  */
 _ORG(0x1100)
 /* TRACE_TRAP(0x1100) */
-#ifdef TLB_STATS
-	lis	r2,DataLoadTLB_trace_ptr@h
-	ori	r2,r2,DataLoadTLB_trace_ptr@l
-	lis	r3,0xF000
-	andc	r2,r2,r3
-	lwz	r1,0(r2)
-	andc	r1,r1,r3
-	li	r0,0x1100
-	stw	r0,0(r1)
-	mftbu	r0
-	stw	r0,4(r1)
-	mftb	r0
-	stw	r0,8(r1)
-	mfspr	r0,DMISS
-	mfspr	r3,SRR1
-	extrwi	r3,r3,1,14
-	or	r0,r0,r3
-	stw	r0,12(r1)
-	addi	r1,r1,16
-	mfcr	r0
-	cmpl	0,r1,r2
-	blt	00f
-	lis	r1,DataLoadTLB_trace_buf@h
-	ori	r1,r1,DataLoadTLB_trace_buf@l
-	lis	r3,0xF000
-	andc	r1,r1,r3
-00:	mtcrf	0xFF,r0
-	stw	r1,0(r2)
-	.data
-DataLoadTLB_trace_buf:
-	.space	64*1024*4
-DataLoadTLB_trace_ptr:
-	.long	DataLoadTLB_trace_buf
-	.text
-#endif	
 	b	DataLoadTLBMiss
 
 /*
@@ -656,35 +539,6 @@
  */
 _ORG(0x1200)
 /* TRACE_TRAP(0x1200) */
-#ifdef TLB_STATS
-	lis	r2,DataLoadTLB_trace_ptr@h
-	ori	r2,r2,DataLoadTLB_trace_ptr@l
-	lis	r3,0xF000
-	andc	r2,r2,r3
-	lwz	r1,0(r2)
-	andc	r1,r1,r3
-	li	r0,0x1200
-	stw	r0,0(r1)
-	mftbu	r0
-	stw	r0,4(r1)
-	mftb	r0
-	stw	r0,8(r1)
-	mfspr	r0,DMISS
-	mfspr	r3,SRR1
-	extrwi	r3,r3,1,14
-	or	r0,r0,r3
-	stw	r0,12(r1)
-	addi	r1,r1,16
-	mfcr	r0
-	cmpl	0,r1,r2
-	blt	00f
-	lis	r1,DataLoadTLB_trace_buf@h
-	ori	r1,r1,DataLoadTLB_trace_buf@l
-	lis	r3,0xF000
-	andc	r1,r1,r3
-00:	mtcrf	0xFF,r0
-	stw	r1,0(r2)
-#endif	
 	b	DataStoreTLBMiss
 
 _ORG(0x1300)
@@ -718,16 +572,40 @@
 #endif
 
 
+/* changed to use r3 as residual pointer (as firmware does), that's all -- Cort */
 /*
  * Hardware reset [actually from bootstrap]
  * Initialize memory management & call secondary init
  * Registers initialized by bootstrap:
  *   R11: Start of command line string
  *   R12: End of command line string
+ *   R28: Residual data
+ *   R29: Total Memory Size
  *   R30: 'BeBx' if this is a BeBox
  */	
 Reset:
 	lis	r7,0xF000		/* To mask upper 4 bits */
+/* set pointer to residual data */
+	lis	r1,resptr@h
+	ori	r1,r1,resptr@l
+	andc	r1,r1,r7
+/* changed to use r3 as residual pointer (as firmware does) -- Cort */
+/* this is only a ptr, the actual data is copied in mmu_init */
+	stw	r3,0(r1)
+	
+/* Copy argument string */
+	li	r0,0		/* Null terminate string */
+	stb	r0,0(r12)
+	lis	r1,cmd_line@h
+	ori	r1,r1,cmd_line@l
+	andc	r1,r1,r7	/* No MMU yet - need unmapped address */
+	subi	r1,r1,1
+	subi	r11,r11,1
+00:	lbzu	r0,1(r11)
+	cmpi	0,r0,0
+	stbu	r0,1(r1)
+	bne	00b
+
 #define IS_BE_BOX	0x42654278	/* 'BeBx' */
 	lis	r1,isBeBox@h
 	ori	r1,r1,isBeBox@l
@@ -751,21 +629,19 @@
 	andc	r5,r5,r7		/* Tell CPU #1 where to go */
 00:	stw	r2,0(r1)
 	stw	r30,4(r1)
-/* Copy argument string */
-	li	r0,0		/* Null terminate string */
-	stb	r0,0(r12)
-	lis	r1,cmd_line@h
-	ori	r1,r1,cmd_line@l
-	andc	r1,r1,r7	/* No MMU yet - need unmapped address */
-	subi	r1,r1,1
-	subi	r11,r11,1
-00:	lbzu	r0,1(r11)
-	cmpi	0,r0,0
-	stbu	r0,1(r1)
-	bne	00b	
+	
+
+#if 0	
 	lis	r1,sys_stack@h
 	ori	r1,r1,sys_stack@l
+#else
+	lis	r1,init_kernel_stack@h
+	ori	r1,r1,init_kernel_stack@l
+#endif
+	addi	r1,r1,0x1000	/* top of stack */
+#if 0	
 	li	r2,0x0FFF	/* Mask stack address down to page boundary */
+#endif
 	andc	r1,r1,r2
 	subi	r1,r1,INT_FRAME_SIZE	/* Padding for first frame */
 	li	r2,0		/* TOC pointer for nanokernel */
@@ -782,6 +658,13 @@
 00:	stwu	r0,4(r3)
 	cmp	0,r3,r4
 	blt	00b
+#if 0	
+/* Save total memory size (passed from bootstrap) */
+	lis	r3,_TotalMemory@h
+	ori	r3,r3,_TotalMemory@l
+	andc	r3,r3,r7	/* make unmapped address */
+	stw	r29,0(r3)
+#endif	
 /* Initialize BAT registers */
 	lis	r3,BAT0@h
 	ori	r3,r3,BAT0@l
@@ -816,7 +699,7 @@
 	lwz	r0,4(r3)
 	mtspr	IBAT2L,r0
 	mtspr	DBAT2L,r0
-#if 0	
+#if 1
 	lis	r3,BAT3@h
 	ori	r3,r3,BAT3@l
 	andc	r3,r3,r7	/* make unmapped address */
@@ -837,7 +720,7 @@
 DO_RFI_TRACE_UNMAPPED(0xDEAD0000)	
 	SYNC
 	rfi				/* enables MMU */
-10:	bl	_EXTERN(MMU_init)	/* initialize MMU environment */
+10:    	bl	_EXTERN(MMU_init)	/* initialize MMU environment */
 DO_RFI_TRACE_MAPPED(0xDEAD0100)	
 /* Withdraw BAT2->RAM mapping */
 	lis	r7,0xF000		/* To mask upper 4 bits */
@@ -1017,14 +900,17 @@
  * Data Access exception
  */
 DataAccess:
-/*	TRACE_TRAP(0x0300) */
 	SAVE_INT_REGS(0x0300)
-	SAVE_PAGE_FAULT_REGS(0x0300)
-	BUMP(__Data_Page_Faults)
-	mr	r3,r1		/* Set pointer to saved regs */
+#if 1
+	mfspr	r3, DAR
+	mfspr	r4, DSISR
+	li	r5, 0		/* not a text fault */
+	mr	r6, r1
+	bl	_EXTERN(new_page_fault)
+#else
+	SAVE_PAGE_FAULT_REGS(0x0D00)	
+	mr	r3,r1
 	bl	_EXTERN(DataAccessException)
-#if 0
-	bl	_EXTERN(flush_instruction_cache)
 #endif	
 	RETURN_FROM_INT(0x0300)
 
@@ -1032,14 +918,17 @@
  * Instruction Access Exception
  */
 InstructionAccess:
-/*	TRACE_TRAP(0x0400) */
 	SAVE_INT_REGS(0x0400)
-	SAVE_PAGE_FAULT_REGS(0x0400)
-	BUMP(__Instruction_Page_Faults)
-	mr	r3,r1		/* Set pointer to saved regs */
+#if 1
+	mfspr	r3, SPR2 /* srr0 was saved here */
+	mfspr	r4, SPR3 /* srr1 was saved here */
+	li	r5, 1	 /* a text fault */
+	mr	r6, r1
+	bl	_EXTERN(new_page_fault)
+#else
+	SAVE_PAGE_FAULT_REGS(0x0D00)	
+	mr	r3,r1
 	bl	_EXTERN(InstructionAccessException)
-#if 0
-	bl	_EXTERN(flush_instruction_cache)
 #endif	
 	RETURN_FROM_INT(0x0400)
 
@@ -1090,17 +979,18 @@
  * Floating point [not available, etc]
  */
 FloatingPointCheck:	
-	TRACE_TRAP(0x0800)
 	SAVE_INT_REGS(0x0800)
 	mr	r3,r1		/* Set pointer to saved regs */
 	bl	_EXTERN(FloatingPointCheckException)
-	RETURN_FROM_INT(0x0200)
+	cmpi	0,r3,MSR_FP    /* check if fp was turned on by handler */
+	bne	00f
+	RETURN_FROM_INT(0x0f0f) /* 0xf0f tells to restore fp regs */
+00:	RETURN_FROM_INT(0x0200)
 
 /*
  * System Call exception
  */
 SystemCall:
-/*	TRACE_TRAP(0x0C00) */
 	SAVE_INT_REGS(0x0C00)
 	lwz	r2,_CCR(r1)	/* Clear SO bit in CR */
 	lis	r9,0x1000
@@ -1118,13 +1008,21 @@
 	lwz	r2,TASK_FLAGS(r2)
 	andi.	r2,r2,PF_TRACESYS
 	bne	50f
+	
 	lis	r2,sys_call_table@h
 	ori	r2,r2,sys_call_table@l
 	slwi	r0,r0,2
 	lwzx	r2,r2,r0	/* Fetch system call handler [ptr] */
+#if 1
+	cmpi	0,r2,0		/* make sure syscall handler not 0 */
+	beq	99f
+	cmpi	0,r0,NR_syscalls<<2 /* make sure syscallnum in bounds */
+	bgt	99f
+#endif	
 	mtlr	r2
 	mr	r9,r1
 	blrl			/* Call handler */
+	
 20:	stw	r3,RESULT(r1)	/* Save result */	
 	cmpi	0,r3,0
 	bge	30f
@@ -1136,10 +1034,6 @@
 	oris	r2,r2,0x1000
 	stw	r2,_CCR(r1)
 30:	stw	r3,GPR3(r1)	/* Update return value */
-#if 0
-	mr	r3,r1
-	bl	_EXTERN(trace_syscall)
-#endif
 	b	99f
 /* Traced system call support */
 50:	bl	_EXTERN(syscall_trace)
@@ -1171,14 +1065,6 @@
 60:	stw	r3,GPR3(r1)	/* Update return value */
 	bl	_EXTERN(syscall_trace)
 99:
-#if 0 /* This isn't needed here - already in RETURN_FROM_INT */
-	lis	r2,kernel_pages_are_copyback@ha
-	lwz	r2,kernel_pages_are_copyback@l(r2)
-	cmpi	0,r2,0
-	beq	00f
-	bl	_EXTERN(flush_instruction_cache)	/* Ensure cache coherency */
-00:
-#endif
 	RETURN_FROM_INT(0x0C00)
 
 /*
@@ -1186,36 +1072,6 @@
  */
 InstructionTLBMiss:
 	BUMP_UNMAPPED(__Instruction_TLB_Misses)
-#ifdef DO_TLB_TRACE
-	lis	r1,_TLB_ptr@h
-	ori	r1,r1,_TLB_ptr@l
-	lis	r2,0xF000
-	andc	r1,r1,r2
-	lwz	r1,0(r1)
-	andc	r1,r1,r2
-	subi	r1,r1,4
-	lis	r2,0xBEBE
-	ori	r2,r2,0x0100
-	stwu	r2,4(r1)
-	mfspr	r2,SRR0
-	stwu	r2,4(r1)
-	mfspr	r2,SRR1
-	stwu	r2,4(r1)
-	mfspr	r2,HASH1
-	stwu	r2,4(r1)
-	mfspr	r2,HASH2
-	stwu	r2,4(r1)
-	mfspr	r2,ICMP
-	stwu	r2,4(r1)
-	mfspr	r2,IMISS
-	stwu	r2,4(r1)
-	addi	r1,r1,4+(1*4)
-	lis	r3,_TLB_ptr@h
-	ori	r3,r3,_TLB_ptr@l
-	lis	r2,0xF000
-	andc	r3,r3,r2
-	stw	r1,0(r3)
-#endif	
 	mfctr	r0		/* Need to save this - CTR can't be touched! */
 	mfspr	r2,HASH1	/* Get PTE pointer */
 	mfspr	r3,ICMP		/* Partial item compare value */
@@ -1256,37 +1112,6 @@
  * Handle TLB miss for DATA Load operation
  */	
 DataLoadTLBMiss:
-	BUMP_UNMAPPED(__DataLoad_TLB_Misses)
-#ifdef DO_TLB_TRACE
-	lis	r1,_TLB_ptr@h
-	ori	r1,r1,_TLB_ptr@l
-	lis	r2,0xF000
-	andc	r1,r1,r2
-	lwz	r1,0(r1)
-	andc	r1,r1,r2
-	subi	r1,r1,4
-	lis	r2,0xBEBE
-	ori	r2,r2,0x0200
-	stwu	r2,4(r1)
-	mfspr	r2,SRR0
-	stwu	r2,4(r1)
-	mfspr	r2,SRR1
-	stwu	r2,4(r1)
-	mfspr	r2,HASH1
-	stwu	r2,4(r1)
-	mfspr	r2,HASH2
-	stwu	r2,4(r1)
-	mfspr	r2,DCMP
-	stwu	r2,4(r1)
-	mfspr	r2,DMISS
-	stwu	r2,4(r1)
-	addi	r1,r1,4+(1*4)
-	lis	r3,_TLB_ptr@h
-	ori	r3,r3,_TLB_ptr@l
-	lis	r2,0xF000
-	andc	r3,r3,r2
-	stw	r1,0(r3)
-#endif	
 	mfctr	r0		/* Need to save this - CTR can't be touched! */
 	mfspr	r2,HASH1	/* Get PTE pointer */
 	mfspr	r3,DCMP		/* Partial item compare value */
@@ -1325,36 +1150,6 @@
  */
 DataStoreTLBMiss:
 	BUMP_UNMAPPED(__DataStore_TLB_Misses)
-#ifdef DO_TLB_TRACE
-	lis	r1,_TLB_ptr@h
-	ori	r1,r1,_TLB_ptr@l
-	lis	r2,0xF000
-	andc	r1,r1,r2
-	lwz	r1,0(r1)
-	andc	r1,r1,r2
-	subi	r1,r1,4
-	lis	r2,0xBEBE
-	ori	r2,r2,0x0300
-	stwu	r2,4(r1)
-	mfspr	r2,SRR0
-	stwu	r2,4(r1)
-	mfspr	r2,SRR1
-	stwu	r2,4(r1)
-	mfspr	r2,HASH1
-	stwu	r2,4(r1)
-	mfspr	r2,HASH2
-	stwu	r2,4(r1)
-	mfspr	r2,DCMP
-	stwu	r2,4(r1)
-	mfspr	r2,DMISS
-	stwu	r2,4(r1)
-	addi	r1,r1,4+(1*4)
-	lis	r3,_TLB_ptr@h
-	ori	r3,r3,_TLB_ptr@l
-	lis	r2,0xF000
-	andc	r3,r3,r2
-	stw	r1,0(r3)
-#endif	
 	mfctr	r0		/* Need to save this - CTR can't be touched! */
 	mfspr	r2,HASH1	/* Get PTE pointer */
 	mfspr	r3,DCMP		/* Partial item compare value */
@@ -1531,7 +1326,7 @@
 	addi	r3,r3,CACHE_LINE_SIZE
 	bdnz	00b
 	blr
-	
+
 /*
  * This routine switches between two different tasks.  The process
  * state of one is saved on its kernel stack.  Then the state
@@ -1543,24 +1338,25 @@
  * of this code; either by coming in via the entry (_switch)
  * or via "fork" which must set up an environment equivalent
  * to the "_switch" path.  If you change this (or in particular, the
- * SAVE_REGS macro), you'll have to change the fork code also.
+ * SAVE_ALL_REGS macro), you'll have to change the fork code also.
  *
  * The code which creates the new task context is in 'copy_thread'
  * in arch/ppc/kernel/process.c
  */	
 _GLOBAL(_switch)
-	mtspr	SPR0,r1		/* SAVE_REGS prologue */
+	mtspr	SPR0,r1		/* SAVE_ALL_REGS prologue */
 	mtspr	SPR1,r2
 	mflr	r2		/* Return to switch caller */
 	mtspr	SPR2,r2
 	mfmsr	r2
 	mtspr	SPR3,r2
-	SAVE_REGS(0x0FF0)
+	SAVE_ALL_REGS(0x0FF0)
+	SAVE_FP_REGS()
+	CHECK_STACK()
 	SYNC()
 	stw	r1,KSP(r3)	/* Set old stack pointer */
 	BUMP(__Context_Switches)
 	lwz	r1,KSP(r4)	/* Load new stack pointer */
-	CHECK_STACK()
 	lwz	r0,MMU_SEG0(r4)
 	mtsr	SR0,r0
 	lwz	r0,MMU_SEG1(r4)
@@ -1577,6 +1373,8 @@
 	mtsr	SR6,r0
 	lwz	r0,MMU_SEG7(r4)
 	mtsr	SR7,r0
+#if 0
+	/* segs 8-15 are shared by everyone -- don't need to be changed */
 	lwz	r0,MMU_SEG8(r4)
 	mtsr	SR8,r0
 	lwz	r0,MMU_SEG9(r4)
@@ -1593,34 +1391,22 @@
 	mtsr	SR14,r0
 	lwz	r0,MMU_SEG15(r4)
 	mtsr	SR15,r0
+#endif
+	/* no need to invalidate tlb since each process has a distinct
+	   set of vsid's.	 -- Cort */
+#if 0	  
 	tlbia				/* Invalidate entire TLB */
 	BUMP(__TLBIAs)
-	bl	_EXTERN(flush_instruction_cache)
-#ifdef TLB_STATS
-/* TEMP */
-	lis	r2,DataLoadTLB_trace_ptr@h
-	ori	r2,r2,DataLoadTLB_trace_ptr@l
-	lis	r3,0x9000
-	lwz	r4,0(r2)
-	or	r4,r4,r3
-	li	r0,0
-	stw	r0,0(r4)
-	stw	r0,4(r4)
-	stw	r0,8(r4)
-	stw	r0,12(r4)
-	addi	r4,r4,4
-	cmpl	0,r4,r2
-	blt	00f
-	lis	r4,DataLoadTLB_trace_buf@h
-	ori	r4,r4,DataLoadTLB_trace_buf@l
-00:	stw	r4,0(r2)
-/* TEMP */	
-#endif
-#if 0
-	lwz	r2,_NIP(r1)	/* Force TLB/MMU hit */
-	lwz	r2,0(r2)
 #endif	
-	RETURN_FROM_INT(0xF000)
+	/* p5.2 603 users manual - with addr transl. enabled, 
+	   the memory access is performed under the control of 
+	   the page table entry.  I interpret this to mean that
+	   it is tagged with the vsid -- so no need to flush here
+	   since each process has a distinct set of vsid's.
+	   Of course, my intepretation may be wrong.
+	              -- Cort */
+	/*bl	_EXTERN(flush_instruction_cache)*/
+	RETURN_FROM_INT(0x0f0f)
 	
 
 /*
@@ -1629,50 +1415,16 @@
 _GLOBAL(__main)
 	blr
 
-#ifdef DO_TRAP_TRACE
-check_trace:
-	sync				/* Force all writes out */
-	lwz	r2,-8(r1)
-	andi.	r2,r2,MSR_PR
-	bne	99f
-	lwz	r2,-32(r1)
-	lwz	r3,-16(r1)
-	cmp	0,r2,r3
-	bne	99f
-	andi.	r2,r2,0x7FFF
-	cmpi	0,r2,0x0C00
-	bge	99f
-	lwz	r2,-32+4(r1)
-	lwz	r3,-16+4(r1)
-	cmp	0,r2,r3
-	bne	99f
-	lwz	r2,-32+8(r1)
-	lwz	r3,-16+8(r1)
-	cmp	0,r2,r3
-	bne	99f
-	lwz	r2,-32(r1)
-	lwz	r3,-16(r1)
-	cmp	0,r2,r3
-	bne	99f
-	andi.	r2,r2,0x7FFF
-	cmpi	0,r2,0x0600
-	beq	00f
-	lwz	r2,-32+12(r1)
-	lwz	r3,-16+12(r1)
-	cmp	0,r2,r3
-	bne	99f
-00:	li	r2,0x7653
-	stw	r2,0(r1)
-	b	00b
-99:	blr
-#endif	
-
 	.data
 	.globl	sdata
 sdata:
 	.space	2*4096
+
+#if 0
+_GLOBAL(sys_stack)
 sys_stack:
-	.space	2*4096
+	.space	4096
+#endif
 CPU1_stack:	
 
 	.globl	empty_zero_page
@@ -1689,32 +1441,40 @@
  */	
 	.globl	cmd_line
 cmd_line:
-	.space	512	
-
+	.space	512
+	
 #ifdef STATS	
 /*
  * Miscellaneous statistics - gathered just for performance info
  */
-
  	.globl	_INTR_stats
 _INTR_stats:
+	.globl __Instruction_TLB_Misses
 __Instruction_TLB_Misses:
 	.long	0,0	/* Instruction TLB misses */
+	.globl __DataLoad_TLB_Misses
 __DataLoad_TLB_Misses:
 	.long	0,0	/* Data [load] TLB misses */
+	.globl __DataStore_TLB_Misses
 __DataStore_TLB_Misses:
 	.long	0,0	/* Data [store] TLB misses */
+	.globl __Instruction_Page_Faults
 __Instruction_Page_Faults:	
 	.long	0,0	/* Instruction page faults */
+	.globl __Data_Page_Faults
 __Data_Page_Faults:	
 	.long	0,0	/* Data page faults */
+	.globl __Cache_Flushes
 __Cache_Flushes:	
 	.long	0,0	/* Explicit cache flushes */
+	.globl __Context_Switches
 __Context_Switches:	
 	.long	0,0	/* Context switches */
+	.globl __Hardware_Interrupts
 __Hardware_Interrupts:	
 	.long	0,0	/* I/O interrupts (disk, timer, etc) */
 	.globl	__TLBIAs
+	.globl __TLBIAs
 __TLBIAs:
 	.long	0,0	/* TLB cache forceably flushed */
 	.globl	__TLBIEs
@@ -1722,33 +1482,14 @@
 	.long	0,0	/* Specific TLB entry flushed */	
 #endif
 
+	.globl	_TotalMemory
+_TotalMemory:
+	.long	0,0	
+	
 /*
  * This location is used to break any outstanding "lock"s when
  * changing contexts.
  */
 _break_lwarx:	.long	0
-
-/*
- * Various trace buffers
- */	
-#ifdef DO_TRAP_TRACE
-	.data
-_TRAP_TRACE: .space	32*1024
-_TRAP_ptr:   .long	_TRAP_TRACE
-	.text
-#endif
-
-#ifdef DO_TLB_TRACE
-	.data
-_TLB_TRACE: .space	128*1024
-_TLB_ptr:   .long	_TLB_TRACE
-	.text
-#endif
-
-#ifdef DO_RFI_TRACE
-	.data
-_RFI_DATA: .space	128*1024
-_RFI_ptr:  .long	_RFI_DATA
-	.text	
-#endif
+	
 
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/include/elf/ChangeLog linux/arch/ppc/kernel/include/elf/ChangeLog
--- v2.1.15/linux/arch/ppc/kernel/include/elf/ChangeLog	Tue May 28 07:46:04 1996
+++ linux/arch/ppc/kernel/include/elf/ChangeLog	Thu Jan  1 02:00:00 1970
@@ -1,155 +0,0 @@
-Tue Jun 20 10:18:28 1995  Jeff Law  (law@snake.cs.utah.edu)
-
-	* hppa.h (CPU_PA_RISC1_0): Protect from redefinitions.
-	(CPU_PA_RISC1_1): Likewise.
-
-Wed Mar  8 18:14:37 1995  Michael Meissner  <meissner@tiktok.cygnus.com>
-
-	* ppc.h: New file for PowerPC support.
-
-Tue Feb 14 13:59:13 1995  Michael Meissner  <meissner@tiktok.cygnus.com>
-
-	* common.h (EM_PPC): Use official value of 20, not 17.
-	(EM_PPC_OLD): Define this to be the old value of EM_PPC.
-
-
-Tue Jan 24 09:40:59 1995  Michael Meissner  <meissner@tiktok.cygnus.com>
-
-	* common.h (EM_PPC): New macro, PowerPC machine id.
-
-Tue Jan 17 10:51:38 1995  Ian Lance Taylor  <ian@sanguine.cygnus.com>
-
-	* mips.h (SHT_MIPS_MSYM, SHT_MIPS_DWARF, SHT_MIPS_EVENTS): Define.
-
-
-Mon Oct 17 13:43:59 1994  Ian Lance Taylor  <ian@sanguine.cygnus.com>
-
-	* internal.h (Elf_Internal_Shdr): Remove rawdata and size fields.
-	Add bfd_section field.
-
-Tue May 24 16:11:50 1994  Ian Lance Taylor  (ian@tweedledumb.cygnus.com)
-
-	* mips.h (Elf32_External_gptab): Define.
-
-Mon May 16 13:22:04 1994  Jeff Law  (law@snake.cs.utah.edu)
-
-	* common.h (EM_HPPA): Delete.
-	(EM_PARISC): Add.
-	* hppa.h: New file.
-
-Mon May  9 13:27:03 1994  Ian Lance Taylor  (ian@tweedledumb.cygnus.com)
-
-	* common.h (SHN_LORESERVE): Rename from SHN_LORESERV.
-	(ELF32_R_TYPE, ELF32_R_INFO): Don't rely on size of unsigned char.
-	(ELF64_R_TYPE): Don't rely on size of unsigned long.
-
-Mon Apr 25 15:53:09 1994  Ian Lance Taylor  (ian@tweedledumb.cygnus.com)
-
-	* internal.h (Elf_Internal_Shdr): Use PTR, not void *.
-
-Fri Mar 11 00:34:59 1994  Peter Schauer  (pes@regent.e-technik.tu-muenchen.de)
-
-	* mips.h (SHN_MIPS_TEXT, SHN_MIPS_DATA):  Define.
-
-Sat Mar  5 14:08:54 1994  Peter Schauer  (pes@regent.e-technik.tu-muenchen.de)
-
-	* internal.h:  Remove Elf32_*, Elf64_* typedefs.  These names
-	cause conflicts with system headers, e.g. link.h in gdb/solib.c.
-	Combine 32- and 64-bit versions of *_Internal_Dyn.
-	* common.h:  Replace uses of Elf64_Word, Elf64_Xword typedefs
-	by their expansion.
-	* mips.h:  Replace uses of Elf32_Word, Elf32_Sword, Elf32_Addr
-	typedefs by their expansion. Add DT_MIPS_RLD_MAP definition.
-
-Fri Feb 18 10:39:54 1994  Ian Lance Taylor  (ian@tweedledumb.cygnus.com)
-
-	* common.h (EM_CYGNUS_POWERPC): Define.  This may be temporary,
-	depending upon how quickly I can find a real PowerPC ABI.
-
-Mon Feb  7 08:27:13 1994  Jim Kingdon  (kingdon@lioth.cygnus.com)
-
-	* internal.h: Change HOST_64_BIT to BFD_HOST_64_BIT.
-
-Wed Feb  2 14:12:18 1994  Jim Kingdon  (kingdon@lioth.cygnus.com)
-
-	* common.h: Add comments regarding value of EM_HPPA and how to
-	pick an unofficial value.
-
-Wed Nov 17 17:14:26 1993  Ian Lance Taylor  (ian@tweedledumb.cygnus.com)
-
-	* mips.h (SHT_MIPS_OPTIONS): Define.
-
-Mon Nov  8 17:57:00 1993  Ian Lance Taylor  (ian@tweedledumb.cygnus.com)
-
-	* mips.h: Added some more MIPS ABI macro definitions.
-
-Wed Nov  3 22:07:17 1993  Ken Raeburn  (raeburn@rtl.cygnus.com)
-
-	* common.h (EM_MIPS_RS4_BE): New macro.
-
-Tue Oct 12 07:28:18 1993  Ian Lance Taylor  (ian@cygnus.com)
-
-	* mips.h: New file.  MIPS ABI specific information.
-
-Mon Jun 21 13:13:43 1993  Ken Raeburn  (raeburn@poseidon.cygnus.com)
-
-	* internal.h: Combined 32- and 64-bit versions of all structures
-	except *_Internal_Dyn.  This will simply the assembler interface,
-	and some bfd code.
-
-Tue May 25 02:00:16 1993  Ken Raeburn  (raeburn@cambridge.cygnus.com)
-
-	* external.h, internal.h, common.h: Added 64-bit versions of some
-	structures and macros.  Renamed old versions to put "32" in the
-	name.  Some are unchanged.
-
-Thu Apr 29 12:12:20 1993  Ken Raeburn  (raeburn@deneb.cygnus.com)
-
-	* common.h (EM_HPPA, NT_VERSION, STN_UNDEF, DT_*): New macros.
-	* external.h (Elf_External_Dyn): New type.
-
-	* internal.h (Elf_Internal_Shdr): New field `size'.
-	(Elf_Internal_Dyn): New type.
-
-Tue Apr 20 16:03:45 1993  Fred Fish  (fnf@cygnus.com)
-
-	* dwarf.h (LANG_CHILL):  Change value to one randomly picked in
-	the user defined range, to reduce probability of collisions.
-
-Sun Nov 15 09:34:02 1992  Fred Fish  (fnf@cygnus.com)
-
-	* dwarf.h (AT_src_coords):  Whitespace change only.
-	* dwarf.h (AT_body_begin, AT_body_end, LANG_MODULA2):
-	Add from latest gcc.
-	* dwarf.h (LANG_CHILL):  Add as GNU extension.
-
-Sat Aug  1 13:46:53 1992  Fred Fish  (fnf@cygnus.com)
-
-	* dwarf.h:  Replace with current version from gcc distribution.
-
-Fri Jun 19 19:05:09 1992  John Gilmore  (gnu at cygnus.com)
-
-	* internal.h:  Add real struct tags to all the Type_Defs, so they
-	can be used in prototypes where the Type_Defs are not known.
-
-Fri Apr  3 20:58:58 1992  Mark Eichin  (eichin at cygnus.com)
-
-	* common.h: added ELF_R_{SYM,TYPE,INFO} for handling relocation
-	info
-	added EM_MIPS, and corrected value of EM_860 based on System V ABI
-	manual. 
-
-	* external.h: added Elf_External_{Rel,Rela}.
-
-	* internal.h: added Elf_Internal_{Rel,Rela}.
-	added rawdata to Elf_Internal_Shdr.
-
-Sat Nov 30 20:43:59 1991  Steve Chamberlain  (sac at rtl.cygnus.com)
-
-	* common.h, dwarf.h, external.h, internal.h, ChangeLog; moved from
-	../elf-<foo>
-
-
-Local Variables:
-version-control: never
-End:
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/include/elf/common.h linux/arch/ppc/kernel/include/elf/common.h
--- v2.1.15/linux/arch/ppc/kernel/include/elf/common.h	Mon May 27 12:00:57 1996
+++ linux/arch/ppc/kernel/include/elf/common.h	Thu Jan  1 02:00:00 1970
@@ -1,232 +0,0 @@
-/* ELF support for BFD.
-   Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
-
-   Written by Fred Fish @ Cygnus Support, from information published
-   in "UNIX System V Release 4, Programmers Guide: ANSI C and
-   Programming Support Tools".
-
-This file is part of BFD, the Binary File Descriptor library.
-
-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.  */
-
-
-/* This file is part of ELF support for BFD, and contains the portions
-   that are common to both the internal and external representations.
-   For example, ELFMAG0 is the byte 0x7F in both the internal (in-memory)
-   and external (in-file) representations. */
-   
-
-/* Fields in e_ident[] */
-
-#define EI_MAG0		0		/* File identification byte 0 index */
-#define ELFMAG0		0x7F		/* Magic number byte 0 */
-
-#define EI_MAG1		1		/* File identification byte 1 index */
-#define ELFMAG1		'E'		/* Magic number byte 1 */
-
-#define EI_MAG2		2		/* File identification byte 2 index */
-#define ELFMAG2		'L'		/* Magic number byte 2 */
-
-#define EI_MAG3		3		/* File identification byte 3 index */
-#define ELFMAG3		'F'		/* Magic number byte 3 */
-
-#define EI_CLASS	4		/* File class */
-#define ELFCLASSNONE	0		/* Invalid class */
-#define ELFCLASS32	1		/* 32-bit objects */
-#define ELFCLASS64	2		/* 64-bit objects */
-
-#define EI_DATA		5		/* Data encoding */
-#define ELFDATANONE	0		/* Invalid data encoding */
-#define ELFDATA2LSB	1		/* 2's complement, little endian */
-#define ELFDATA2MSB	2		/* 2's complement, big endian */
-
-#define EI_VERSION	6		/* File version */
-
-#define EI_PAD		7		/* Start of padding bytes */
-
-
-/* Values for e_type, which identifies the object file type */
-
-#define ET_NONE		0		/* No file type */
-#define ET_REL		1		/* Relocatable file */
-#define ET_EXEC		2		/* Executable file */
-#define ET_DYN		3		/* Shared object file */
-#define ET_CORE		4		/* Core file */
-#define ET_LOPROC	0xFF00		/* Processor-specific */
-#define ET_HIPROC	0xFFFF		/* Processor-specific */
-
-/* Values for e_machine, which identifies the architecture */
-
-#define EM_NONE		0	/* No machine */
-#define EM_M32		1	/* AT&T WE 32100 */
-#define EM_SPARC	2	/* SUN SPARC */
-#define EM_386		3	/* Intel 80386 */
-#define EM_68K		4	/* Motorola m68k family */
-#define EM_88K		5	/* Motorola m88k family */
-#define EM_860		7	/* Intel 80860 */
-#define EM_MIPS		8	/* MIPS R3000 (officially, big-endian only) */
-
-#define EM_MIPS_RS4_BE 10	/* MIPS R4000 big-endian */
-
-#define EM_SPARC64     11	/* SPARC v9 (not official) 64-bit */
-
-#define EM_PARISC      15	/* HPPA */
-#define EM_PPC	       20	/* PowerPC */
-
-/* If it is necessary to assign new unofficial EM_* values, please pick large
-   random numbers (0x8523, 0xa7f2, etc.) to minimize the chances of collision
-   with official or non-GNU unofficial values.  */
-
-/* Cygnus PowerPC ELF backend.  Written in the absence of an ABI.  */
-#define EM_CYGNUS_POWERPC 0x9025
-
-/* Old version of PowerPC, this should be removed shortly. */
-#define EM_PPC_OLD	17
-
-
-/* Values for e_version */
-
-#define EV_NONE		0		/* Invalid ELF version */
-#define EV_CURRENT	1		/* Current version */
-
-/* Values for program header, p_type field */
-
-#define	PT_NULL		0		/* Program header table entry unused */
-#define PT_LOAD		1		/* Loadable program segment */
-#define PT_DYNAMIC	2		/* Dynamic linking information */
-#define PT_INTERP	3		/* Program interpreter */
-#define PT_NOTE		4		/* Auxiliary information */
-#define PT_SHLIB	5		/* Reserved, unspecified semantics */
-#define PT_PHDR		6		/* Entry for header table itself */
-#define PT_LOPROC	0x70000000	/* Processor-specific */
-#define PT_HIPROC	0x7FFFFFFF	/* Processor-specific */
-
-/* Program segment permissions, in program header p_flags field */
-
-#define PF_X		(1 << 0)	/* Segment is executable */
-#define PF_W		(1 << 1)	/* Segment is writable */
-#define PF_R		(1 << 2)	/* Segment is readable */
-#define PF_MASKPROC	0xF0000000	/* Processor-specific reserved bits */
-
-/* Values for section header, sh_type field */
-
-#define SHT_NULL	0		/* Section header table entry unused */
-#define SHT_PROGBITS	1		/* Program specific (private) data */
-#define SHT_SYMTAB	2		/* Link editing symbol table */
-#define SHT_STRTAB	3		/* A string table */
-#define SHT_RELA	4		/* Relocation entries with addends */
-#define SHT_HASH	5		/* A symbol hash table */
-#define SHT_DYNAMIC	6		/* Information for dynamic linking */
-#define SHT_NOTE	7		/* Information that marks file */
-#define SHT_NOBITS	8		/* Section occupies no space in file */
-#define SHT_REL		9		/* Relocation entries, no addends */
-#define SHT_SHLIB	10		/* Reserved, unspecified semantics */
-#define SHT_DYNSYM	11		/* Dynamic linking symbol table */
-#define SHT_LOPROC	0x70000000	/* Processor-specific semantics, lo */
-#define SHT_HIPROC	0x7FFFFFFF	/* Processor-specific semantics, hi */
-#define SHT_LOUSER	0x80000000	/* Application-specific semantics */
-#define SHT_HIUSER	0x8FFFFFFF	/* Application-specific semantics */
-
-/* Values for section header, sh_flags field */
-
-#define SHF_WRITE	(1 << 0)	/* Writable data during execution */
-#define SHF_ALLOC	(1 << 1)	/* Occupies memory during execution */
-#define SHF_EXECINSTR	(1 << 2)	/* Executable machine instructions */
-#define SHF_MASKPROC	0xF0000000	/* Processor-specific semantics */
-
-/* Values of note segment descriptor types for core files. */
-
-#define NT_PRSTATUS	1		/* Contains copy of prstatus struct */
-#define NT_FPREGSET	2		/* Contains copy of fpregset struct */
-#define NT_PRPSINFO	3		/* Contains copy of prpsinfo struct */
-
-/* Values of note segment descriptor types for object files.  */
-/* (Only for hppa right now.  Should this be moved elsewhere?)  */
-
-#define NT_VERSION	1		/* Contains a version string.  */
-
-/* These three macros disassemble and assemble a symbol table st_info field,
-   which contains the symbol binding and symbol type.  The STB_ and STT_
-   defines identify the binding and type. */
-
-#define ELF_ST_BIND(val)		(((unsigned int)(val)) >> 4)
-#define ELF_ST_TYPE(val)		((val) & 0xF)
-#define ELF_ST_INFO(bind,type)		(((bind) << 4) + ((type) & 0xF))
-
-#define STN_UNDEF	0		/* undefined symbol index */
-
-#define STB_LOCAL	0		/* Symbol not visible outside obj */
-#define STB_GLOBAL	1		/* Symbol visible outside obj */
-#define STB_WEAK	2		/* Like globals, lower precedence */
-#define STB_LOPROC	13		/* Application-specific semantics */
-#define STB_HIPROC	15		/* Application-specific semantics */
-
-#define STT_NOTYPE	0		/* Symbol type is unspecified */
-#define STT_OBJECT	1		/* Symbol is a data object */
-#define STT_FUNC	2		/* Symbol is a code object */
-#define STT_SECTION	3		/* Symbol associated with a section */
-#define STT_FILE	4		/* Symbol gives a file name */
-#define STT_LOPROC	13		/* Application-specific semantics */
-#define STT_HIPROC	15		/* Application-specific semantics */
-
-/* Special section indices, which may show up in st_shndx fields, among
-   other places. */
-
-#define SHN_UNDEF	0		/* Undefined section reference */
-#define SHN_LORESERVE	0xFF00		/* Begin range of reserved indices */
-#define SHN_LOPROC	0xFF00		/* Begin range of appl-specific */
-#define SHN_HIPROC	0xFF1F		/* End range of appl-specific */
-#define SHN_ABS		0xFFF1		/* Associated symbol is absolute */
-#define SHN_COMMON	0xFFF2		/* Associated symbol is in common */
-#define SHN_HIRESERVE	0xFFFF		/* End range of reserved indices */
-
-/* relocation info handling macros */
-
-#define ELF32_R_SYM(i)		((i) >> 8)
-#define ELF32_R_TYPE(i)		((i) & 0xff)
-#define ELF32_R_INFO(s,t)	(((s) << 8) + ((t) & 0xff))
-
-#define ELF64_R_SYM(i)		((i) >> 32)
-#define ELF64_R_TYPE(i)		((i) & 0xffffffff)
-#define ELF64_R_INFO(s,t)	(((bfd_vma) (s) << 32) + (bfd_vma) (t))
-
-/* Dynamic section tags */
-
-#define DT_NULL		0
-#define DT_NEEDED	1
-#define DT_PLTRELSZ	2
-#define DT_PLTGOT	3
-#define DT_HASH		4
-#define DT_STRTAB	5
-#define DT_SYMTAB	6
-#define DT_RELA		7
-#define DT_RELASZ	8
-#define DT_RELAENT	9
-#define DT_STRSZ	10
-#define DT_SYMENT	11
-#define DT_INIT		12
-#define DT_FINI		13
-#define DT_SONAME	14
-#define DT_RPATH	15
-#define DT_SYMBOLIC	16
-#define DT_REL		17
-#define DT_RELSZ	18
-#define DT_RELENT	19
-#define DT_PLTREL	20
-#define DT_DEBUG	21
-#define DT_TEXTREL	22
-#define DT_JMPREL	23
-#define DT_LOPROC	0x70000000
-#define DT_HIPROC	0x7fffffff
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/include/elf/dwarf.h linux/arch/ppc/kernel/include/elf/dwarf.h
--- v2.1.15/linux/arch/ppc/kernel/include/elf/dwarf.h	Mon May 27 12:00:57 1996
+++ linux/arch/ppc/kernel/include/elf/dwarf.h	Thu Jan  1 02:00:00 1970
@@ -1,314 +0,0 @@
-/* Declarations and definitions of codes relating to the DWARF symbolic
-   debugging information format.
-
-   Written by Ron Guilmette (rfg@ncd.com)
-
-Copyright (C) 1992 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU CC 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 GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
-
-/* This file is derived from the DWARF specification (a public document)
-   Revision 1.0.1 (April 8, 1992) developed by the UNIX International
-   Programming Languages Special Interest Group (UI/PLSIG) and distributed
-   by UNIX International.  Copies of this specification are available from
-   UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054.
-*/
-
-/* Tag names and codes.  */
-
-enum dwarf_tag {
-    TAG_padding			= 0x0000,
-    TAG_array_type		= 0x0001,
-    TAG_class_type		= 0x0002,
-    TAG_entry_point		= 0x0003,
-    TAG_enumeration_type	= 0x0004,
-    TAG_formal_parameter	= 0x0005,
-    TAG_global_subroutine	= 0x0006,
-    TAG_global_variable		= 0x0007,
-    				/* 0x0008 -- reserved */
-				/* 0x0009 -- reserved */
-    TAG_label			= 0x000a,
-    TAG_lexical_block		= 0x000b,
-    TAG_local_variable		= 0x000c,
-    TAG_member			= 0x000d,
-				/* 0x000e -- reserved */
-    TAG_pointer_type		= 0x000f,
-    TAG_reference_type		= 0x0010,
-    TAG_compile_unit		= 0x0011,
-    TAG_string_type		= 0x0012,
-    TAG_structure_type		= 0x0013,
-    TAG_subroutine		= 0x0014,
-    TAG_subroutine_type		= 0x0015,
-    TAG_typedef			= 0x0016,
-    TAG_union_type		= 0x0017,
-    TAG_unspecified_parameters	= 0x0018,
-    TAG_variant			= 0x0019,
-    TAG_common_block		= 0x001a,
-    TAG_common_inclusion	= 0x001b,
-    TAG_inheritance		= 0x001c,
-    TAG_inlined_subroutine	= 0x001d,
-    TAG_module			= 0x001e,
-    TAG_ptr_to_member_type	= 0x001f,
-    TAG_set_type		= 0x0020,
-    TAG_subrange_type		= 0x0021,
-    TAG_with_stmt		= 0x0022,
-
-    /* GNU extensions */
-
-    TAG_format_label		= 0x8000,  /* for FORTRAN 77 and Fortran 90 */
-    TAG_namelist		= 0x8001,  /* For Fortran 90 */
-    TAG_function_template	= 0x8002,  /* for C++ */
-    TAG_class_template		= 0x8003   /* for C++ */
-};
-
-#define TAG_lo_user	0x8000  /* implementation-defined range start */
-#define TAG_hi_user	0xffff  /* implementation-defined range end */
-#define TAG_source_file TAG_compile_unit  /* for backward compatibility */
-
-/* Form names and codes.  */
-
-enum dwarf_form {
-    FORM_ADDR	= 0x1,
-    FORM_REF	= 0x2,
-    FORM_BLOCK2	= 0x3,
-    FORM_BLOCK4	= 0x4,
-    FORM_DATA2	= 0x5,
-    FORM_DATA4	= 0x6,
-    FORM_DATA8	= 0x7,
-    FORM_STRING	= 0x8
-};
-
-/* Attribute names and codes.  */
-
-enum dwarf_attribute {
-    AT_sibling			= (0x0010|FORM_REF),
-    AT_location			= (0x0020|FORM_BLOCK2),
-    AT_name			= (0x0030|FORM_STRING),
-    AT_fund_type		= (0x0050|FORM_DATA2),
-    AT_mod_fund_type		= (0x0060|FORM_BLOCK2),
-    AT_user_def_type		= (0x0070|FORM_REF),
-    AT_mod_u_d_type		= (0x0080|FORM_BLOCK2),
-    AT_ordering			= (0x0090|FORM_DATA2),
-    AT_subscr_data		= (0x00a0|FORM_BLOCK2),
-    AT_byte_size		= (0x00b0|FORM_DATA4),
-    AT_bit_offset		= (0x00c0|FORM_DATA2),
-    AT_bit_size			= (0x00d0|FORM_DATA4),
-				/* (0x00e0|FORM_xxxx) -- reserved */
-    AT_element_list		= (0x00f0|FORM_BLOCK4),
-    AT_stmt_list		= (0x0100|FORM_DATA4),
-    AT_low_pc			= (0x0110|FORM_ADDR),
-    AT_high_pc			= (0x0120|FORM_ADDR),
-    AT_language			= (0x0130|FORM_DATA4),
-    AT_member			= (0x0140|FORM_REF),
-    AT_discr			= (0x0150|FORM_REF),
-    AT_discr_value		= (0x0160|FORM_BLOCK2),
-				/* (0x0170|FORM_xxxx) -- reserved */
-				/* (0x0180|FORM_xxxx) -- reserved */
-    AT_string_length		= (0x0190|FORM_BLOCK2),
-    AT_common_reference		= (0x01a0|FORM_REF),
-    AT_comp_dir			= (0x01b0|FORM_STRING),
-        AT_const_value_string	= (0x01c0|FORM_STRING),
-        AT_const_value_data2	= (0x01c0|FORM_DATA2),
-        AT_const_value_data4	= (0x01c0|FORM_DATA4),
-        AT_const_value_data8	= (0x01c0|FORM_DATA8),
-        AT_const_value_block2	= (0x01c0|FORM_BLOCK2),
-        AT_const_value_block4	= (0x01c0|FORM_BLOCK4),
-    AT_containing_type		= (0x01d0|FORM_REF),
-        AT_default_value_addr	= (0x01e0|FORM_ADDR),
-        AT_default_value_data2	= (0x01e0|FORM_DATA2),
-        AT_default_value_data4	= (0x01e0|FORM_DATA4),
-        AT_default_value_data8	= (0x01e0|FORM_DATA8),
-        AT_default_value_string	= (0x01e0|FORM_STRING),
-    AT_friends			= (0x01f0|FORM_BLOCK2),
-    AT_inline			= (0x0200|FORM_STRING),
-    AT_is_optional		= (0x0210|FORM_STRING),
-        AT_lower_bound_ref	= (0x0220|FORM_REF),
-        AT_lower_bound_data2	= (0x0220|FORM_DATA2),
-        AT_lower_bound_data4	= (0x0220|FORM_DATA4),
-        AT_lower_bound_data8	= (0x0220|FORM_DATA8),
-    AT_private			= (0x0240|FORM_STRING),
-    AT_producer			= (0x0250|FORM_STRING),
-    AT_program			= (0x0230|FORM_STRING),
-    AT_protected		= (0x0260|FORM_STRING),
-    AT_prototyped		= (0x0270|FORM_STRING),
-    AT_public			= (0x0280|FORM_STRING),
-    AT_pure_virtual		= (0x0290|FORM_STRING),
-    AT_return_addr		= (0x02a0|FORM_BLOCK2),
-    AT_abstract_origin		= (0x02b0|FORM_REF),
-    AT_start_scope		= (0x02c0|FORM_DATA4),
-    AT_stride_size		= (0x02e0|FORM_DATA4),
-        AT_upper_bound_ref	= (0x02f0|FORM_REF),
-        AT_upper_bound_data2	= (0x02f0|FORM_DATA2),
-        AT_upper_bound_data4	= (0x02f0|FORM_DATA4),
-        AT_upper_bound_data8	= (0x02f0|FORM_DATA8),
-    AT_virtual			= (0x0300|FORM_STRING),
-
-    /* GNU extensions.  */
-
-    AT_sf_names			= (0x8000|FORM_DATA4),
-    AT_src_info			= (0x8010|FORM_DATA4),
-    AT_mac_info			= (0x8020|FORM_DATA4),
-    AT_src_coords		= (0x8030|FORM_DATA4),
-    AT_body_begin		= (0x8040|FORM_ADDR),
-    AT_body_end			= (0x8050|FORM_ADDR)
-};
-
-#define AT_lo_user	0x8000  /* implementation-defined range start */
-#define AT_hi_user	0xffff  /* implementation-defined range end */
-
-/* Location atom names and codes.  */
-
-enum dwarf_location_atom {
-    OP_REG	= 0x01,
-    OP_BASEREG	= 0x02,
-    OP_ADDR	= 0x03,
-    OP_CONST	= 0x04,
-    OP_DEREF2	= 0x05,
-    OP_DEREF4	= 0x06,
-    OP_ADD	= 0x07
-};
-
-#define OP_LO_USER	0x80  /* implementation-defined range start */
-#define OP_HI_USER	0xff  /* implementation-defined range end */
-
-/* Fundamental type names and codes.  */
-
-enum dwarf_fundamental_type {
-    FT_char		= 0x0001,
-    FT_signed_char	= 0x0002,
-    FT_unsigned_char	= 0x0003,
-    FT_short		= 0x0004,
-    FT_signed_short	= 0x0005,
-    FT_unsigned_short	= 0x0006,
-    FT_integer		= 0x0007,
-    FT_signed_integer	= 0x0008,
-    FT_unsigned_integer	= 0x0009,
-    FT_long		= 0x000a,
-    FT_signed_long	= 0x000b,
-    FT_unsigned_long	= 0x000c,
-    FT_pointer		= 0x000d,  /* an alias for (void *) */
-    FT_float		= 0x000e,
-    FT_dbl_prec_float	= 0x000f,
-    FT_ext_prec_float	= 0x0010,  /* breaks "classic" svr4 SDB */
-    FT_complex		= 0x0011,  /* breaks "classic" svr4 SDB */
-    FT_dbl_prec_complex	= 0x0012,  /* breaks "classic" svr4 SDB */
-			/* 0x0013 -- reserved */
-    FT_void		= 0x0014,
-    FT_boolean		= 0x0015,  /* breaks "classic" svr4 SDB */
-    FT_ext_prec_complex	= 0x0016,  /* breaks "classic" svr4 SDB */
-    FT_label		= 0x0017,
-  
-    /* GNU extensions
-       The low order byte must indicate the size (in bytes) for the type.
-       All of these types will probably break "classic" svr4 SDB */
-
-    FT_long_long	= 0x8008,
-    FT_signed_long_long	= 0x8108,
-    FT_unsigned_long_long = 0x8208,
-
-    FT_int8		= 0x9001,
-    FT_signed_int8	= 0x9101,
-    FT_unsigned_int8	= 0x9201,
-    FT_int16		= 0x9302,
-    FT_signed_int16	= 0x9402,
-    FT_unsigned_int16	= 0x9502,
-    FT_int32		= 0x9604,
-    FT_signed_int32	= 0x9704,
-    FT_unsigned_int32	= 0x9804,
-    FT_int64		= 0x9908,
-    FT_signed_int64	= 0x9a08,
-    FT_unsigned_int64	= 0x9b08,
-
-    FT_real32		= 0xa004,
-    FT_real64		= 0xa108,
-    FT_real96		= 0xa20c,
-    FT_real128		= 0xa310
-};
-
-#define FT_lo_user	0x8000  /* implementation-defined range start */
-#define FT_hi_user	0xffff  /* implementation defined range end */
-
-/* Type modifier names and codes.  */
-
-enum dwarf_type_modifier {
-    MOD_pointer_to	= 0x01,
-    MOD_reference_to	= 0x02,
-    MOD_const		= 0x03,
-    MOD_volatile	= 0x04
-};
-
-#define MOD_lo_user	0x80  /* implementation-defined range start */
-#define MOD_hi_user	0xff  /* implementation-defined range end */
-
-/* Array ordering names and codes.  */
-
-enum dwarf_array_dim_ordering {
-    ORD_row_major	= 0,
-    ORD_col_major	= 1
-};
-
-/* Array subscript format names and codes.  */
-
-enum dwarf_subscr_data_formats {
-    FMT_FT_C_C	= 0x0,
-    FMT_FT_C_X	= 0x1,
-    FMT_FT_X_C	= 0x2,
-    FMT_FT_X_X	= 0x3,
-    FMT_UT_C_C	= 0x4,
-    FMT_UT_C_X	= 0x5,
-    FMT_UT_X_C	= 0x6,
-    FMT_UT_X_X	= 0x7,
-    FMT_ET	= 0x8
-};
-
-/* Derived from above for ease of use.  */
-
-#define FMT_CODE(_FUNDAMENTAL_TYPE_P, _UB_CONST_P, _LB_CONST_P) \
- (((_FUNDAMENTAL_TYPE_P) ? 0 : 4)	\
-  | ((_UB_CONST_P) ? 0 : 2)		\
-  | ((_LB_CONST_P) ? 0 : 1))
-
-/* Source language names and codes.  */
-
-enum dwarf_source_language {
-    LANG_C89		= 0x00000001,
-    LANG_C		= 0x00000002,
-    LANG_ADA83		= 0x00000003,
-    LANG_C_PLUS_PLUS	= 0x00000004,
-    LANG_COBOL74	= 0x00000005,
-    LANG_COBOL85	= 0x00000006,
-    LANG_FORTRAN77	= 0x00000007,
-    LANG_FORTRAN90	= 0x00000008,
-    LANG_PASCAL83	= 0x00000009,
-    LANG_MODULA2	= 0x0000000a,
-
-    /* GNU extensions */
-
-    LANG_CHILL		= 0x00009af3	/* random value for GNU Chill */
-};
-
-#define LANG_lo_user	0x00008000  /* implementation-defined range start */
-#define LANG_hi_user	0x0000ffff  /* implementation-defined range end */
-
-/* Names and codes for GNU "macinfo" extension.  */
-
-enum dwarf_macinfo_record_type {
-    MACINFO_start	= 's',
-    MACINFO_resume	= 'r',
-    MACINFO_define	= 'd',
-    MACINFO_undef	= 'u'
-};
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/include/elf/external.h linux/arch/ppc/kernel/include/elf/external.h
--- v2.1.15/linux/arch/ppc/kernel/include/elf/external.h	Mon May 27 12:00:57 1996
+++ linux/arch/ppc/kernel/include/elf/external.h	Thu Jan  1 02:00:00 1970
@@ -1,190 +0,0 @@
-/* ELF support for BFD.
-   Copyright (C) 1991, 1992 Free Software Foundation, Inc.
-
-   Written by Fred Fish @ Cygnus Support, from information published
-   in "UNIX System V Release 4, Programmers Guide: ANSI C and
-   Programming Support Tools".
-
-This file is part of BFD, the Binary File Descriptor library.
-
-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.  */
-
-
-/* This file is part of ELF support for BFD, and contains the portions
-   that describe how ELF is represented externally by the BFD library.
-   I.E. it describes the in-file representation of ELF.  It requires
-   the elf-common.h file which contains the portions that are common to
-   both the internal and external representations. */
-   
-/* The 64-bit stuff is kind of random.  Perhaps someone will publish a
-   spec someday.  */
-
-/* ELF Header (32-bit implementations) */
-
-typedef struct {
-  unsigned char	e_ident[16];		/* ELF "magic number" */
-  unsigned char	e_type[2];		/* Identifies object file type */
-  unsigned char	e_machine[2];		/* Specifies required architecture */
-  unsigned char	e_version[4];		/* Identifies object file version */
-  unsigned char	e_entry[4];		/* Entry point virtual address */
-  unsigned char	e_phoff[4];		/* Program header table file offset */
-  unsigned char	e_shoff[4];		/* Section header table file offset */
-  unsigned char	e_flags[4];		/* Processor-specific flags */
-  unsigned char	e_ehsize[2];		/* ELF header size in bytes */
-  unsigned char	e_phentsize[2];		/* Program header table entry size */
-  unsigned char	e_phnum[2];		/* Program header table entry count */
-  unsigned char	e_shentsize[2];		/* Section header table entry size */
-  unsigned char	e_shnum[2];		/* Section header table entry count */
-  unsigned char	e_shstrndx[2];		/* Section header string table index */
-} Elf32_External_Ehdr;
-
-typedef struct {
-  unsigned char	e_ident[16];		/* ELF "magic number" */
-  unsigned char	e_type[2];		/* Identifies object file type */
-  unsigned char	e_machine[2];		/* Specifies required architecture */
-  unsigned char	e_version[4];		/* Identifies object file version */
-  unsigned char	e_entry[8];		/* Entry point virtual address */
-  unsigned char	e_phoff[8];		/* Program header table file offset */
-  unsigned char	e_shoff[8];		/* Section header table file offset */
-  unsigned char	e_flags[4];		/* Processor-specific flags */
-  unsigned char	e_ehsize[2];		/* ELF header size in bytes */
-  unsigned char	e_phentsize[2];		/* Program header table entry size */
-  unsigned char	e_phnum[2];		/* Program header table entry count */
-  unsigned char	e_shentsize[2];		/* Section header table entry size */
-  unsigned char	e_shnum[2];		/* Section header table entry count */
-  unsigned char	e_shstrndx[2];		/* Section header string table index */
-} Elf64_External_Ehdr;
-
-/* Program header */
-
-typedef struct {
-  unsigned char	p_type[4];		/* Identifies program segment type */
-  unsigned char	p_offset[4];		/* Segment file offset */
-  unsigned char	p_vaddr[4];		/* Segment virtual address */
-  unsigned char	p_paddr[4];		/* Segment physical address */
-  unsigned char	p_filesz[4];		/* Segment size in file */
-  unsigned char	p_memsz[4];		/* Segment size in memory */
-  unsigned char	p_flags[4];		/* Segment flags */
-  unsigned char	p_align[4];		/* Segment alignment, file & memory */
-} Elf32_External_Phdr;
-
-typedef struct {
-  unsigned char	p_type[4];		/* Identifies program segment type */
-  unsigned char	p_flags[4];		/* Segment flags */
-  unsigned char	p_offset[8];		/* Segment file offset */
-  unsigned char	p_vaddr[8];		/* Segment virtual address */
-  unsigned char	p_paddr[8];		/* Segment physical address */
-  unsigned char	p_filesz[8];		/* Segment size in file */
-  unsigned char	p_memsz[8];		/* Segment size in memory */
-  unsigned char	p_align[8];		/* Segment alignment, file & memory */
-} Elf64_External_Phdr;
-
-/* Section header */
-
-typedef struct {
-  unsigned char	sh_name[4];		/* Section name, index in string tbl */
-  unsigned char	sh_type[4];		/* Type of section */
-  unsigned char	sh_flags[4];		/* Miscellaneous section attributes */
-  unsigned char	sh_addr[4];		/* Section virtual addr at execution */
-  unsigned char	sh_offset[4];		/* Section file offset */
-  unsigned char	sh_size[4];		/* Size of section in bytes */
-  unsigned char	sh_link[4];		/* Index of another section */
-  unsigned char	sh_info[4];		/* Additional section information */
-  unsigned char	sh_addralign[4];	/* Section alignment */
-  unsigned char	sh_entsize[4];		/* Entry size if section holds table */
-} Elf32_External_Shdr;
-
-typedef struct {
-  unsigned char	sh_name[4];		/* Section name, index in string tbl */
-  unsigned char	sh_type[4];		/* Type of section */
-  unsigned char	sh_flags[8];		/* Miscellaneous section attributes */
-  unsigned char	sh_addr[8];		/* Section virtual addr at execution */
-  unsigned char	sh_offset[8];		/* Section file offset */
-  unsigned char	sh_size[8];		/* Size of section in bytes */
-  unsigned char	sh_link[4];		/* Index of another section */
-  unsigned char	sh_info[4];		/* Additional section information */
-  unsigned char	sh_addralign[8];	/* Section alignment */
-  unsigned char	sh_entsize[8];		/* Entry size if section holds table */
-} Elf64_External_Shdr;
-
-/* Symbol table entry */
-
-typedef struct {
-  unsigned char	st_name[4];		/* Symbol name, index in string tbl */
-  unsigned char	st_value[4];		/* Value of the symbol */
-  unsigned char	st_size[4];		/* Associated symbol size */
-  unsigned char	st_info[1];		/* Type and binding attributes */
-  unsigned char	st_other[1];		/* No defined meaning, 0 */
-  unsigned char	st_shndx[2];		/* Associated section index */
-} Elf32_External_Sym;
-
-typedef struct {
-  unsigned char	st_name[4];		/* Symbol name, index in string tbl */
-  unsigned char	st_info[1];		/* Type and binding attributes */
-  unsigned char	st_other[1];		/* No defined meaning, 0 */
-  unsigned char	st_shndx[2];		/* Associated section index */
-  unsigned char	st_value[8];		/* Value of the symbol */
-  unsigned char	st_size[8];		/* Associated symbol size */
-} Elf64_External_Sym;
-
-/* Note segments */
-
-typedef struct {
-  unsigned char	namesz[4];		/* Size of entry's owner string */
-  unsigned char	descsz[4];		/* Size of the note descriptor */
-  unsigned char	type[4];		/* Interpretation of the descriptor */
-  char		name[1];		/* Start of the name+desc data */
-} Elf_External_Note;
-
-/* Relocation Entries */
-typedef struct {
-  unsigned char r_offset[4];	/* Location at which to apply the action */
-  unsigned char	r_info[4];	/* index and type of relocation */
-} Elf32_External_Rel;
-
-typedef struct {
-  unsigned char r_offset[4];	/* Location at which to apply the action */
-  unsigned char	r_info[4];	/* index and type of relocation */
-  unsigned char	r_addend[4];	/* Constant addend used to compute value */
-} Elf32_External_Rela;
-
-typedef struct {
-  unsigned char r_offset[8];	/* Location at which to apply the action */
-  unsigned char	r_info[8];	/* index and type of relocation */
-} Elf64_External_Rel;
-
-typedef struct {
-  unsigned char r_offset[8];	/* Location at which to apply the action */
-  unsigned char	r_info[8];	/* index and type of relocation */
-  unsigned char	r_addend[8];	/* Constant addend used to compute value */
-} Elf64_External_Rela;
-
-/* dynamic section structure */
-
-typedef struct {
-  unsigned char	d_tag[4];		/* entry tag value */
-  union {
-    unsigned char	d_val[4];
-    unsigned char	d_ptr[4];
-  } d_un;
-} Elf32_External_Dyn;
-
-typedef struct {
-  unsigned char	d_tag[8];		/* entry tag value */
-  union {
-    unsigned char	d_val[8];
-    unsigned char	d_ptr[8];
-  } d_un;
-} Elf64_External_Dyn;
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/include/elf/hppa.h linux/arch/ppc/kernel/include/elf/hppa.h
--- v2.1.15/linux/arch/ppc/kernel/include/elf/hppa.h	Mon May 27 12:00:57 1996
+++ linux/arch/ppc/kernel/include/elf/hppa.h	Thu Jan  1 02:00:00 1970
@@ -1,90 +0,0 @@
-/* HPPA ELF support for BFD.
-   Copyright (C) 1993, 1994 Free Software Foundation, Inc.
-
-This file is part of BFD, the Binary File Descriptor library.
-
-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.  */
-
-/* This file holds definitions specific to the HPPA ELF ABI.  Note
-   that most of this is not actually implemented by BFD.  */
-
-/* Processor specific flags for the ELF header e_flags field.  */
-
-/* Target processor IDs to be placed in the low 16 bits of the flags
-   field.  Note these names are shared with SOM, and therefore do not
-   follow ELF naming conventions.  */
-
-/* PA 1.0 big endian.  */
-#ifndef CPU_PA_RISC1_0
-#define CPU_PA_RISC1_0		0x0000020b
-#endif
-
-/* PA 1.1 big endian.  */
-#ifndef CPU_PA_RISC1_1
-#define CPU_PA_RISC1_1		0x00000210
-#endif
-
-/* PA 1.0 little endian (unsupported) is 0x0000028b.  */
-/* PA 1.1 little endian (unsupported) is 0x00000290.  */
-
-/* Trap null address dereferences.  */
-#define ELF_PARISC_TRAPNIL	0x00010000
-
-/* .PARISC.archext section is present.  */
-#define EF_PARISC_EXT		0x00020000
-
-/* Processor specific section types.  */
-
-/* Holds the global offset table, a table of pointers to external
-   data.  */
-#define SHT_PARISC_GOT		SHT_LOPROC+0
-
-/* Nonloadable section containing information in architecture
-   extensions used by the code.  */
-#define SHT_PARISC_ARCH		SHT_LOPROC+1
-
-/* Section in which $global$ is defined.  */
-#define SHT_PARISC_GLOBAL	SHT_LOPROC+2
-
-/* Section holding millicode routines (mul, div, rem, dyncall, etc.  */
-#define SHT_PARISC_MILLI	SHT_LOPROC+3
-
-/* Section holding unwind information for use by debuggers.  */
-#define SHT_PARISC_UNWIND	SHT_LOPROC+4
-
-/* Section holding the procedure linkage table.  */
-#define SHT_PARISC_PLT		SHT_LOPROC+5
-
-/* Short initialized and uninitialized data.  */
-#define SHT_PARISC_SDATA	SHT_LOPROC+6
-#define SHT_PARISC_SBSS		SHT_LOPROC+7
-
-/* Optional section holding argument location/relocation info.  */
-#define SHT_PARISC_SYMEXTN	SHT_LOPROC+8
-
-/* Option section for linker stubs.  */
-#define SHT_PARISC_STUBS	SHT_LOPROC+9
-
-/* Processor specific section flags.  */
-
-/* This section is near the global data pointer and thus allows short
-   addressing modes to be used.  */
-#define SHF_PARISC_SHORT        0x20000000
-
-/* Processor specific symbol types.  */
-
-/* Millicode function entry point.  */
-#define STT_PARISC_MILLICODE	STT_LOPROC+0
-
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/include/elf/internal.h linux/arch/ppc/kernel/include/elf/internal.h
--- v2.1.15/linux/arch/ppc/kernel/include/elf/internal.h	Mon May 27 12:00:57 1996
+++ linux/arch/ppc/kernel/include/elf/internal.h	Thu Jan  1 02:00:00 1970
@@ -1,173 +0,0 @@
-/* ELF support for BFD.
-   Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
-
-   Written by Fred Fish @ Cygnus Support, from information published
-   in "UNIX System V Release 4, Programmers Guide: ANSI C and
-   Programming Support Tools".
-
-This file is part of BFD, the Binary File Descriptor library.
-
-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.  */
-
-
-/* This file is part of ELF support for BFD, and contains the portions
-   that describe how ELF is represented internally in the BFD library.
-   I.E. it describes the in-memory representation of ELF.  It requires
-   the elf-common.h file which contains the portions that are common to
-   both the internal and external representations. */
-   
-
-/* NOTE that these structures are not kept in the same order as they appear
-   in the object file.  In some cases they've been reordered for more optimal
-   packing under various circumstances.  */
-
-/* ELF Header */
-
-#define EI_NIDENT	16		/* Size of e_ident[] */
-
-typedef struct elf_internal_ehdr {
-  unsigned char		e_ident[EI_NIDENT];	/* ELF "magic number" */
-  bfd_vma		e_entry;		/* Entry point virtual address */
-  bfd_signed_vma	e_phoff;		/* Program header table file offset */
-  bfd_signed_vma	e_shoff;		/* Section header table file offset */
-  unsigned long		e_version;		/* Identifies object file version */
-  unsigned long		e_flags;		/* Processor-specific flags */
-  unsigned short	e_type;			/* Identifies object file type */
-  unsigned short	e_machine;		/* Specifies required architecture */
-  unsigned short	e_ehsize;		/* ELF header size in bytes */
-  unsigned short	e_phentsize;		/* Program header table entry size */
-  unsigned short	e_phnum;		/* Program header table entry count */
-  unsigned short	e_shentsize;		/* Section header table entry size */
-  unsigned short	e_shnum;		/* Section header table entry count */
-  unsigned short	e_shstrndx;		/* Section header string table index */
-} Elf_Internal_Ehdr;
-
-#define elf32_internal_ehdr elf_internal_ehdr
-#define Elf32_Internal_Ehdr Elf_Internal_Ehdr
-#define elf64_internal_ehdr elf_internal_ehdr
-#define Elf64_Internal_Ehdr Elf_Internal_Ehdr
-
-/* Program header */
-
-struct elf_internal_phdr {
-  unsigned long	p_type;			/* Identifies program segment type */
-  unsigned long	p_flags;		/* Segment flags */
-  bfd_vma	p_offset;		/* Segment file offset */
-  bfd_vma	p_vaddr;		/* Segment virtual address */
-  bfd_vma	p_paddr;		/* Segment physical address */
-  bfd_vma	p_filesz;		/* Segment size in file */
-  bfd_vma	p_memsz;		/* Segment size in memory */
-  bfd_vma	p_align;		/* Segment alignment, file & memory */
-};
-
-typedef struct elf_internal_phdr Elf_Internal_Phdr;
-#define elf32_internal_phdr elf_internal_phdr
-#define Elf32_Internal_Phdr Elf_Internal_Phdr
-#define elf64_internal_phdr elf_internal_phdr
-#define Elf64_Internal_Phdr Elf_Internal_Phdr
-
-/* Section header */
-
-typedef struct elf_internal_shdr {
-  unsigned int	sh_name;		/* Section name, index in string tbl */
-  unsigned int	sh_type;		/* Type of section */
-  bfd_vma	sh_flags;		/* Miscellaneous section attributes */
-  bfd_vma	sh_addr;		/* Section virtual addr at execution */
-  bfd_size_type	sh_size;		/* Size of section in bytes */
-  bfd_size_type	sh_entsize;		/* Entry size if section holds table */
-  unsigned long	sh_link;		/* Index of another section */
-  unsigned long	sh_info;		/* Additional section information */
-  file_ptr	sh_offset;		/* Section file offset */
-  unsigned int	sh_addralign;		/* Section alignment */
-
-  /* The internal rep also has some cached info associated with it. */
-  asection *	bfd_section;		/* Associated BFD section.  */
-  PTR		contents;		/* Section contents.  */
-} Elf_Internal_Shdr;
-
-#define elf32_internal_shdr elf_internal_shdr
-#define Elf32_Internal_Shdr Elf_Internal_Shdr
-#define elf64_internal_shdr elf_internal_shdr
-#define Elf64_Internal_Shdr Elf_Internal_Shdr
-
-/* Symbol table entry */
-
-struct elf_internal_sym {
-  bfd_vma	st_value;		/* Value of the symbol */
-  bfd_vma	st_size;		/* Associated symbol size */
-  unsigned long	st_name;		/* Symbol name, index in string tbl */
-  unsigned char	st_info;		/* Type and binding attributes */
-  unsigned char	st_other;		/* No defined meaning, 0 */
-  unsigned short st_shndx;		/* Associated section index */
-};
-
-typedef struct elf_internal_sym Elf_Internal_Sym;
-
-#define elf32_internal_sym elf_internal_sym
-#define elf64_internal_sym elf_internal_sym
-#define Elf32_Internal_Sym Elf_Internal_Sym
-#define Elf64_Internal_Sym Elf_Internal_Sym
-
-/* Note segments */
-
-typedef struct elf_internal_note {
-  unsigned long	namesz;			/* Size of entry's owner string */
-  unsigned long	descsz;			/* Size of the note descriptor */
-  unsigned long	type;			/* Interpretation of the descriptor */
-  char		name[1];		/* Start of the name+desc data */
-} Elf_Internal_Note;
-#define Elf32_Internal_Note	Elf_Internal_Note
-#define elf32_internal_note	elf_internal_note
-
-/* Relocation Entries */
-
-typedef struct elf_internal_rel {
-  bfd_vma	r_offset;	/* Location at which to apply the action */
-  /* This needs to support 64-bit values in elf64.  */
-  bfd_vma	r_info;		/* index and type of relocation */
-} Elf_Internal_Rel;
-
-#define elf32_internal_rel elf_internal_rel
-#define Elf32_Internal_Rel Elf_Internal_Rel
-#define elf64_internal_rel elf_internal_rel
-#define Elf64_Internal_Rel Elf_Internal_Rel
-
-typedef struct elf_internal_rela {
-  bfd_vma	r_offset;	/* Location at which to apply the action */
-  bfd_vma	r_info;		/* Index and Type of relocation */
-  bfd_signed_vma r_addend;	/* Constant addend used to compute value */
-} Elf_Internal_Rela;
-
-#define elf32_internal_rela elf_internal_rela
-#define elf64_internal_rela elf_internal_rela
-#define Elf32_Internal_Rela Elf_Internal_Rela
-#define Elf64_Internal_Rela Elf_Internal_Rela
-
-/* dynamic section structure */
-
-typedef struct elf_internal_dyn {
-  /* This needs to support 64-bit values in elf64.  */
-  bfd_vma d_tag;		/* entry tag value */
-  union {
-    /* This needs to support 64-bit values in elf64.  */
-    bfd_vma	d_val;
-    bfd_vma	d_ptr;
-  } d_un;
-} Elf_Internal_Dyn;
-
-#define elf32_internal_dyn elf_internal_dyn
-#define elf64_internal_dyn elf_internal_dyn
-#define Elf32_Internal_Dyn Elf_Internal_Dyn
-#define Elf64_Internal_Dyn Elf_Internal_Dyn
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/include/elf/mips.h linux/arch/ppc/kernel/include/elf/mips.h
--- v2.1.15/linux/arch/ppc/kernel/include/elf/mips.h	Mon May 27 12:00:57 1996
+++ linux/arch/ppc/kernel/include/elf/mips.h	Thu Jan  1 02:00:00 1970
@@ -1,267 +0,0 @@
-/* MIPS ELF support for BFD.
-   Copyright (C) 1993, 1994 Free Software Foundation, Inc.
-
-   By Ian Lance Taylor, Cygnus Support, <ian@cygnus.com>, from
-   information in the System V Application Binary Interface, MIPS
-   Processor Supplement.
-
-This file is part of BFD, the Binary File Descriptor library.
-
-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.  */
-
-/* This file holds definitions specific to the MIPS ELF ABI.  Note
-   that most of this is not actually implemented by BFD.  */
-
-/* Processor specific flags for the ELF header e_flags field.  */
-
-/* At least one .noreorder directive appears in the source.  */
-#define EF_MIPS_NOREORDER	0x00000001
-
-/* File contains position independent code.  */
-#define EF_MIPS_PIC		0x00000002
-
-/* Code in file uses the standard calling sequence for calling
-   position independent code.  */
-#define EF_MIPS_CPIC		0x00000004
-
-/* Four bit MIPS architecture field.  */
-#define EF_MIPS_ARCH		0xf0000000
-
-/* -mips1 code.  */
-#define E_MIPS_ARCH_1		0x00000000
-
-/* -mips2 code.  */
-#define E_MIPS_ARCH_2		0x10000000
-
-/* -mips3 code.  */
-#define E_MIPS_ARCH_3		0x20000000
-
-/* Processor specific section indices.  These sections do not actually
-   exist.  Symbols with a st_shndx field corresponding to one of these
-   values have a special meaning.  */
-
-/* Defined and allocated common symbol.  Value is virtual address.  If
-   relocated, alignment must be preserved.  */
-#define SHN_MIPS_ACOMMON	0xff00
-
-/* Defined and allocated text symbol.  Value is virtual address.
-   Occur in the dynamic symbol table of Alpha OSF/1 and Irix 5 executables.  */
-#define SHN_MIPS_TEXT		0xff01
-
-/* Defined and allocated data symbol.  Value is virtual address.
-   Occur in the dynamic symbol table of Alpha OSF/1 and Irix 5 executables.  */
-#define SHN_MIPS_DATA		0xff02
-
-/* Small common symbol.  */
-#define SHN_MIPS_SCOMMON	0xff03
-
-/* Small undefined symbol.  */
-#define SHN_MIPS_SUNDEFINED	0xff04
-
-/* Processor specific section types.  */
-
-/* Section contains the set of dynamic shared objects used when
-   statically linking.  */
-#define SHT_MIPS_LIBLIST	0x70000000
-
-/* I'm not sure what this is, but it's used on Irix 5.  */
-#define SHT_MIPS_MSYM		0x70000001
-
-/* Section contains list of symbols whose definitions conflict with
-   symbols defined in shared objects.  */
-#define SHT_MIPS_CONFLICT	0x70000002
-
-/* Section contains the global pointer table.  */
-#define SHT_MIPS_GPTAB		0x70000003
-
-/* Section contains microcode information.  The exact format is
-   unspecified.  */
-#define SHT_MIPS_UCODE		0x70000004
-
-/* Section contains some sort of debugging information.  The exact
-   format is unspecified.  It's probably ECOFF symbols.  */
-#define SHT_MIPS_DEBUG		0x70000005
-
-/* Section contains register usage information.  */
-#define SHT_MIPS_REGINFO	0x70000006
-
-/* Section contains miscellaneous options (used on Irix).  */
-#define SHT_MIPS_OPTIONS	0x7000000d
-
-/* DWARF debugging section (used on Irix 6).  */
-#define SHT_MIPS_DWARF		0x7000001e
-
-/* Events section.  This appears on Irix 6.  I don't know what it
-   means.  */
-#define SHT_MIPS_EVENTS		0x70000021
-
-/* A section of type SHT_MIPS_LIBLIST contains an array of the
-   following structure.  The sh_link field is the section index of the
-   string table.  The sh_info field is the number of entries in the
-   section.  */
-typedef struct
-{
-  /* String table index for name of shared object.  */
-  unsigned long l_name;
-  /* Time stamp.  */
-  unsigned long l_time_stamp;
-  /* Checksum of symbol names and common sizes.  */
-  unsigned long l_checksum;
-  /* String table index for version.  */
-  unsigned long l_version;
-  /* Flags.  */
-  unsigned long l_flags;
-} Elf32_Lib;
-
-/* The l_flags field of an Elf32_Lib structure may contain the
-   following flags.  */
-
-/* Require an exact match at runtime.  */
-#define LL_EXACT_MATCH		0x00000001
-
-/* Ignore version incompatibilities at runtime.  */
-#define LL_IGNORE_INT_VER	0x00000002
-
-/* A section of type SHT_MIPS_CONFLICT is an array of indices into the
-   .dynsym section.  Each element has the following type.  */
-typedef unsigned long Elf32_Conflict;
-
-/* A section of type SHT_MIPS_GPTAB contains information about how
-   much GP space would be required for different -G arguments.  This
-   information is only used so that the linker can provide informative
-   suggestions as to the best -G value to use.  The sh_info field is
-   the index of the section for which this information applies.  The
-   contents of the section are an array of the following union.  The
-   first element uses the gt_header field.  The remaining elements use
-   the gt_entry field.  */
-typedef union
-{
-  struct
-    {
-      /* -G value actually used for this object file.  */
-      unsigned long gt_current_g_value;
-      /* Unused.  */
-      unsigned long gt_unused;
-    } gt_header;
-  struct
-    {
-      /* If this -G argument has been used...  */
-      unsigned long gt_g_value;
-      /* ...this many GP section bytes would be required.  */
-      unsigned long gt_bytes;
-    } gt_entry;
-} Elf32_gptab;
-
-/* The external version of Elf32_gptab.  */
-
-typedef union
-{
-  struct
-    {
-      unsigned char gt_current_g_value[4];
-      unsigned char gt_unused[4];
-    } gt_header;
-  struct
-    {
-      unsigned char gt_g_value[4];
-      unsigned char gt_bytes[4];
-    } gt_entry;
-} Elf32_External_gptab;
-
-/* A section of type SHT_MIPS_REGINFO contains the following
-   structure.  */
-typedef struct
-{
-  /* Mask of general purpose registers used.  */
-  unsigned long ri_gprmask;
-  /* Mask of co-processor registers used.  */
-  unsigned long ri_cprmask[4];
-  /* GP register value for this object file.  */
-  long ri_gp_value;
-} Elf32_RegInfo;
-
-/* The external version of the Elf_RegInfo structure.  */
-typedef struct
-{
-  unsigned char ri_gprmask[4];
-  unsigned char ri_cprmask[4][4];
-  unsigned char ri_gp_value[4];
-} Elf32_External_RegInfo;
-
-/* MIPS ELF .reginfo swapping routines.  */
-extern void bfd_mips_elf32_swap_reginfo_in
-  PARAMS ((bfd *, const Elf32_External_RegInfo *, Elf32_RegInfo *));
-extern void bfd_mips_elf32_swap_reginfo_out
-  PARAMS ((bfd *, const Elf32_RegInfo *, Elf32_External_RegInfo *));
-
-/* Processor specific section flags.  */
-
-/* This section must be in the global data area.  */
-#define SHF_MIPS_GPREL		0x10000000
-
-/* Processor specific program header types.  */
-
-/* Register usage information.  Identifies one .reginfo section.  */
-#define PT_MIPS_REGINFO		0x70000000
-
-/* Processor specific dynamic array tags.  */
-
-/* 32 bit version number for runtime linker interface.  */
-#define DT_MIPS_RLD_VERSION	0x70000001
-
-/* Time stamp.  */
-#define DT_MIPS_TIME_STAMP	0x70000002
-
-/* Checksum of external strings and common sizes.  */
-#define DT_MIPS_ICHECKSUM	0x70000003
-
-/* Index of version string in string table.  */
-#define DT_MIPS_IVERSION	0x70000004
-
-/* 32 bits of flags.  */
-#define DT_MIPS_FLAGS		0x70000005
-
-/* Base address of the segment.  */
-#define DT_MIPS_BASE_ADDRESS	0x70000006
-
-/* Address of .conflict section.  */
-#define DT_MIPS_CONFLICT	0x70000008
-
-/* Address of .liblist section.  */
-#define DT_MIPS_LIBLIST		0x70000009
-
-/* Number of local global offset table entries.  */
-#define DT_MIPS_LOCAL_GOTNO	0x7000000a
-
-/* Number of entries in the .conflict section.  */
-#define DT_MIPS_CONFLICTNO	0x7000000b
-
-/* Number of entries in the .liblist section.  */
-#define DT_MIPS_LIBLISTNO	0x70000010
-
-/* Number of entries in the .dynsym section.  */
-#define DT_MIPS_SYMTABNO	0x70000011
-
-/* Index of first external dynamic symbol not referenced locally.  */
-#define DT_MIPS_UNREFEXTNO	0x70000012
-
-/* Index of first dynamic symbol in global offset table.  */
-#define DT_MIPS_GOTSYM		0x70000013
-
-/* Number of page table entries in global offset table.  */
-#define DT_MIPS_HIPAGENO	0x70000014
-
-/* Address of run time loader map, used for debugging.  */
-#define DT_MIPS_RLD_MAP		0x70000016
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/include/elf/ppc.h linux/arch/ppc/kernel/include/elf/ppc.h
--- v2.1.15/linux/arch/ppc/kernel/include/elf/ppc.h	Mon May 27 12:00:57 1996
+++ linux/arch/ppc/kernel/include/elf/ppc.h	Thu Jan  1 02:00:00 1970
@@ -1,32 +0,0 @@
-/* MIPS PPC support for BFD.
-   Copyright (C) 1995 Free Software Foundation, Inc.
-
-   By Michael Meissner, Cygnus Support, <meissner@cygnus.com>, from information
-   in the System V Application Binary Interface, PowerPC Processor Supplement
-   and the PowerPC Embedded Application Binary Interface (eabi).
-
-This file is part of BFD, the Binary File Descriptor library.
-
-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.  */
-
-/* This file holds definitions specific to the PPC ELF ABI.  Note
-   that most of this is not actually implemented by BFD.  */
-
-/* Processor specific flags for the ELF header e_flags field.  */
-
-#define	EF_PPC_EMB		0x80000000	/* PowerPC embedded flag  */
-
-						/* CYGNUS local bits below */
-#define	EF_PPC_RELOCATABLE	0x00010000	/* PowerPC -mrelocatable flag */
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.1.15/linux/arch/ppc/kernel/irq.c	Mon Jul  8 11:27:42 1996
+++ linux/arch/ppc/kernel/irq.c	Wed Dec 18 10:49:52 1996
@@ -3,6 +3,7 @@
  *
  *	Copyright (C) 1992 Linus Torvalds
  *      Adapted from arch/i386 by Gary Thomas
+ *      Modified by Cort Dougan (cort@cs.nmt.edu) 
  *
  * This file contains the code used by various IRQ handling routines:
  * asking for different IRQ's should be done through these routines
@@ -30,6 +31,24 @@
 #include <asm/irq.h>
 #include <asm/bitops.h>
 
+inline int get_irq_list(char *);
+void check_irq(void);
+void BeBox_CPU1(void);
+void BeBox_state(void);
+int BeBox_irq(void);
+void show_BeBox_state(void);
+void BeBox_enable_irq(int );
+void BeBox_disable_irq(int );
+void BeBox_init_IRQ(void);
+void _do_bottom_half(void);
+static _NOP(void);
+static _delay(void);
+void hard_disk_LED(int state);
+
+
+#define SHOW_IRQ
+#undef  SHOW_IRQ
+
 /*
  * For the BeBox, interrupt numbers are 0..15 for 8259 PIC interrupts
  * and 16..31 for other BeBox motherboard type interrupts.
@@ -52,7 +71,8 @@
 	} else
 	{
 		mask = 1 << (irq_nr & 7);
-		if (irq_nr < 8) {
+		if (irq_nr < 8)
+		{
 			cache_21 |= mask;
 			outb(cache_21,0x21);
 		} else
@@ -120,150 +140,202 @@
 	{ NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }
 };
 
-int get_irq_list(char *buf)
-{
-	int i, len = 0;
-	struct irq_action * action = irq_action;
 
-	for (i = 0;  i < 132;  i++, action++) {
-		if (!action->handler)
-			continue;
-		len += sprintf(buf+len, "%2d: %8d %c %s\n",
-			i, kstat.interrupts[i],
-			(action->flags & SA_INTERRUPT) ? '+' : ' ',
-			action->name);
-	}
-	return len;
-}
-
-asmlinkage void handle_IRQ(struct pt_regs *regs)
+inline int get_irq_list(char *buf)
 {
-	int irq, _irq, s;
+  int i, len = 0;
+  struct irq_action * action = irq_action;
+  
+  for (i = 0;  i < 32;  i++, action++) {
+    if (!action->handler)
+      continue;
+    len += sprintf(buf+len, "%2d: %8d %c %s\n",
+		   i, kstat.interrupts[i],
+		   (action->flags & SA_INTERRUPT) ? '+' : ' ',
+		   action->name);
+  }
+  return len;
+}
+
+inline void
+process_IRQ(int irq, int _irq, struct pt_regs *regs)
+{
+  struct irq_action *action;
+  intr_count++;
+  if (irq < 16)
+  {
+    /* Mask interrupt */
+    if (irq > 7)
+    {
+      cache_A1 |= (1<<(irq-8));
+      outb(cache_A1, 0xA1);
+    } else
+    {
+      cache_21 |= (1<<irq);
+      outb(cache_21, 0x21);
+    }
+  }
+  action = irq + irq_action;
+  kstat.interrupts[irq]++;
+  /* TEMP */
+  /* On the Nobis, the keyboard interrupt "edge" gets lost - why? */
+  if (irq == 0)
+  {
+    static int count;
+    if (++count == 500)
+    {
+      if (inb(0x64) & 0x01)
+      {
 	struct irq_action *action;
-	intr_count++;
-	if (!isBeBox[0] || ((irq = BeBox_irq()) < 16))
-	{
-		/* Figure out IRQ#, etc. */
-		outb(0x0C, 0x20);  /* Poll interrupt controller */
-		irq = _irq = inb(0x20);
-		irq &= 0x07;  /* Caution! */
-		if (irq == 2)
-		{ /* Cascaded interrupt -> IRQ8..IRQ15 */
-			outb(0x0C, 0xA0);
-			irq = (_irq = inb(0xA0)) & 0x07;
-			irq += 8;
-		}
-		/* Mask interrupt & Issue EOI to interrupt controller */
-		if (irq > 7)
-		{
-			cache_A1 |= (1<<(irq-8));
-			outb(cache_A1, 0xA1);
-#if 0			
-			outb(0x20, 0xA0);
-			/* Need to ack cascade controller as well */
-			outb(0x20, 0x20);
-#else			
-			outb(0x60|(irq-8), 0xA0);	/* Specific EOI */
-			/* Need to ack cascade controller as well */
-			outb(0x62, 0x20);
-#endif			
-		} else
-		{
-			cache_21 |= (1<<irq);
-			outb(cache_21, 0x21);
-			outb(0x20, 0x20);
-		}
-	}
-	action = irq + irq_action;
-	kstat.interrupts[irq]++;
-	if (action->handler)
-	{
-		action->handler(irq, action->dev_id, regs);
-	} else
-	{
-		printk("Bogus interrupt #%d/%x, PC: %x\n", irq, _irq, regs->nip);
-	}
-	if (_disable_interrupts() && !action->notified)
-	{
-		action->notified = 1;
-		printk("*** WARNING! %s handler [IRQ %d] turned interrupts on!\n", action->name, irq);
-	}
-	if (irq < 16)
-	{
-		if (!(action->flags & SA_ONESHOT))
-		{
-			/* Re-enable interrupt */
-			if (irq > 7)
-			{
-				cache_A1 &= ~(1<<(irq-8));
-				outb(cache_A1, 0xA1);
-			} else
-			{
-				cache_21 &= ~(1<<irq);
-				outb(cache_21, 0x21);
-			}
-		}
-	} else
+	action = irq_action + 1;  /* Keyboard */
+	printk("Reset KBD, KBSTAT = %x, ELCR = %x/%x, MASK = %x/%x\n",
+	       inb(0x64), inb(0x4D0), inb(0x4D1), cache_21, cache_A1);
+	action->handler(1, action->dev_id, regs);
+      }
+      count = 0;
+    }
+  }
+  if (action->handler)
+  {	
+    action->handler(irq, action->dev_id, regs);
+  } else
+  {
+    printk("Bogus interrupt %d/%x, pc %x regs %x\n",
+	   irq, _irq,regs->nip,regs);
+#if 0
+    printk("BeBox[] = %x/%x\n", isBeBox[0], isBeBox[1]);
+    show_BeBox_state();
+    cnpause();
+#endif
+  }
+  if (_disable_interrupts() && !action->notified)
+  {
+    action->notified = 1;
+    printk("*** WARNING! %s handler [IRQ %d] turned interrupts on!\n",
+	   action->name, irq);
+  }
+  if (irq < 16)
+  {
+    /* Issue EOI to interrupt controller */
+    if (irq > 7)
+    {
+      outb(0xE0|(irq-8), 0xA0);
+      outb(0xE2, 0x20);
+    } else
+    {
+      outb(0xE0|irq, 0x20);
+    }
+    if (!(action->flags & SA_ONESHOT))
+    {
+      /* Re-enable interrupt */
+      if (irq > 7)
+      {
+	cache_A1 &= ~(1<<(irq-8));
+	outb(cache_A1, 0xA1);
+      } else
+      {
+	cache_21 &= ~(1<<irq);
+	outb(cache_21, 0x21);
+      }
+    }
+  } else
+  {
+    BeBox_enable_irq(irq);
+  }
+  intr_count--;
+}
+
+asmlinkage inline void handle_IRQ(struct pt_regs *regs)
+{
+  int irq, _irq, s;
+  struct irq_action *action;
+  static int _ints;
+  
+  if (!isBeBox[0] || ((irq = BeBox_irq()) < 16))
+  {
+    /* Figure out IRQ#, etc. */
+    outb(0x0C, 0x20);  /* Poll interrupt controller */
+    irq = _irq = inb(0x20);
+    irq &= 0x07;  /* Caution! */
+    if (irq == 2)
+    { /* Cascaded interrupt -> IRQ8..IRQ15 */
+      outb(0x0C, 0xA0);
+      irq = (_irq = inb(0xA0)) & 0x07;
+      irq += 8;
+    }
+  }
+  process_IRQ(irq, _irq, regs);
+  
+  /* Sometimes, the cascaded IRQ controller get's "stuck" */
+  if ((irq == 0) && (_ints++ == 100))
+  {
+    _ints = 0;
+    outb(0x0A, 0xA0);  _irq = inb(0xA0);
+    if (_irq & ~cache_A1)
+    {  /* Figure out which IRQs are present */
+      _irq &= ~cache_A1;
+      for (irq = 0;  irq < 7;  irq++)
+      {
+	if (_irq & (1<<irq))
 	{
-		BeBox_enable_irq(irq);
+#if 0
+	  printk("Dropped IRQ #%d\n", irq+8);
+#endif
+	  process_IRQ(irq+8, _irq, regs);
 	}
-	intr_count--;
+      }
+    }
+  }
 }
 
 /*
- * This routine gets called when the SCSI times out on an operation.
- * I don't know why this happens, but every so often it does and it
- * seems to be a problem with the interrupt controller [state].  It
- * happens a lot when there is also network activity (both devices
- * are on the PCI bus with interrupts on the cascaded controller).
- * Re-initializing the interrupt controller [which might lose some
- * pending edge detected interrupts] seems to fix it.
+ * Display current IRQ state
  */
-check_irq()
+
+void
+show_irq_state(void)
+{
+  unsigned char state_21, state_A1;
+  outb(0x0A, 0x20);  state_21 = inb(0x20);
+  outb(0x0A, 0xA0);  state_A1 = inb(0xA0);
+  printk("IRQ State = %x/%x, Edge = %x/%x, Processor = %d\n", state_21, state_A1, inb(0x4D0), inb(0x4D1), _Processor);
+}
+
+/*
+ * Initialize interrupt controllers to a well-known state.
+ */
+
+static void
+reset_int_controllers(void)
 {
-	int s;
-	unsigned char _a0, _a1, _20, _21;
-	if (isBeBox[0])
-	{
-		return;
-	}
-	s = _disable_interrupts();
-	_a1 = inb(0xA1);
-	_21 = inb(0x21);
-	outb(0x0C, 0x20);  _20 = inb(0x20);	
-	outb(0x0C, 0xA0);  _a0 = inb(0xA0);
-#if 0	
-	printk("IRQ 0x20 = %x, 0x21 = %x/%x, 0xA0 = %x, 0xA1 = %x/%x\n",
-		_20, _21, cache_21, _a0, _a1, cache_A1);
-#endif		
-	/* Reset interrupt controller - see if this fixes it! */
 	/* Initialize interrupt controllers */
 	outb(0x11, 0x20); /* Start init sequence */
 	outb(0x40, 0x21); /* Vector base */
 	outb(0x04, 0x21); /* Cascade (slave) on IRQ2 */
 	outb(0x01, 0x21); /* Select 8086 mode */
 	outb(0xFF, 0x21); /* Mask all */
-	outb(0x00, 0x4D0); /* All edge triggered */
 	outb(0x11, 0xA0); /* Start init sequence */
 	outb(0x48, 0xA1); /* Vector base */
 	outb(0x02, 0xA1); /* Cascade (slave) on IRQ2 */
 	outb(0x01, 0xA1); /* Select 8086 mode */
 	outb(0xFF, 0xA1); /* Mask all */
+#if 0
+	outb(0x00, 0x4D0); /* All edge triggered */
 	outb(0xCF, 0x4D1); /* Trigger mode */
+#endif
 	outb(cache_A1, 0xA1);
 	outb(cache_21, 0x21);
 	enable_irq(2);  /* Enable cascade interrupt */
-	_enable_interrupts(s);
 }
 
 int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-	unsigned long irqflags, const char * devname, void *dev_id)
+		unsigned long irqflags, const char * devname, void *dev_id)
 {
 	struct irq_action * action;
 	unsigned long flags;
 
-#if 0
-_printk("Request IRQ #%d, Handler: %x\n", irq, handler);
+#ifdef SHOW_IRQ
+if (irq) printk("Request IRQ #%d, Handler: %x\n", irq, handler);
 #endif
 	if (irq > 15)
 	{
@@ -374,24 +446,33 @@
  
 void init_IRQ(void)
 {
-	int i;
+  int i;
 
-	/* set the clock to 100 Hz */
-	outb_p(0x34,0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
-	outb_p(LATCH & 0xff , 0x40);	/* LSB */
-	outb(LATCH >> 8 , 0x40);	/* MSB */
-	if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL))
-		printk("Unable to get IRQ2 for cascade\n");
-	request_region(0x20,0x20,"pic1");
-	request_region(0xa0,0x20,"pic2");
-
-	/* Set up PCI interrupts */
-	route_PCI_interrupts();
-
-	if (isBeBox[0])
-	{
-		BeBox_init_IRQ();
-	}
+  if ((_get_PVR()>>16) == 1)  /* PPC 601 */
+  { /* Nobis? */
+    reset_int_controllers();
+  }
+#define TIMER0_COUNT 0x40
+#define TIMER_CONTROL 0x43
+  /* set the clock to 100 Hz */
+  outb_p(0x34,TIMER_CONTROL);		/* binary, mode 2, LSB/MSB, ch 0 */
+  outb_p(LATCH & 0xff , TIMER0_COUNT);	/* LSB */
+  outb(LATCH >> 8 , TIMER0_COUNT);	/* MSB */
+  if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL))
+    printk("Unable to get IRQ2 for cascade\n");
+  request_region(0x20,0x20,"pic1");
+  request_region(0xa0,0x20,"pic2");
+  
+  /* Make sure IRQ2 (cascade) interrupt is "level" based */
+  outb(inb(0x4D0)|0x04, 0x4D0); /* IRQ2 level based */
+  
+  /* Set up PCI interrupts */
+  route_PCI_interrupts();
+  
+  if (isBeBox[0])
+  {
+    BeBox_init_IRQ();
+  }
 }
 
 /*
@@ -399,11 +480,18 @@
  * is called whenever an interrupt needs non-interrupt-time service.
  */
 
-_do_bottom_half()
+void _do_bottom_half(void)
 {
-	_enable_interrupts(1);
-	do_bottom_half();
-	_disable_interrupts();
+  _enable_interrupts(1);
+  do_bottom_half();
+  _disable_interrupts();
+}
+
+void hard_disk_LED(int state)
+{
+  if (_Processor == _PROC_IBM) {
+    outb(state, IBM_HDD_LED);
+  }
 }
  
 
@@ -416,6 +504,11 @@
 #define INT_SOURCE	(volatile unsigned long *)(BeBox_IO_page+0x2F0)
 #define CPU_RESET	(volatile unsigned long *)(BeBox_IO_page+0x4F0)
 
+#define _CPU0_INT_MASK	(volatile unsigned long *)(0xA0000000+0x0F0)
+#define _CPU1_INT_MASK	(volatile unsigned long *)(0xA0000000+0x1F0)
+#define _INT_SOURCE	(volatile unsigned long *)(0xA0000000+0x2F0)
+#define _CPU_RESET	(volatile unsigned long *)(0xA0000000+0x4F0)
+
 #define CPU_HRESET	0x20000000
 #define CPU_SRESET	0x40000000
 
@@ -454,12 +547,12 @@
 volatile int CPU1_trace;
 
 static
-_NOP()
+_NOP(void)
 {
 }
 
 static
-_delay()
+_delay(void)
 {
 	int i;
 	for (i = 0;  i < 100;  i++) _NOP();
@@ -486,12 +579,6 @@
 		_delay();
 	}
 printk("CPU #1 running!\n");
-#if 0
-/* Temp - for SCSI */
-	*(unsigned char *)0x81000038 = 0x00;
-	*(unsigned char *)0x8080103C = 0xFF;
-	*(unsigned char *)0x8080100D = 0x32;
-#endif	
 }
 
 void
@@ -516,6 +603,16 @@
 	_enable_interrupts(s);	
 }
 
+void
+show_BeBox_state(void)
+{
+	unsigned long cpu0_int_mask;
+	unsigned long int_state;
+	cpu0_int_mask = (*CPU0_INT_MASK & 0x0FFFFFFC) & ~INT_8259;
+	int_state = cpu0_int_mask & *INT_SOURCE;
+	printk("Ints[%x] = %x, Mask[%x] = %x/%x, State = %x\n", INT_SOURCE, *INT_SOURCE, CPU0_INT_MASK, *CPU0_INT_MASK, cpu0_int_mask, int_state);
+}
+
 int
 BeBox_irq(void)
 {
@@ -542,12 +639,12 @@
 	return (0);
 }
 
-BeBox_state()
+void BeBox_state(void)
 {
 	printk("Int state = %x, CPU0 mask = %x, CPU1 mask = %x\n", *INT_SOURCE, *CPU0_INT_MASK, *CPU1_INT_MASK);
 }
 
-BeBox_CPU1()
+void BeBox_CPU1(void)
 {
 	CPU1_alive++;
 	while (1) ;
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/ld.script-user linux/arch/ppc/kernel/ld.script-user
--- v2.1.15/linux/arch/ppc/kernel/ld.script-user	Mon May 27 12:00:58 1996
+++ linux/arch/ppc/kernel/ld.script-user	Thu Jan  1 02:00:00 1970
@@ -1,75 +0,0 @@
-OUTPUT_ARCH(powerpc)
-SEARCH_DIR(libc); SEARCH_DIR(../sa_test/libc); 
-SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
-/* Do we need any of these for elf?
-   __DYNAMIC = 0;    */
-SECTIONS
-{
-  /* Read-only sections, merged into text segment: */
-  . = + SIZEOF_HEADERS;
-  .interp : { *(.interp) }
-  .hash          : { *(.hash)		}
-  .dynsym        : { *(.dynsym)		}
-  .dynstr        : { *(.dynstr)		}
-  .rel.text      : { *(.rel.text)		}
-  .rela.text     : { *(.rela.text) 	}
-  .rel.data      : { *(.rel.data)		}
-  .rela.data     : { *(.rela.data) 	}
-  .rel.rodata    : { *(.rel.rodata) 	}
-  .rela.rodata   : { *(.rela.rodata) 	}
-  .rel.got       : { *(.rel.got)		}
-  .rela.got      : { *(.rela.got)		}
-  .rel.ctors     : { *(.rel.ctors)	}
-  .rela.ctors    : { *(.rela.ctors)	}
-  .rel.dtors     : { *(.rel.dtors)	}
-  .rela.dtors    : { *(.rela.dtors)	}
-  .rel.bss       : { *(.rel.bss)		}
-  .rela.bss      : { *(.rela.bss)		}
-  .rel.plt       : { *(.rel.plt)		}
-  .rela.plt      : { *(.rela.plt)		}
-  .init          : { *(.init)	} =0
-  .plt : { *(.plt) }
-  .text      :
-  {
-    *(.text)
-  }
-  _etext = .;
-  PROVIDE (etext = .);
-  .fini      : { *(.fini)    } =0
-  .ctors     : { *(.ctors)   }
-  .dtors     : { *(.dtors)   }
-  .rodata    : { *(.rodata)  }
-  .rodata1   : { *(.rodata1) }
-  /* Read-write section, merged into data segment: */
-/*  . = (. + 0x0FFF) & 0xFFFFF000; */
-  .data    :
-  {
-    *(.data)
-    CONSTRUCTORS
-  }
-  .data1   : { *(.data1) }
-  .got           : { *(.got.plt) *(.got) }
-  .dynamic       : { *(.dynamic) }
-  /* We want the small data sections together, so single-instruction offsets
-     can access them all, and initialized data all before uninitialized, so
-     we can shorten the on-disk segment size.  */
-  .sdata     : { *(.sdata) }
-  _edata  =  .;
-  PROVIDE (edata = .);
-  __bss_start = .;
-  .sbss      : { *(.sbss) *(.scommon) }
-  .bss       :
-  {
-   *(.dynbss)
-   *(.bss)
-   *(COMMON)
-  }
-  _end = . ;
-  PROVIDE (end = .);
-  /* These are needed for ELF backends which have not yet been
-     converted to the new style linker.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  /* These must appear regardless of  .  */
-}
-
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- v2.1.15/linux/arch/ppc/kernel/misc.S	Mon Jul  8 11:27:42 1996
+++ linux/arch/ppc/kernel/misc.S	Wed Dec 18 10:49:52 1996
@@ -3,9 +3,12 @@
  * set of code at specific locations, based on function
  */
 
-#include <linux/sys.h>
 #include "ppc_asm.tmpl"
-
+#include <linux/sys.h>
+#include <asm/errno.h>
+#include "ppc_defs.h"
+#include <asm/processor.h>
+		
 /* Keep track of low-level exceptions - rather crude, but informative */	
 #define STATS
 
@@ -23,6 +26,7 @@
 	addze	r3,r3; \
 	stw	r3,0(r2)
 
+/*#ifdef CONFIG_603*/
 /* This instruction is not implemented on the PPC 603 */
 #define tlbia \
 	li	r4,64; \
@@ -31,9 +35,195 @@
 0:	tlbie	r4; \
 	addi	r4,r4,0x1000; \
 	bdnz	0b
+/*#endif*/ /* CONFIG_603*/
 	
 _TEXT()
+#define CPU_CTL     0x80000092
+_GLOBAL(hard_reset_now)
+        mfmsr   r3              /* Disable interrupts */
+        li      r4,0            
+        ori     r4,r4,MSR_EE    
+        andc    r3,r3,r4        
+        ori     r3,r3,MSR_IP    /* Set FLASH/ROM interrupt handlers */
+        sync
+        mtmsr   r3
+        lis     r3,CPU_CTL>>16
+        ori     r3,r3,(CPU_CTL&0xFFFF)
+        lbz     r4,0(r3)        /* Turn on SRESET */
+        li      r5,1
+        andc    r4,r4,r5        /* Make sure we go from 0->1 */
+        stb     r4,0(r3)
+        ori     r4,r4,1
+        stb     r4,0(r3)        /* This should do it! */
+99:     nop
+        b       99b
 
+#if 0	
+/*
+  unsigned short
+     le16_to_cpu(unsigned short val)
+*/
+_GLOBAL(le16_to_cpu)
+	lis	r4,_le_scratch@h
+	ori	r4,r4,_le_scratch@l
+	sth	r3,0(r4)
+	li	r5,0
+	lhbrx	r3,r4,r5
+	blr
+
+_GLOBAL(le32_to_cpu)
+	lis	r4,_le_scratch@h
+	ori	r4,r4,_le_scratch@l
+	stw	r3,0(r4)
+	li	r5,0
+	lwbrx	r3,r4,r5
+	blr
+_GLOBAL(_le_scratch)
+	.space 4
+#endif	
+#if 1
+/*	
+extern int __put_user_8(char, char *);
+extern int __put_user_16(short, short *);
+extern int __put_user_32(long, long *);
+*/
+_GLOBAL(__put_user_8)
+	/* setup exception stuff */
+	lis	r2,current_set@ha
+	lwz	r2,current_set@l(r2)
+	/* increment excount */
+	lwz	r6,TSS+TSS_EXCOUNT(r2)
+	addi	r6,r6,1
+	stw	r6,TSS+TSS_EXCOUNT(r2)
+	/* set expc */
+	lis	r6,1f@h
+	ori	r6,r6,1f@l
+	stw	r6,TSS+TSS_EXPC(r2)
+	
+	stb	r3,0(r4)
+	li	r3,0		/* successful return */
+	li	r6,0
+	stw	r6,TSS+TSS_EXCOUNT(r2)
+	blr
+1:	li	r3,-EFAULT	/* bad access */
+	li	r6,0
+	stw	r6,TSS+TSS_EXCOUNT(r2)
+	blr
+		
+_GLOBAL(__put_user_16)
+	/* setup exception stuff */
+	lis	r2,current_set@ha
+	lwz	r2,current_set@l(r2)
+	/* increment excount */
+	lwz	r6,TSS+TSS_EXCOUNT(r2)
+	addi	r6,r6,1
+	stw	r6,TSS+TSS_EXCOUNT(r2)
+	/* set expc */
+	lis	r6,1f@h
+	ori	r6,r6,1f@l
+	stw	r6,TSS+TSS_EXPC(r2)
+	
+	sth	r3,0(r4)
+	li	r3,0		/* successful return */
+	li	r6,0
+	stw	r6,TSS+TSS_EXCOUNT(r2)
+	blr
+1:	li	r3,-EFAULT	/* bad access */
+	li	r6,0
+	stw	r6,TSS+TSS_EXCOUNT(r2)
+	blr
+
+_GLOBAL(__put_user_32)
+	/* setup exception stuff */
+	lis	r2,current_set@ha
+	lwz	r2,current_set@l(r2)
+	/* increment excount */
+	lwz	r6,TSS+TSS_EXCOUNT(r2)
+	addi	r6,r6,1
+	stw	r6,TSS+TSS_EXCOUNT(r2)
+	/* set expc */
+	lis	r6,1f@h
+	ori	r6,r6,1f@l
+	stw	r6,TSS+TSS_EXPC(r2)
+	
+	stw	r3,0(r4)
+	li	r3,0		/* successful return */
+	li	r6,0
+	stw	r6,TSS+TSS_EXCOUNT(r2)
+	blr
+1:	li	r3,-EFAULT	/* bad access */
+	li	r6,0
+	stw	r6,TSS+TSS_EXCOUNT(r2)
+	blr
+	
+_GLOBAL(__get_user_8)
+	/* setup exception stuff */
+	lis	r2,current_set@ha
+	lwz	r2,current_set@l(r2)
+	/* increment excount */
+	lwz	r6,TSS+TSS_EXCOUNT(r2)
+	addi	r6,r6,1
+	stw	r6,TSS+TSS_EXCOUNT(r2)
+	/* set expc */
+	lis	r6,1f@h
+	ori	r6,r6,1f@l
+	stw	r6,TSS+TSS_EXPC(r2)
+	
+	lbz	r3,0(r4)
+	li	r4,0		/* successful return */
+	li	r6,0
+	stw	r6,TSS+TSS_EXCOUNT(r2)
+	blr
+1:	li	r4,-EFAULT	/* bad access */
+	li	r6,0
+	stw	r6,TSS+TSS_EXCOUNT(r2)
+	blr
+	
+_GLOBAL(__get_user_16)
+	/* setup exception stuff */
+	lis	r2,current_set@ha
+	lwz	r2,current_set@l(r2)
+	/* increment excount */
+	lwz	r6,TSS+TSS_EXCOUNT(r2)
+	addi	r6,r6,1
+	stw	r6,TSS+TSS_EXCOUNT(r2)
+	/* set expc */
+	lis	r6,1f@h
+	ori	r6,r6,1f@l
+	stw	r6,TSS+TSS_EXPC(r2)
+	
+	lhz	r3,0(r4)
+	li	r4,0		/* successful return */
+	li	r6,0
+	stw	r6,TSS+TSS_EXCOUNT(r2)
+	blr
+1:	li	r4,-EFAULT	/* bad access */
+	li	r6,0
+	stw	r6,TSS+TSS_EXCOUNT(r2)
+	blr
+	
+_GLOBAL(__get_user_32)
+	/* setup exception stuff */
+	lis	r2,current_set@ha
+	lwz	r2,current_set@l(r2)
+	/* increment excount */
+	lwz	r6,TSS+TSS_EXCOUNT(r2)
+	addi	r6,r6,1
+	stw	r6,TSS+TSS_EXCOUNT(r2)
+	/* set expc */
+	lis	r6,1f@h
+	ori	r6,r6,1f@l
+	stw	r6,TSS+TSS_EXPC(r2)
+	lwz	r3,0(r4)
+	li	r4,0		/* successful return */
+	li	r6,0
+	stw	r6,TSS+TSS_EXCOUNT(r2)
+	blr
+1:	li	r4,-EFAULT	/* bad access */
+	li	r6,0
+	stw	r6,TSS+TSS_EXCOUNT(r2)
+	blr
+#endif	
 /*
  * Disable interrupts
  *	rc = _disable_interrupts()
@@ -418,7 +608,9 @@
 	
 _GLOBAL(abort)
 	.long	0
-
+	
+/* in include/asm/string.h now -- Cort */
+#if 0
 _GLOBAL(bzero)
 #define bufp r3
 #define len  r4
@@ -447,7 +639,9 @@
 20:	stbu	pat,1(bufp)	/* Store value */
 	bdnz	20b		/* Loop [based on counter] */
 99:	blr
+#endif
 
+	
 _GLOBAL(abs)
 	cmpi	0,r3,0
 	bge	10f
@@ -474,18 +668,22 @@
  * Create a kernel thread
  *   __kernel_thread(flags, fn, arg)
  */
-#if 0
+#if 1
 #define SYS_CLONE 	120
 _GLOBAL(__kernel_thread)
 __kernel_thread:
 	li	r0,SYS_CLONE
 	sc
-	cmpi	0,r3,0
-	bnelr
-	mtlr	r4
-	mr	r3,r5
+	cmpi	0,r3,0		/* parent or child? */
+	bnelr			/* return if parent */
+	mtlr	r4              /* fn addr in lr */
+	mr	r3,r5	        /* load arg and call fn */
 	blr
+	li	0, 1 		/* exit after child exits */
+        li	3, 0
+	sc
 #endif
+	
 /* Why isn't this a) automatic, b) written in 'C'? */	
 	.data
 	.align 4
@@ -655,5 +853,7 @@
 	.long sys_sched_rr_get_interval
 	.long sys_nanosleep
 	.long sys_mremap
-	.space (NR_syscalls-163)*4
+	.long SYMBOL_NAME(sys_setresuid)
+	.long SYMBOL_NAME(sys_getresuid)
+	.space (NR_syscalls-165)*4
 
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/mk_defs.c linux/arch/ppc/kernel/mk_defs.c
--- v2.1.15/linux/arch/ppc/kernel/mk_defs.c	Mon Jul  8 11:27:42 1996
+++ linux/arch/ppc/kernel/mk_defs.c	Wed Dec 18 10:49:52 1996
@@ -25,6 +25,8 @@
 	FILE *out;
 	struct task_struct task;
 	struct thread_struct tss;
+	int i;
+	char s[256];
 	struct pt_regs regs;
 	if (!(out = fopen(argv[1], "w")))
 	{
@@ -62,6 +64,8 @@
 	put_line(out, "MMU_SEG13", (int)&tss.segs[13]-(int)&tss);
 	put_line(out, "MMU_SEG14", (int)&tss.segs[14]-(int)&tss);
 	put_line(out, "MMU_SEG15", (int)&tss.segs[15]-(int)&tss);
+	put_line(out, "TSS_EXPC", (int)&tss.expc-(int)&tss);
+	put_line(out, "TSS_EXCOUNT", (int)&tss.excount-(int)&tss);		
 	put_line(out, "TSS_FPR0", (int)&tss.fpr[0]-(int)&tss);
 	put_line(out, "TSS_FPR1", (int)&tss.fpr[1]-(int)&tss);
 	put_line(out, "TSS_FPR2", (int)&tss.fpr[2]-(int)&tss);
@@ -94,6 +98,7 @@
 	put_line(out, "TSS_FPR29", (int)&tss.fpr[29]-(int)&tss);
 	put_line(out, "TSS_FPR30", (int)&tss.fpr[30]-(int)&tss);
 	put_line(out, "TSS_FPR31", (int)&tss.fpr[31]-(int)&tss);
+	put_line(out, "TSS_FP_USED", (int)&tss.fp_used-(int)&tss);
 	/* Interrupt register frame */
 	put_line(out, "INT_FRAME_SIZE", sizeof(regs));
 	put_line(out, "GPR0", (int)&regs.gpr[0]-(int)&regs);
@@ -128,14 +133,19 @@
 	put_line(out, "GPR29", (int)&regs.gpr[29]-(int)&regs);
 	put_line(out, "GPR30", (int)&regs.gpr[30]-(int)&regs);
 	put_line(out, "GPR31", (int)&regs.gpr[31]-(int)&regs);
-	put_line(out, "FPR0", (int)&regs.fpr[0]-(int)&regs);
-	put_line(out, "FPR1", (int)&regs.fpr[1]-(int)&regs);
-	put_line(out, "FPR2", (int)&regs.fpr[2]-(int)&regs);
-	put_line(out, "FPR3", (int)&regs.fpr[3]-(int)&regs);
+#if 0	
+	for ( i = 0 ; i <= 31 ; i++)
+	{
+	  sprintf(s,"FPR%d",i);
+	  put_line(out, s, (int)&regs.fpr[i]-(int)&regs);
+	}
+#endif
 	put_line(out, "FPCSR", (int)&regs.fpcsr-(int)&regs);
 	/* Note: these symbols include "_" because they overlap with special register names */
 	put_line(out, "_NIP", (int)&regs.nip-(int)&regs);
 	put_line(out, "_MSR", (int)&regs.msr-(int)&regs);
+	/*		put_line(out, "_SRR1", (int)&regs.srr1-(int)&regs);	
+	put_line(out, "_SRR0", (int)&regs.srr0-(int)&regs);	*/
 	put_line(out, "_CTR", (int)&regs.ctr-(int)&regs);
 	put_line(out, "_LINK", (int)&regs.link-(int)&regs);
 	put_line(out, "_CCR", (int)&regs.ccr-(int)&regs);
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- v2.1.15/linux/arch/ppc/kernel/pci.c	Mon May 27 12:00:58 1996
+++ linux/arch/ppc/kernel/pci.c	Wed Dec 18 10:49:52 1996
@@ -145,7 +145,38 @@
    	15	/* Line 4 */
    };
 
-/* #define PCI_DEBUG */
+/* IBM Nobis */
+static char Nobis_pci_IRQ_map[16] =
+  {
+  	0,	/* Slot 0  - unused */
+  	0,	/* Slot 1  - unused */
+  	0,	/* Slot 2  - unused */
+  	0,	/* Slot 3  - unused */
+  	0,	/* Slot 4  - unused */
+  	0,	/* Slot 5  - unused */
+  	0,	/* Slot 6  - unused */
+  	0,	/* Slot 7  - unused */
+  	0,	/* Slot 8  - unused */
+  	0,	/* Slot 9  - unused */
+  	0,	/* Slot 10 - unused */
+  	0,	/* Slot 11 - unused */
+  	3,	/* Slot 12 - SCSI */
+  	0,	/* Slot 13 - unused */
+  	0,	/* Slot 14 - unused */
+  	0,	/* Slot 15 - unused */
+  };
+
+static char Nobis_pci_IRQ_routes[] =
+   {
+   	0,	/* Line 0 - Unused */
+   	13,	/* Line 1 */
+   	13,	/* Line 2 */
+   	13,	/* Line 3 */
+   	13      /* Line 4 */
+   };
+
+#define PCI_DEBUG
+#undef  PCI_DEBUG
 
 #ifdef PCI_STATS
 int PCI_conversions[2];
@@ -459,6 +490,11 @@
 	{
 		Motherboard_map = BeBox_pci_IRQ_map;
 		Motherboard_routes = BeBox_pci_IRQ_routes;
+	} else
+	if ((_get_PVR()>>16) == 1)
+	{ /* Nobis */
+		Motherboard_map = Nobis_pci_IRQ_map;
+		Motherboard_routes = Nobis_pci_IRQ_routes;
 	} else
 	{ /* Motorola hardware */
 		switch (inb(0x800) & 0xF0)
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/port_io.c linux/arch/ppc/kernel/port_io.c
--- v2.1.15/linux/arch/ppc/kernel/port_io.c	Mon May 27 12:00:58 1996
+++ linux/arch/ppc/kernel/port_io.c	Wed Dec 18 10:49:52 1996
@@ -141,3 +141,9 @@
 unsigned short outw_p(unsigned short val,int port) { return (outw(val,port)); }
 unsigned long  outl_p(unsigned long val,int port) { return (outl(val,port)); }
 
+
+/* makes writing to the ibm acorn power management stuff easier -- Cort */
+/* args in forn of PA.B as in tech spec for ibm carolina */
+void ibm_write(unsigned char val,unsigned int port)
+{
+}
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/ppc_asm.tmpl linux/arch/ppc/kernel/ppc_asm.tmpl
--- v2.1.15/linux/arch/ppc/kernel/ppc_asm.tmpl	Mon Jul  8 11:27:43 1996
+++ linux/arch/ppc/kernel/ppc_asm.tmpl	Wed Dec 18 10:49:52 1996
@@ -17,6 +17,8 @@
 #else
 #define _EXTERN(n) n	
 
+#define SYMBOL_NAME(x) x
+
 #define _GLOBAL(n)\
 	.globl n;\
 n:
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/ppc_defs.h linux/arch/ppc/kernel/ppc_defs.h
--- v2.1.15/linux/arch/ppc/kernel/ppc_defs.h	Mon May 27 12:00:58 1996
+++ linux/arch/ppc/kernel/ppc_defs.h	Thu Jan  1 02:00:00 1970
@@ -1,119 +0,0 @@
-/*
- * WARNING! This file is automatically generated - DO NOT EDIT!
- */
-#define STATE 0
-#define COUNTER 4
-#define BLOCKED 16
-#define SIGNAL 12
-#define KERNEL_STACK_PAGE 88
-#define TSS 528
-#define KSP 0
-#define LAST_PC 72
-#define USER_STACK 76
-#define PT_REGS 340
-#define PF_TRACESYS 32
-#define TASK_FLAGS 20
-#define MMU_SEG0 8
-#define MMU_SEG1 12
-#define MMU_SEG2 16
-#define MMU_SEG3 20
-#define MMU_SEG4 24
-#define MMU_SEG5 28
-#define MMU_SEG6 32
-#define MMU_SEG7 36
-#define MMU_SEG8 40
-#define MMU_SEG9 44
-#define MMU_SEG10 48
-#define MMU_SEG11 52
-#define MMU_SEG12 56
-#define MMU_SEG13 60
-#define MMU_SEG14 64
-#define MMU_SEG15 68
-#define TSS_FPR0 80
-#define TSS_FPR1 88
-#define TSS_FPR2 96
-#define TSS_FPR3 104
-#define TSS_FPR4 112
-#define TSS_FPR5 120
-#define TSS_FPR6 128
-#define TSS_FPR7 136
-#define TSS_FPR8 144
-#define TSS_FPR9 152
-#define TSS_FPR10 160
-#define TSS_FPR11 168
-#define TSS_FPR12 176
-#define TSS_FPR13 184
-#define TSS_FPR14 192
-#define TSS_FPR15 200
-#define TSS_FPR16 208
-#define TSS_FPR17 216
-#define TSS_FPR18 224
-#define TSS_FPR19 232
-#define TSS_FPR20 240
-#define TSS_FPR21 248
-#define TSS_FPR22 256
-#define TSS_FPR23 264
-#define TSS_FPR24 272
-#define TSS_FPR25 280
-#define TSS_FPR26 288
-#define TSS_FPR27 296
-#define TSS_FPR28 304
-#define TSS_FPR29 312
-#define TSS_FPR30 320
-#define TSS_FPR31 328
-#define INT_FRAME_SIZE 384
-#define GPR0 56
-#define GPR1 60
-#define GPR2 64
-#define GPR3 68
-#define GPR4 72
-#define GPR5 76
-#define GPR6 80
-#define GPR7 84
-#define GPR8 88
-#define GPR9 92
-#define GPR10 96
-#define GPR11 100
-#define GPR12 104
-#define GPR13 108
-#define GPR14 112
-#define GPR15 116
-#define GPR16 120
-#define GPR17 124
-#define GPR18 128
-#define GPR19 132
-#define GPR20 136
-#define GPR21 140
-#define GPR22 144
-#define GPR23 148
-#define GPR24 152
-#define GPR25 156
-#define GPR26 160
-#define GPR27 164
-#define GPR28 168
-#define GPR29 172
-#define GPR30 176
-#define GPR31 180
-#define FPR0 248
-#define FPR1 256
-#define FPR2 264
-#define FPR3 272
-#define FPCSR 280
-#define _NIP 184
-#define _MSR 188
-#define _CTR 192
-#define _LINK 196
-#define _CCR 200
-#define _XER 204
-#define _DAR 208
-#define _DSISR 212
-#define _HASH1 216
-#define _HASH2 220
-#define _IMISS 224
-#define _DMISS 228
-#define _ICMP 232
-#define _DCMP 236
-#define ORIG_GPR3 240
-#define RESULT 244
-#define TRAP 288
-#define MARKER 292
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- v2.1.15/linux/arch/ppc/kernel/process.c	Mon Jul  8 11:27:43 1996
+++ linux/arch/ppc/kernel/process.c	Wed Dec 18 10:49:52 1996
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1995  Linus Torvalds
  *  Adapted for PowerPC by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu) 
  */
 
 /*
@@ -17,69 +18,140 @@
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
 #include <linux/malloc.h>
-#include <linux/ldt.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
 
 #include <asm/pgtable.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/io.h>
 
 #include <asm/ppc_machine.h>
+int dump_fpu(void);
+void hard_reset_now(void);
+void switch_to(struct task_struct *, struct task_struct *);
+void copy_thread(int,unsigned long,unsigned long,struct task_struct *,
+		 struct pt_regs *);
+void print_backtrace(unsigned long *);
 
 int
-dump_fpu()
+dump_fpu(void)
 {
-	return (1);
+  return (1);
 }
 
+
+/* check to make sure the kernel stack is healthy */
+int check_stack(struct task_struct *tsk)
+{
+  extern unsigned long init_kernel_stack[PAGE_SIZE/sizeof(long)];
+  int ret = 0;
+  int i;
+  
+  /* skip check in init_kernel_task -- swapper */
+  if ( tsk->kernel_stack_page == (unsigned long)&init_kernel_stack )
+    return;
+  /* check bounds on stack -- above/below kstack page */
+  if ( (tsk->tss.ksp-1 & KERNEL_STACK_MASK) != tsk->kernel_stack_page )
+  {
+    printk("check_stack(): not in bounds %s/%d ksp %x/%x\n",
+	   tsk->comm,tsk->pid,tsk->tss.ksp,tsk->kernel_stack_page);
+    ret |= 1;
+  }
+
+  /* check for magic on kstack */
+  if ( *(unsigned long *)(tsk->kernel_stack_page) != STACK_MAGIC)
+  {
+    printk("check_stack(): no magic %s/%d ksp %x/%x magic %x\n",
+	   tsk->comm,tsk->pid,tsk->tss.ksp,tsk->kernel_stack_page,
+	   *(unsigned long *)(tsk->kernel_stack_page));
+    ret |= 2;
+  }
+
+#ifdef KERNEL_STACK_BUFFER
+  /* check extra padding page under kernel stack */
+  for ( i = PAGE_SIZE/sizeof(long) ; i >= 1; i--)
+  {
+    struct pt_regs *regs;
+    
+    if ( *((unsigned long *)(tsk->kernel_stack_page)-1) )
+    {
+      printk("check_stack(): padding touched %s/%d ksp %x/%x value %x/%d\n",
+	     tsk->comm,tsk->pid,tsk->tss.ksp,tsk->kernel_stack_page,
+	     *(unsigned long *)(tsk->kernel_stack_page-i),i*sizeof(long));
+      regs = (struct pt_regs *)(tsk->kernel_stack_page-(i*sizeof(long)));
+      printk("marker %x trap %x\n", regs->marker,regs->trap);
+      print_backtrace((unsigned long *)(tsk->tss.ksp));
+      
+      ret |= 4;
+      break;
+    }
+  }
+#endif
+  
+#if 0
+  if (ret)
+    panic("bad stack");
+#endif
+  return(ret);
+}
+
+
 void
 switch_to(struct task_struct *prev, struct task_struct *new)
 {
 	struct pt_regs *regs;
 	struct thread_struct *new_tss, *old_tss;
 	int s = _disable_interrupts();
-	regs = new->tss.ksp;
+	regs = (struct pt_regs *)(new->tss.ksp);
+#if 1
+	check_stack(prev);
+	check_stack(new);
+#endif
+ 	/* if a process has used fp 15 times, then turn
+	   on the fpu for good otherwise turn it on with the fp
+	   exception handler as needed.
+	   skip this for kernel tasks.
+	            -- Cort */
+	if ( (regs->msr & MSR_FP)&&(regs->msr & MSR_PR)&&(new->tss.fp_used < 15) )
+	{
 #if 0
-	printk("Task %x(%d) -> %x(%d)", current, current->pid, new, new->pid);
-	printk(" - IP: %x, SR: %x, SP: %x\n", regs->nip, regs->msr, regs);
+	  printk("turning off fpu: %s/%d fp_used %d\n",
+		 new->comm,new->pid,new->tss.fp_used);
+#endif
+	  regs->msr = regs->msr & ~MSR_FP;
+	}
+#if 0
+	printk("%s/%d -> %s/%d\n",prev->comm,prev->pid,new->comm,new->pid);
 #endif
 	new_tss = &new->tss;
 	old_tss = &current->tss;
-	current_set[0] = new;	/* FIX ME! */
+	current_set[0] = new;
 	_switch(old_tss, new_tss);
-#if 0
-	printk("Back in task %x(%d)\n", current, current->pid);
-#endif
 	_enable_interrupts(s);
 }
 
-asmlinkage int sys_idle(void)
+asmlinkage int sys_debug(unsigned long r3)
 {
-	if (current->pid != 0)
-		return -EPERM;
-
-	/* endless idle loop with no priority at all */
-	current->counter = -100;
-	for (;;) {
-		schedule();
-	}
+  if ( !strcmp(current->comm,"crashme"))
+    printk("sys_debug(): r3 (syscall) %d\n", r3);
 }
 
-void hard_reset_now(void)
+asmlinkage int sys_idle(void)
 {
-	halt();
+  if (current->pid != 0)
+    return -EPERM;
+  /* endless idle loop with no priority at all */
+  current->counter = -100;
+  for (;;) {
+    schedule();
+  }
 }
 
 void show_regs(struct pt_regs * regs)
 {
-	_panic("show_regs");
 }
 
-/*
- * Free current thread data structures etc..
- */
 void exit_thread(void)
 {
 }
@@ -102,24 +174,28 @@
 	int i;
 	SEGREG *segs;
 	struct pt_regs * childregs;
-#if 0
-printk("copy thread - NR: %d, Flags: %x, USP: %x, Task: %x, Regs: %x\n", nr, clone_flags, usp, p, regs);
-#endif
+	
 	/* Construct segment registers */
-	segs = p->tss.segs;
+	segs = (SEGREG *)(p->tss.segs);
 	for (i = 0;  i < 8;  i++)
 	{
 		segs[i].ks = 0;
 		segs[i].kp = 1;
+#if 0
 		segs[i].vsid = i | (nr << 4);
+#else
+		segs[i].vsid = i | ((nr * 10000) << 4);		
+#endif
 	}
 	if ((p->mm->context == 0) || (p->mm->count == 1))
 	{
-		p->mm->context = (nr<<4);
-#if 0		
-printk("Setting MM[%x] Context = %x Task = %x Current = %x/%x\n", p->mm, p->mm->context, p, current, current->mm);
+#if 0
+	  p->mm->context = ((nr)<<4);
+#else	  
+	  p->mm->context = ((nr*10000)<<4);	  
 #endif
 	}
+	
 	/* Last 8 are shared with kernel & everybody else... */
 	for (i = 8;  i < 16;  i++)
 	{
@@ -127,22 +203,21 @@
 		segs[i].kp = 1;
 		segs[i].vsid = i;
 	}
+	
 	/* Copy registers */
-#ifdef STACK_HAS_TWO_PAGES
-	childregs = ((struct pt_regs *) (p->kernel_stack_page + 2*PAGE_SIZE)) - 2;
-#else	
-	childregs = ((struct pt_regs *) (p->kernel_stack_page + 1*PAGE_SIZE)) - 2;
-#endif	
+	childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 2;
+
 	*childregs = *regs;	/* STRUCT COPY */
 	childregs->gpr[3] = 0;  /* Result from fork() */
-	p->tss.ksp = childregs;
+	p->tss.ksp = (unsigned long)(childregs);
 	if (usp >= (unsigned long)regs)
 	{ /* Stack is in kernel space - must adjust */
-		childregs->gpr[1] = childregs+1;
+		childregs->gpr[1] = (long)(childregs+1);
 	} else
 	{ /* Provided stack is in user space */
 		childregs->gpr[1] = usp;
 	}
+	p->tss.fp_used = 0;
 }
 
 /*
@@ -152,43 +227,12 @@
 {
 }
 
-#if 0
-/*
- * Do necessary setup to start up a newly executed thread.
- */
-void start_thread(struct pt_regs * regs, unsigned long eip, unsigned long esp)
-{
-	regs->nip = eip;
-	regs->gpr[1] = esp;
-	regs->msr = MSR_USER;
-#if 0
-{
-	int len;
-	len = (unsigned long)0x80000000 - esp;
-	if (len > 128) len = 128;
-	printk("Start thread [%x] at PC: %x, SR: %x, SP: %x\n", regs, eip, regs->msr, esp);
-	dump_buf(esp, len);
-	dump_buf(eip, 0x80);
-}
-#endif	
-}
-#endif
 
 asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs)
 {
-	return do_fork(SIGCHLD, regs->gpr[1], regs);
+  return do_fork(SIGCHLD, regs->gpr[1], regs);
 }
 
-/*
- * sys_execve() executes a new program.
- *
- * This works due to the PowerPC calling sequence: the first 6 args
- * are gotten from registers, while the rest is on the stack, so
- * we get a0-a5 for free, and then magically find "struct pt_regs"
- * on the stack for us..
- *
- * Don't do this at home.
- */
 asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
 	unsigned long a3, unsigned long a4, unsigned long a5,
 	struct pt_regs *regs)
@@ -196,11 +240,31 @@
 	int error;
 	char * filename;
 
+	/* getname does it's own verification of the address
+	   when it calls get_max_filename() but
+	   it will assume it's valid if get_fs() == KERNEL_DS
+	   which is always true on the ppc so we check
+	   it here
+	   
+	   this doesn't completely check any of these data structures,
+	   it just makes sure that the 1st long is in a good area
+	   and from there we assume that it's safe then
+	   -- Cort
+	   */
+	/* works now since get_fs/set_fs work properly */
+#if 0
+	if ( verify_area(VERIFY_READ,(void *)a0,1)
+	     && verify_area(VERIFY_READ,(void *)a1,1)
+	     && verify_area(VERIFY_READ,(void *)a2,1)
+	     )
+	{
+	  return -EFAULT;
+	}
+#endif
 	error = getname((char *) a0, &filename);
 	if (error)
 	{
-printk("Error getting EXEC name: %d\n", error);		
-		return error;
+	  return error;
 	}
 	flush_instruction_cache();
 	error = do_execve(filename, (char **) a1, (char **) a2, regs);
@@ -214,10 +278,6 @@
 	return error;
 }
 
-/*
- * This doesn't actually work correctly like this: we need to do the
- * same stack setups that fork() does first.
- */
 asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs)
 {
 	unsigned long clone_flags = p1;
@@ -229,12 +289,13 @@
 void
 print_backtrace(unsigned long *sp)
 {
+#if 0
 	int cnt = 0;
 	printk("... Call backtrace:\n");
-	while (*sp)
+	while (verify_area(VERIFY_READ,sp,sizeof(long)) && *sp)
 	{
 		printk("%08X ", sp[1]);
-		sp = *sp;
+		sp = (unsigned long *)*sp;
 		if (++cnt == 8)
 		{
 			printk("\n");
@@ -242,17 +303,19 @@
 		if (cnt > 32) break;
 	}
 	printk("\n");
+#endif
 }
 
 void
 print_user_backtrace(unsigned long *sp)
 {
+#if 0
 	int cnt = 0;
 	printk("... [User] Call backtrace:\n");
-	while (valid_addr(sp) && *sp)
+	while (verify_area(VERIFY_READ,sp,sizeof(long)) && *sp)
 	{
 		printk("%08X ", sp[1]);
-		sp = *sp;
+		sp = (unsigned long *)*sp;
 		if (++cnt == 8)
 		{
 			printk("\n");
@@ -260,11 +323,23 @@
 		if (cnt > 16) break;
 	}
 	printk("\n");
+#endif
 }
 
 void
 print_kernel_backtrace(void)
 {
+#if 0
 	unsigned long *_get_SP(void);
 	print_backtrace(_get_SP());
+#endif
 }
+inline void start_thread(struct pt_regs * regs,
+                         unsigned long eip, unsigned long esp)
+{
+  regs->nip = eip;
+  regs->gpr[1] = esp;
+  regs->msr = MSR_USER;
+  set_fs(USER_DS);
+}
+
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c
--- v2.1.15/linux/arch/ppc/kernel/ptrace.c	Mon May 27 12:00:58 1996
+++ linux/arch/ppc/kernel/ptrace.c	Wed Dec 18 10:49:52 1996
@@ -7,6 +7,7 @@
  *
  * Adapted from 'linux/arch/m68k/kernel/ptrace.c'
  * PowerPC version by Gary Thomas (gdt@linuxppc.org)
+ * 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
@@ -264,7 +265,7 @@
 	struct vm_area_struct * vma;
 
 	addr &= PAGE_MASK;
-	vma = find_vma(tsk,addr);
+	vma = find_vma(tsk->mm,addr);
 	if (!vma)
 		return NULL;
 	if (vma->vm_start <= addr)
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.1.15/linux/arch/ppc/kernel/setup.c	Mon Jul  8 11:27:43 1996
+++ linux/arch/ppc/kernel/setup.c	Wed Dec 18 10:49:52 1996
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1995  Linus Torvalds
  *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
  */
 
 /*
@@ -17,23 +18,22 @@
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
 #include <linux/malloc.h>
-#include <linux/ldt.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
 #include <linux/tty.h>
 #include <linux/major.h>
 
-#define SIO_CONFIG_RA	0x398
-#define SIO_CONFIG_RD	0x399
-
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
 #include <asm/pgtable.h>
 
 extern unsigned long *end_of_DRAM;
 extern PTE *Hash;
 extern unsigned long Hash_size, Hash_mask;
-
-char sda_root[] = "root=/dev/sda1";
-extern int root_mountflags;
+extern int probingmem;
+unsigned long empty_zero_page[1024];
 
 unsigned char aux_device_present;
 #ifdef CONFIG_BLK_DEV_RAM
@@ -42,6 +42,14 @@
 extern int rd_image_start;	/* starting block # of image */
 #endif
 
+#undef HASHSTATS
+
+extern unsigned long isBeBox[];
+
+/* copy of the residual data */
+RESIDUAL res;
+unsigned long resptr = 0; /* ptr to residual data from hw */
+
 /*
  * The format of "screen_info" is strange, and due to early
  * i386-setup code. This is just enough to make the console
@@ -51,196 +59,351 @@
         -- Cort
  */
 struct screen_info screen_info = {
-	0, 25,			/* orig-x, orig-y */
-	{ 0, 0 },		/* unused */
-	0,			/* orig-video-page */
-	0,			/* orig-video-mode */
-	80,			/* orig-video-cols */
-	0,0,0,			/* ega_ax, ega_bx, ega_cx */
-	25,			/* orig-video-lines */
-	1,			/* orig-video-isVGA */
-	16			/* orig-video-points */
+  0, 25,			/* orig-x, orig-y */
+  { 0, 0 },		/* unused */
+  0,			/* orig-video-page */
+  0,			/* orig-video-mode */
+  80,			/* orig-video-cols */
+  0,0,0,			/* ega_ax, ega_bx, ega_cx */
+  25,			/* orig-video-lines */
+  1,			/* orig-video-isVGA */
+  16			/* orig-video-points */
 };
 
 
 unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
 {
-	return memory_start;
+  return memory_start;
 }
 
-unsigned long find_end_of_memory(void)
+#ifdef HASHSTATS
+unsigned long *hashhits;
+#endif
+
+extern unsigned long _TotalMemory;
+/* find the physical size of RAM and setup hardware hash table */
+unsigned long *find_end_of_memory(void)
 {
-	unsigned char dram_size = inb(0x0804);
-	unsigned long total;
-	extern BAT BAT2;
-printk("DRAM Size = %x\n", dram_size);
-printk("Config registers = %x/%x/%x/%x\n", inb(0x0800), inb(0x0801), inb(0x0802), inb(0x0803));
-	switch (dram_size & 0x07)
-	{
-		case 0:
-			total = 0x08000000;  /* 128M */
-			break;
-		case 1:
-			total = 0x02000000;  /* 32M */
-			break;
-		case 2:
-			total = 0x00800000;  /* 8M */
-			break;
-		case 3:
-			total = 0x00400000;  /* 4M - can't happen! */
-			break;
-		case 4:
-			total = 0x10000000;  /* 256M */
-			break;
-		case 5:
-			total = 0x04000000;  /* 64M */
-			break;
-		case 6:
-			total = 0x01000000;  /* 16M */
-			break;
-		case 7:
-			total = 0x04000000;  /* Can't happen */
-			break;
-	}
-	switch ((dram_size>>4) & 0x07)
-	{
-		case 0:
-			total += 0x08000000;  /* 128M */
-			break;
-		case 1:
-			total += 0x02000000;  /* 32M */
-			break;
-		case 2:
-			total += 0x00800000;  /* 8M */
-			break;
-		case 3:
-			total += 0x00000000;  /* Module not present */
-			break;
-		case 4:
-			total += 0x10000000;  /* 256M */
-			break;
-		case 5:
-			total += 0x04000000;  /* 64M */
-			break;
-		case 6:
-			total += 0x01000000;  /* 16M */
-			break;
-		case 7:
-			total += 0x00000000;  /* Module not present */
-			break;
-	}
-/* TEMP */ total = 0x01000000;
-/* _cnpause();	*/
-/* CAUTION!! This can be done more elegantly! */	
-	if (total < 0x01000000)
-	{
-		Hash_size = HASH_TABLE_SIZE_64K;
-		Hash_mask = HASH_TABLE_MASK_64K;
-	} else
-	{
-		Hash_size = HASH_TABLE_SIZE_128K;
-		Hash_mask = HASH_TABLE_MASK_128K;
-	}
-	switch(total)
-	{
-	  case 0x01000000:
-/*	    BAT2[0][1] = BL_16M;*/
-	    break;
-	  default:
-	    printk("WARNING: setup.c: find_end_of_memory() unknown total ram size %x\n", total);
-	    break;
-	}
-	
-	Hash = (PTE *)((total-Hash_size)+KERNELBASE);
-	bzero(Hash, Hash_size);
-	return ((unsigned long)Hash);
+  extern BAT BAT2;
+  _TotalMemory = res.TotalMemory;
+  
+  if (_TotalMemory == 0 )
+  {
+    printk("Ramsize from residual data was 0 -- Probing for value\n");
+    /* this needs be done differently since the bats actually map
+       addresses beyond physical memory! -- Cort */
+#if 0
+    probingmem = 1;
+    while ( probingmem )
+    {
+	_TotalMemory += 0x00800000; /* 8M */
+	*(unsigned long *)_TotalMemory+KERNELBASE;
+    }
+    _TotalMemory -= 0x00800000;
+#else    
+    _TotalMemory = 0x03000000;
+#endif
+    printk("Ramsize probed to be %dM\n", _TotalMemory>>20);
+  }
+  
+  /* setup BAT2 mapping so that it covers kernelbase to kernelbase+ramsize */
+  switch(_TotalMemory)
+  {
+    case 0x01000000:		/* 16M */
+      BAT2.batu.bl = BL_16M;
+      Hash_size = HASH_TABLE_SIZE_128K;
+      Hash_mask = HASH_TABLE_MASK_128K;
+      break;
+    case 0x00800000:		/* 8M */
+      BAT2.batu.bl = BL_8M;
+      Hash_size = HASH_TABLE_SIZE_64K;
+      Hash_mask = HASH_TABLE_MASK_64K;
+      break;
+    case 0x01800000:		/* 24M */
+    case 0x02000000:		/* 32M */
+      BAT2.batu.bl = BL_32M;
+      Hash_size = HASH_TABLE_SIZE_256K;
+      Hash_mask = HASH_TABLE_MASK_256K;
+      break;
+    case 0x03000000:		/* 48M */
+    case 0x04000000:		/* 64M */
+      BAT2.batu.bl = BL_64M;
+      Hash_size = HASH_TABLE_SIZE_512K;
+      Hash_mask = HASH_TABLE_MASK_512K;
+      break;
+    case 0x05000000:		/* 80M */
+      BAT2.batu.bl = BL_128M;
+      Hash_size = HASH_TABLE_SIZE_1M;
+      Hash_mask = HASH_TABLE_MASK_1M;
+      break;    
+    default:
+      printk("WARNING: setup.c: find_end_of_memory() unknown total ram size %x\n",
+	     _TotalMemory);
+      break;
+  }
+  
+  Hash = (PTE *)((_TotalMemory-Hash_size)+KERNELBASE);
+  bzero(Hash, Hash_size);
+  
+ 
+#ifdef HASHSTATS
+  hashhits = (unsigned long *)Hash - (Hash_size/sizeof(struct _PTE))/2;
+  bzero(hashhits, (Hash_size/sizeof(struct _PTE))/2);
+  return ((unsigned long *)hashhits);
+#else
+  return ((unsigned long *)Hash);
+#endif
 }
 
 int size_memory;
 
-/* #define DEFAULT_ROOT_DEVICE 0x0200	/* fd0 */
-#define DEFAULT_ROOT_DEVICE 0x0801	/* sda1 */
+/*
+ * This is set up by the setup-routine at boot-time
+ */
+#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
+#ifdef CONFIG_APM
+#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+64))
+#endif
+#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
+#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
+#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2))
+#define RAMDISK_FLAGS (*(unsigned short *) (PARAM+0x1F8))
+#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC))
+#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF))
+#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
+#define KERNEL_START (*(unsigned long *) (PARAM+0x214))
+#define INITRD_START (*(unsigned long *) (PARAM+0x218))
+#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
+#define COMMAND_LINE ((char *) (PARAM+2048))
+#define COMMAND_LINE_SIZE 256
+
+#define RAMDISK_IMAGE_START_MASK  	0x07FF
+#define RAMDISK_PROMPT_FLAG		0x8000
+#define RAMDISK_LOAD_FLAG		0x4000	
+
+static char command_line[COMMAND_LINE_SIZE] = { 0, };
+       char saved_command_line[COMMAND_LINE_SIZE];
 
-void setup_arch(char **cmdline_p,
-	unsigned long * memory_start_p, unsigned long * memory_end_p)
+
+void
+setup_arch(char **cmdline_p, unsigned long * memory_start_p,
+	   unsigned long * memory_end_p)
 {
-	extern int _end;
-	extern char cmd_line[];
-	unsigned char reg;
-
-	/* Set up floppy in PS/2 mode */
-	outb(0x09, SIO_CONFIG_RA);
-	reg = inb(SIO_CONFIG_RD);
-	reg = (reg & 0x3F) | 0x40;
-	outb(reg, SIO_CONFIG_RD);
-	outb(reg, SIO_CONFIG_RD);	/* Have to write twice to change! */
-	ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE);
-        /*ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255);*/	/* nfs */
-	aux_device_present = 0xaa;
+  extern int _end;
+  extern char cmd_line[];
+  unsigned char reg;
+  extern int panic_timeout;
+  char inf[512];
+  int i;
+
+  if (isBeBox[0])
+    _Processor = _PROC_Be;
+  else
+  {
+    if (strncmp(res.VitalProductData.PrintableModel,"IBM",3))
+    {
+      _Processor = _PROC_Motorola;
+    }
+    else
+      _Processor = _PROC_IBM;
+  }
+  
+  get_cpuinfo(&inf);
+  printk("%s",inf);
+  
+  /* Set up floppy in PS/2 mode */
+  outb(0x09, SIO_CONFIG_RA);
+  reg = inb(SIO_CONFIG_RD);
+  reg = (reg & 0x3F) | 0x40;
+  outb(reg, SIO_CONFIG_RD);
+  outb(reg, SIO_CONFIG_RD);	/* Have to write twice to change! */
+
+  switch ( _Processor )
+  {
+    case _PROC_IBM:
+        ROOT_DEV = to_kdev_t(0x0301); /* hda1 */
+	break;
+    case _PROC_Motorola:
+        ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
+        break;
+  }
+  aux_device_present = 0xaa;
+
+  panic_timeout = 300;		/* reboot on panic */
+  
+#if 0
+  /* get root via nfs from charon -- was only used for testing */
+  ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255);	/* nfs */
   /*nfsaddrs=myip:serverip:gateip:netmaskip:clientname*/
   strcpy(cmd_line,
-    "nfsaddrs=129.138.6.13:129.138.6.90:129.138.6.1:255.255.255.0:pandora");
-  /*  strcpy(cmd_line,"root=/dev/sda1");*/
-	*cmdline_p = cmd_line;
-	*memory_start_p = (unsigned long) &_end;
-	*memory_end_p = (unsigned long *)end_of_DRAM;
-	size_memory = *memory_end_p - KERNELBASE;  /* Relative size of memory */
+	 "nfsaddrs=129.138.6.101:129.138.6.90:129.138.6.1:255.255.255.0:gordito nfsroot=/joplin/ppc/root/");
+#endif
+  *cmdline_p = cmd_line;
+  *memory_start_p = (unsigned long) &_end;
+  (unsigned long *)*memory_end_p = (unsigned long *)end_of_DRAM;
+  size_memory = *memory_end_p - KERNELBASE;  /* Relative size of memory */
 
 #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);
-  rd_prompt = 0;
-  rd_doload = 0;
+#if 1
+  rd_prompt = 1;
+  rd_doload = 1;
   rd_image_start = 0;
-#endif  	
+#endif
+#endif
+
+  /* Save unparsed command line copy for /proc/cmdline */
+  memcpy(saved_command_line, cmd_line,strlen(cmd_line)+1);
+  printk("Command line: %s\n", cmd_line);
 }
 
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
 {
-	return -EIO;
+  return -EIO;
 }
-#if 0
-extern char builtin_ramdisk_image;
-extern long builtin_ramdisk_size;
 
-void
-builtin_ramdisk_init(void)
-{
-	if ((ROOT_DEV == to_kdev_t(DEFAULT_ROOT_DEVICE)) && (builtin_ramdisk_size != 0))
-	{
-		rd_preloaded_init(&builtin_ramdisk_image, builtin_ramdisk_size);
-	} else
-	{  /* Not ramdisk - assume root needs to be mounted read only */
-		root_mountflags |= MS_RDONLY;
-	}
-}
-#endif
-#define MAJOR(n) (((n)&0xFF00)>>8)
-#define MINOR(n) ((n)&0x00FF)
 
 int
 get_cpuinfo(char *buffer)
 {
-	int pvr = _get_PVR();
-	char *model;
-	switch (pvr>>16)
-	{
-		case 3:
-			model = "603";
-			break;
-		case 4:
-			model = "604";
-			break;
-		case 6:
-			model = "603e";
-			break;
-		case 7:
-			model = "603ev";
-			break;
-		default:
-			model = "unknown";
-			break;
-	}
-	return sprintf(buffer, "PowerPC %s rev %d.%d\n", model, MAJOR(pvr), MINOR(pvr));
+  extern unsigned long loops_per_sec;
+  int i;
+  int pvr = _get_PVR();
+  int len;
+  char *model;
+  unsigned long full = 0, overflow = 0;
+  unsigned int ti;
+  PTE *ptr;  
+  
+  switch (pvr>>16)
+    {
+    case 3:
+      model = "603";
+      break;
+    case 4:
+      model = "604";
+      break;
+    case 6:
+      model = "603e";
+      break;
+    case 7:
+      model = "603ev";
+      break;
+    default:
+      model = "unknown";
+      break;
+    }
+  
+#ifdef __SMP__
+#define CD(X)		(cpu_data[n].X)  
+#else
+#define CD(X) (X)
+#define CPUN 0
+#endif
+  
+  len = sprintf(buffer, "PowerPC %s/%dMHz revision %d.%d %s\n",
+		model,
+		(res.VitalProductData.ProcessorHz > 1024) ?
+		res.VitalProductData.ProcessorHz>>20 :
+		res.VitalProductData.ProcessorHz,
+		MAJOR(pvr), MINOR(pvr),
+		(inb(IBM_EQUIP_PRESENT) & 2) ? "" : "upgrade");
+#if 1
+  if ( res.VitalProductData.PrintableModel[0] )
+    len += sprintf(buffer+len,"%s\n",res.VitalProductData.PrintableModel);
+  
+  len += sprintf(buffer+len,"Bus %dMHz\n",
+		(res.VitalProductData.ProcessorBusHz > 1024) ?
+		res.VitalProductData.ProcessorBusHz>>20 :
+		res.VitalProductData.ProcessorBusHz);
+  
+  /* make sure loops_per_sec has been setup -- ie not at boottime -- Cort */
+  if ( CD(loops_per_sec+2500)/500000 > 0)
+    len += sprintf(buffer+len,
+		   "bogomips: %lu.%02lu\n",
+		   CD(loops_per_sec+2500)/500000,
+		   (CD(loops_per_sec+2500)/5000) % 100);
+
+
+  len += sprintf(buffer+len,"Total Ram: %dM Hash Table: %dkB (%dk buckets)\n",
+	 _TotalMemory>>20, Hash_size>>10,
+	 (Hash_size/(sizeof(PTE)*8)) >> 10);
+  
+  for ( i = 0 ; (res.ActualNumMemories) && (i < MAX_MEMS) ; i++ )
+  {
+    if (i == 0)
+      len += sprintf(buffer+len,"SIMM Banks: ");
+    if ( res.Memories[i].SIMMSize != 0 )
+      len += sprintf(buffer+len,"%d:%dM ",i,
+		     (res.Memories[i].SIMMSize > 1024) ?
+		     res.Memories[i].SIMMSize>>20 :
+		     res.Memories[i].SIMMSize);
+    if ( i == MAX_MEMS-1)
+      len += sprintf(buffer+len,"\n");
+  }
+
+  /* TLB */
+  len += sprintf(buffer+len,"TLB");
+  switch(res.VitalProductData.TLBAttrib)
+  {
+    case CombinedTLB:
+      len += sprintf(buffer+len,": %d entries\n",
+		     res.VitalProductData.TLBSize);
+      break;
+    case SplitTLB:
+      len += sprintf(buffer+len,": (split I/D) %d/%d entries\n",
+		     res.VitalProductData.I_TLBSize,
+		     res.VitalProductData.D_TLBSize);
+      break;
+    case NoneTLB:
+      len += sprintf(buffer+len,": not present\n");
+      break;
+  }
+
+  /* L1 */
+  len += sprintf(buffer+len,"L1: ");
+  switch(res.VitalProductData.CacheAttrib)
+  {
+    case CombinedCAC:
+      len += sprintf(buffer+len,"%dkB LineSize\n",
+		     res.VitalProductData.CacheSize,
+		     res.VitalProductData.CacheLineSize);
+      break;
+    case SplitCAC:
+      len += sprintf(buffer+len,"(split I/D) %dkB/%dkB Linesize %dB/%dB\n",
+		     res.VitalProductData.I_CacheSize,
+		     res.VitalProductData.D_CacheSize,
+		     res.VitalProductData.D_CacheLineSize,
+		     res.VitalProductData.D_CacheLineSize);
+      break;
+    case NoneCAC:
+      len += sprintf(buffer+len,"not present\n");
+      break;
+  }
+
+  /* L2 */
+  if ( (inb(IBM_EQUIP_PRESENT) & 1) == 0) /* l2 present */
+  {
+    int size;
+    
+    len += sprintf(buffer+len,"L2: %dkB %s\n",
+		   ((inb(IBM_L2_STATUS) >> 5) & 1) ? 512 : 256,
+                   (inb(IBM_SYS_CTL) & 64) ? "enabled" : "disabled");
+  }
+  else
+  {
+    len += sprintf(buffer+len,"L2: not present\n");
+  }
+#if 0  
+  len+= sprintf(buffer+len,"Equip register %x\n",
+		inb(IBM_EQUIP_PRESENT));
+  len+= sprintf(buffer+len,"L2Status register %x\n",
+		inb(IBM_L2_STATUS));
+#endif
+#endif
+
+  
+  return len;
 }
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c
--- v2.1.15/linux/arch/ppc/kernel/signal.c	Mon Jul  8 11:27:43 1996
+++ linux/arch/ppc/kernel/signal.c	Wed Dec 18 10:49:52 1996
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Adapted for PowerPC by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu) 
  */
 
 #include <linux/sched.h>
@@ -13,6 +14,7 @@
 #include <linux/wait.h>
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
+#include <asm/uaccess.h>
 
 #define _S(nr) (1<<((nr)-1))
 
@@ -41,14 +43,16 @@
 	}
 }
 
-/*
- * This sets regs->esp even though we don't actually use sigstacks yet..
- */
 asmlinkage int sys_sigreturn(struct pt_regs *regs)
 {
 	struct sigcontext_struct *sc;
 	struct pt_regs *int_regs;
 	int signo;
+#if 1 	
+	if (verify_area(VERIFY_READ, (void *) regs->gpr[1], sizeof(sc))
+	    || (regs->gpr[1] >=KERNELBASE))
+		goto badframe;
+#endif	
 	sc = (struct sigcontext_struct *)regs->gpr[1];
 	current->blocked = sc->oldmask & _BLOCKABLE;
 	int_regs = sc->regs;
@@ -82,6 +86,10 @@
 		regs->nip = sc->handler;
 		return (sc->signal);
 	}
+badframe:
+	/*printk("sys_sigreturn(): badstack regs %x cur %s/%d\n",
+	 regs,current->comm,current->pid);*/
+  do_exit(SIGSEGV);
 }
 
 
@@ -96,144 +104,159 @@
  */
 asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
 {
-	unsigned long mask = ~current->blocked;
-	unsigned long handler_signal = 0;
-	unsigned long *frame = NULL;
-	unsigned long *trampoline;
-	unsigned long *regs_ptr;
-	unsigned long nip = 0;
-	unsigned long signr;
-	int bitno;
-	struct sigcontext_struct *sc;
-	struct sigaction * sa;
-	int s = _disable_interrupts();
-	while ((signr = current->signal & mask)) {
-#if 0
-		signr = ffz(~signr);  /* Compute bit # */
-#else
-		for (bitno = 0;  bitno < 32;  bitno++)
-		{
-			if (signr & (1<<bitno)) break;
-		}
-		signr = bitno;
-#endif
-		current->signal &= ~(1<<signr);  /* Clear bit */
-		sa = current->sig->action + signr;
-		signr++;
-		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
-			current->exit_code = signr;
-			current->state = TASK_STOPPED;
-			notify_parent(current);
-			schedule();
-			if (!(signr = current->exit_code))
-				continue;
-			current->exit_code = 0;
-			if (signr == SIGSTOP)
-				continue;
-			if (_S(signr) & current->blocked) {
-				current->signal |= _S(signr);
-				continue;
-			}
-			sa = current->sig->action + signr - 1;
-		}
-		if (sa->sa_handler == SIG_IGN) {
-			if (signr != SIGCHLD)
-				continue;
-			/* check for SIGCHLD: it's special */
-			while (sys_waitpid(-1,NULL,WNOHANG) > 0)
-				/* nothing */;
-			continue;
-		}
-		if (sa->sa_handler == SIG_DFL) {
-			if (current->pid == 1)
-				continue;
-			switch (signr) {
-			case SIGCONT: case SIGCHLD: case SIGWINCH:
-				continue;
-
-			case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
-				if (current->flags & PF_PTRACED)
-					continue;
-				current->state = TASK_STOPPED;
-				current->exit_code = signr;
-				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
-						SA_NOCLDSTOP))
-					notify_parent(current);
-				schedule();
-				continue;
-
-			case SIGQUIT: case SIGILL: case SIGTRAP:
-			case SIGIOT: case SIGFPE: case SIGSEGV:
-				if (current->binfmt && current->binfmt->core_dump) {
-					if (current->binfmt->core_dump(signr, regs))
-						signr |= 0x80;
-				}
-				/* fall through */
-			default:
-				current->signal |= _S(signr & 0x7f);
-				do_exit(signr);
-			}
-		}
-		/*
-		 * OK, we're invoking a handler
-		 */
-		if ((int)regs->orig_gpr3 >= 0) {
-			if ((int)regs->result == -ERESTARTNOHAND ||
-			   ((int)regs->result == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
-				(int)regs->result = -EINTR;
-		}
-		handler_signal |= 1 << (signr-1);
-		mask &= ~sa->sa_mask;
+  unsigned long mask = ~current->blocked;
+  unsigned long handler_signal = 0;
+  unsigned long *frame = NULL;
+  unsigned long *trampoline;
+  unsigned long *regs_ptr;
+  unsigned long nip = 0;
+  unsigned long signr;
+  int bitno;
+  struct sigcontext_struct *sc;
+  struct sigaction * sa;
+  int s;
+
+  while ((signr = current->signal & mask)) {
+    for (bitno = 0;  bitno < 32;  bitno++)
+    {
+      if (signr & (1<<bitno)) break;
+    }
+    signr = bitno;
+
+    current->signal &= ~(1<<signr);  /* Clear bit */
+    sa = current->sig->action + signr;
+    signr++;
+    if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+      current->exit_code = signr;
+      current->state = TASK_STOPPED;
+      notify_parent(current);
+      schedule();
+      if (!(signr = current->exit_code))
+	continue;
+      current->exit_code = 0;
+      if (signr == SIGSTOP)
+	continue;
+      if (_S(signr) & current->blocked) {
+	current->signal |= _S(signr);
+	continue;
+      }
+      sa = current->sig->action + signr - 1;
+    }
+    if (sa->sa_handler == SIG_IGN) {
+      if (signr != SIGCHLD)
+	continue;
+      /* check for SIGCHLD: it's special */
+      while (sys_waitpid(-1,NULL,WNOHANG) > 0)
+	/* nothing */;
+      continue;
+    }
+    if (sa->sa_handler == SIG_DFL) {
+      if (current->pid == 1)
+	continue;
+      switch (signr) {
+      case SIGCONT: case SIGCHLD: case SIGWINCH:
+	continue;
+
+      case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
+	if (current->flags & PF_PTRACED)
+	  continue;
+	current->state = TASK_STOPPED;
+	current->exit_code = signr;
+	if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
+	      SA_NOCLDSTOP))
+	  notify_parent(current);
+	schedule();
+	continue;
+
+      case SIGQUIT: case SIGILL: case SIGTRAP:
+      case SIGIOT: case SIGFPE: case SIGSEGV:
+	if (current->binfmt && current->binfmt->core_dump) {
+	  if (current->binfmt->core_dump(signr, regs))
+	    signr |= 0x80;
 	}
-	if (!handler_signal)		/* no handler will be called - return 0 */
-	{
-		_enable_interrupts(s);
-		return 0;
-	}
-	nip = regs->nip;
-	frame = (unsigned long *) regs->gpr[1];
-	/* Build trampoline code on stack */
-	frame -= 2;
-	trampoline = frame;
-	trampoline[0] = 0x38007777;  /* li r0,0x7777 */
-	trampoline[1] = 0x44000002;  /* sc           */
-	frame -= sizeof(*regs) / sizeof(long);
-	regs_ptr = frame;
-	memcpy(regs_ptr, regs, sizeof(*regs));
-	signr = 1;
-	sa = current->sig->action;
-	for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
-		if (mask > handler_signal)
-			break;
-		if (!(mask & handler_signal))
-			continue;
-		frame -= sizeof(struct sigcontext_struct) / sizeof(long);
-		sc = (struct sigcontext_struct *)frame;
-		nip = (unsigned long) sa->sa_handler;
+	/* fall through */
+      default:
+	current->signal |= _S(signr & 0x7f);
+	do_exit(signr);
+      }
+    }
+    /* handle signal */
+    
+    if ((int)regs->orig_gpr3 >= 0) {
+      if ((int)regs->result == -ERESTARTNOHAND ||
+	  ((int)regs->result == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
+	(int)regs->result = -EINTR;
+    }
+    handler_signal |= 1 << (signr-1);
+    mask &= ~sa->sa_mask;
+  }
+  if (!handler_signal)		/* no handler will be called - return 0 */
+  {
+    return 0;
+  }
+
+
+  nip = regs->nip;
+  frame = (unsigned long *) regs->gpr[1];
+  /* Build trampoline code on stack */
+  frame -= 2;
+  trampoline = frame;
+#if 1
+  /* verify stack is valid for writing regs struct */
+  if (verify_area(VERIFY_WRITE,(void *)frame, sizeof(long)*2+sizeof(*regs))
+      || (frame >= KERNELBASE ))
+    goto badframe;
+#endif
+  trampoline[0] = 0x38007777;  /* li r0,0x7777 */
+  trampoline[1] = 0x44000002;  /* sc           */
+  frame -= sizeof(*regs) / sizeof(long);
+  regs_ptr = frame;
+  memcpy(regs_ptr, regs, sizeof(*regs));
+  signr = 1;
+  sa = current->sig->action;
+  
+  
+  for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
+    if (mask > handler_signal)
+      break;
+    if (!(mask & handler_signal))
+      continue;
+
+    frame -= sizeof(struct sigcontext_struct) / sizeof(long);
+#if 1
+    if (verify_area(VERIFY_WRITE,(void *)frame,
+		    sizeof(struct sigcontext_struct)/sizeof(long)))
+      goto badframe;
+#endif    
+    sc = (struct sigcontext_struct *)frame;
+    nip = (unsigned long) sa->sa_handler;
 #if 0 /* Old compiler */		
-		nip = *(unsigned long *)nip;
+    nip = *(unsigned long *)nip;
 #endif		
-		if (sa->sa_flags & SA_ONESHOT)
-			sa->sa_handler = NULL;
-		sc->handler = nip;
-		sc->oldmask = current->blocked;
-		sc->regs = (unsigned long)regs_ptr;
-		sc->signal = signr;
-		current->blocked |= sa->sa_mask;
-		regs->gpr[3] = signr;
-		regs->gpr[4] = (unsigned long)regs_ptr;
-	}
-	regs->link = (unsigned long)trampoline;
-	regs->nip = nip;
-	regs->gpr[1] = (unsigned long)sc;
-	/* The DATA cache must be flushed here to insure coherency */
-	/* between the DATA & INSTRUCTION caches.  Since we just */
-	/* created an instruction stream using the DATA [cache] space */
-	/* and since the instruction cache will not look in the DATA */
-	/* cache for new data, we have to force the data to go on to */
-	/* memory and flush the instruction cache to force it to look */
-	/* there.  The following function performs this magic */
-	flush_instruction_cache();
-	_enable_interrupts(s);
-	return 1;
+    if (sa->sa_flags & SA_ONESHOT)
+      sa->sa_handler = NULL;
+    sc->handler = nip;
+    sc->oldmask = current->blocked;
+    sc->regs = (unsigned long)regs_ptr;
+    sc->signal = signr;
+    current->blocked |= sa->sa_mask;
+    regs->gpr[3] = signr;
+    regs->gpr[4] = (unsigned long)regs_ptr;
+  }
+  regs->link = (unsigned long)trampoline;
+  regs->nip = nip;
+  regs->gpr[1] = (unsigned long)sc;
+  /* The DATA cache must be flushed here to insure coherency */
+  /* between the DATA & INSTRUCTION caches.  Since we just */
+  /* created an instruction stream using the DATA [cache] space */
+  /* and since the instruction cache will not look in the DATA */
+  /* cache for new data, we have to force the data to go on to */
+  /* memory and flush the instruction cache to force it to look */
+  /* there.  The following function performs this magic */
+  flush_instruction_cache();
+  return 1;
+badframe:
+  /*  printk("do_signal(): badstack signr %d frame %x regs %x cur %s/%d\n",
+	 signr,frame,regs,current->comm,current->pid);*/
+  do_exit(SIGSEGV);
 }
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/stubs.c linux/arch/ppc/kernel/stubs.c
--- v2.1.15/linux/arch/ppc/kernel/stubs.c	Mon Jul  8 11:27:43 1996
+++ linux/arch/ppc/kernel/stubs.c	Wed Dec 18 10:49:52 1996
@@ -1,49 +1,14 @@
-#include <linux/in.h>
+/*#include <linux/in.h>*/
+#include <linux/autoconf.h>
 
-void sys_iopl(void) { _panic("sys_iopl"); }
-void sys_vm86(void) { _panic("sys_vm86"); }
-void sys_modify_ldt(void) { _panic("sys_modify_ldt"); }
-
-void sys_ipc(void) {_panic("sys_ipc"); }
-void sys_newselect(void) {_panic("sys_newselect"); }
-
-halt()
-{
-	printk("\n...Halt!\n");
-	abort();
-}
-
-_panic(char *msg)
-{
-	printk("Panic: %s\n", msg);
-	printk("Panic: %s\n", msg);
-	abort();
-}
-
-_warn(char *msg)
-{
-	printk("*** Warning: %s UNIMPLEMENTED!\n", msg);
-}
+void sys_iopl(void) { panic("sys_iopl"); }
+void sys_vm86(void) { panic("sys_vm86"); }
+void sys_modify_ldt(void) { panic("sys_modify_ldt"); }
 
+void sys_ipc(void) {panic("sys_ipc"); }
+void sys_newselect(void) {panic("sys_newselect"); }
 
-void
-saved_command_line(void)
-{
-	panic("saved_command_line");
-}
-
-void
-KSTK_EIP(void)
-{
-	panic("KSTK_EIP");
-}
-
-void
-KSTK_ESP(void)
-{
-	panic("KSTK_ESP");
-}
-
+#ifndef CONFIG_MODULES
 void
 scsi_register_module(void)
 {
@@ -55,5 +20,7 @@
 {
 	panic("scsi_unregister_module");
 }
+#endif
+
 
 
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c
--- v2.1.15/linux/arch/ppc/kernel/syscalls.c	Tue May 28 07:46:04 1996
+++ linux/arch/ppc/kernel/syscalls.c	Wed Dec 18 10:49:52 1996
@@ -2,6 +2,7 @@
  * linux/arch/ppc/kernel/sys_ppc.c
  *
  * Adapted from the i386 version by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
  *
  * This file contains various random system calls that
  * have a non-standard calling sequence on the Linux/PPC
@@ -16,6 +17,7 @@
 #include <linux/shm.h>
 #include <linux/stat.h>
 #include <linux/mman.h>
+#include <asm/uaccess.h>
 
 /*
  * sys_pipe() is the normal C calling standard for creating
@@ -47,7 +49,6 @@
 	return do_mmap(file, addr, len, prot, flags, offset);
 }
 
-#if 0
 /*
  * Perform the select(nd, in, out, ex, tv) and mmap() system
  * calls. Linux/i386 didn't use to be able to handle more than
@@ -58,20 +59,24 @@
 {
 	int error;
 	unsigned long flags;
+	long a,b,c,d,e;
 	struct file * file = NULL;
 
 	error = verify_area(VERIFY_READ, buffer, 6*sizeof(long));
 	if (error)
 		return error;
-	flags = get_user(buffer+3);
+	get_user(flags,buffer+3);
 	if (!(flags & MAP_ANONYMOUS)) {
-		unsigned long fd = get_user(buffer+4);
+		unsigned long fd;
+		get_user(fd,buffer+4);
 		if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 			return -EBADF;
 	}
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-	return do_mmap(file, get_user(buffer), get_user(buffer+1),
-		       get_user(buffer+2), flags, get_user(buffer+5));
+	if ( get_user(a,buffer) || get_user(b,buffer+1) ||
+	     get_user(c,buffer+2)||get_user(d,buffer+5)	)
+	  return -EFAULT;
+	return do_mmap(file,a,b,c, flags, d);
 }
 
 extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
@@ -87,13 +92,14 @@
 	n = verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long));
 	if (n)
 		return n;
-	n = get_user(buffer);
-	inp = (fd_set *) get_user(buffer+1);
-	outp = (fd_set *) get_user(buffer+2);
-	exp = (fd_set *) get_user(buffer+3);
-	tvp = (struct timeval *) get_user(buffer+4);
+	get_user(n,buffer);
+	get_user(inp,buffer+1);
+	get_user(outp,buffer+2);
+	get_user(exp,buffer+3);
+	get_user(tvp,buffer+4);
 	return sys_select(n, inp, outp, exp, tvp);
 }
+#if 0
 
 /*
  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- v2.1.15/linux/arch/ppc/kernel/time.c	Mon May 27 12:00:58 1996
+++ linux/arch/ppc/kernel/time.c	Wed Dec 18 10:49:52 1996
@@ -24,6 +24,7 @@
 #include <asm/io.h>
 #include <asm/nvram.h>
 #include <asm/mc146818rtc.h>
+#include <asm/processor.h>
 
 #include <linux/timex.h>
 #include <linux/config.h>
@@ -43,6 +44,13 @@
 	return (inb(NVRAM_DATA));
 }
 
+static inline int CMOS_WRITE(int addr, int val)
+{
+	outb(addr>>8, NVRAM_AS1);
+	outb(addr, NVRAM_AS0);
+	return (outb(val, NVRAM_DATA));
+}
+
 /* This function must be called with interrupts disabled 
  * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
  * 
@@ -138,9 +146,110 @@
 	time_state = TIME_BAD;
 	time_maxerror = 0x70000000;
 	time_esterror = 0x70000000;
+	set_rtc(xtime.tv_sec);
 	sti();
 }
 
+static int      month_days[12] = {
+	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+#define FEBRUARY	2
+#define	STARTOFTIME	1970
+#define SECDAY		86400L
+#define SECYR		(SECDAY * 365)
+#define	leapyear(year)		((year) % 4 == 0)
+#define	days_in_year(a) 	(leapyear(a) ? 366 : 365)
+#define	days_in_month(a) 	(month_days[(a) - 1])
+
+struct _tm
+{
+	int             tm_sec;
+	int             tm_min;
+	int             tm_hour;
+	int             tm_day;
+	int             tm_month;
+	int             tm_year;
+};
+
+static _to_tm(int tim, struct _tm * tm)
+{
+	register int    i;
+	register long   hms, day;
+
+	day = tim / SECDAY;
+	hms = tim % SECDAY;
+
+	/* Hours, minutes, seconds are easy */
+	tm->tm_hour = hms / 3600;
+	tm->tm_min = (hms % 3600) / 60;
+	tm->tm_sec = (hms % 3600) % 60;
+
+	/* Number of years in days */
+	for (i = STARTOFTIME; day >= days_in_year(i); i++)
+		day -= days_in_year(i);
+	tm->tm_year = i;
+
+	/* Number of months in days left */
+	if (leapyear(tm->tm_year))
+		days_in_month(FEBRUARY) = 29;
+	for (i = 1; day >= days_in_month(i); i++)
+		day -= days_in_month(i);
+	days_in_month(FEBRUARY) = 28;
+	tm->tm_month = i;
+
+	/* Days are what is left over (+1) from all that. */
+	tm->tm_day = day + 1;
+}
+
+/*
+ * Set the time into the CMOS
+ */
+static void set_rtc(unsigned long nowtime)
+{
+  int retval = 0;
+  struct _tm tm;
+  unsigned char save_control, save_freq_select;
+  
+  /*if (_Processor != _PROC_IBM) return;*/
+  
+  _to_tm(nowtime, &tm);
+  
+  /* tell the clock it's being set */  
+  save_control = CMOS_MCRTC_READ(MCRTC_CONTROL); 
+  CMOS_MCRTC_WRITE((save_control|MCRTC_SET), MCRTC_CONTROL);
+  /* stop and reset prescaler */  
+  save_freq_select = CMOS_MCRTC_READ(MCRTC_FREQ_SELECT);
+  CMOS_MCRTC_WRITE((save_freq_select|MCRTC_DIV_RESET2), MCRTC_FREQ_SELECT);
+
+  printk("Set RTC H:M:S M/D/Y %d:%02d:%02d %d/%d/%d\n", 
+       tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_month, tm.tm_day, tm.tm_year);
+	if (!(save_control & MCRTC_DM_BINARY) || MCRTC_ALWAYS_BCD) {
+		BIN_TO_BCD(tm.tm_sec);
+		BIN_TO_BCD(tm.tm_min);
+		BIN_TO_BCD(tm.tm_hour);
+		BIN_TO_BCD(tm.tm_month);
+		BIN_TO_BCD(tm.tm_day);
+		BIN_TO_BCD(tm.tm_year);
+	}
+
+	CMOS_MCRTC_WRITE(tm.tm_sec,  MCRTC_SECONDS);
+	CMOS_MCRTC_WRITE(tm.tm_min,  MCRTC_MINUTES);
+	CMOS_MCRTC_WRITE(tm.tm_hour, MCRTC_HOURS);
+	CMOS_MCRTC_WRITE(tm.tm_month,  MCRTC_MONTH);
+	CMOS_MCRTC_WRITE(tm.tm_day,  MCRTC_MINUTES);
+	CMOS_MCRTC_WRITE(tm.tm_year - 1900, MCRTC_MINUTES);
+
+	/* The following flags have to be released exactly in this order,
+	 * otherwise the DS12887 (popular MC146818A clone with integrated
+	 * battery and quartz) will not reset the oscillator and will not
+	 * update precisely 500 ms later. You won't find this mentioned in
+	 * the Dallas Semiconductor data sheets, but who believes data
+	 * sheets anyway ...                           -- Markus Kuhn
+	 */
+	CMOS_MCRTC_WRITE(save_control, MCRTC_CONTROL);
+	CMOS_MCRTC_WRITE(save_freq_select, MCRTC_FREQ_SELECT);
+}
 
 /*
  * In order to set the CMOS clock precisely, set_rtc_mmss has to be
@@ -156,17 +265,19 @@
 	unsigned char save_control, save_freq_select;
 
 #ifdef __powerpc__
+printk("%s: %d - set TOD\n", __FILE__, __LINE__);
 return (-1);  /* Not implemented */
 #else	
 
-	save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
-	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+printk("%s: %d - set TOD\n", __FILE__, __LINE__);
+	save_control = CMOS_MCRTC_READ(MCRTC_CONTROL); /* tell the clock it's being set */
+	CMOS_MCRTC_WRITE((save_control|MCRTC_SET), MCRTC_CONTROL);
 
-	save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
-	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+	save_freq_select = CMOS_MCRTC_READ(MCRTC_FREQ_SELECT); /* stop and reset prescaler */
+	CMOS_MCRTC_WRITE((save_freq_select|MCRTC_DIV_RESET2), MCRTC_FREQ_SELECT);
 
-	cmos_minutes = CMOS_READ(RTC_MINUTES);
-	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+	cmos_minutes = CMOS_MCRTC_READ(MCRTC_MINUTES);
+	if (!(save_control & MCRTC_DM_BINARY) || MCRTC_ALWAYS_BCD)
 		BCD_TO_BIN(cmos_minutes);
 
 	/*
@@ -182,12 +293,12 @@
 	real_minutes %= 60;
 
 	if (abs(real_minutes - cmos_minutes) < 30) {
-		if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		if (!(save_control & MCRTC_DM_BINARY) || MCRTC_ALWAYS_BCD) {
 			BIN_TO_BCD(real_seconds);
 			BIN_TO_BCD(real_minutes);
 		}
-		CMOS_WRITE(real_seconds,RTC_SECONDS);
-		CMOS_WRITE(real_minutes,RTC_MINUTES);
+		CMOS_MCRTC_WRITE(real_seconds,MCRTC_SECONDS);
+		CMOS_MCRTC_WRITE(real_minutes,MCRTC_MINUTES);
 	} else
 		retval = -1;
 
@@ -198,8 +309,8 @@
 	 * the Dallas Semiconductor data sheets, but who believes data
 	 * sheets anyway ...                           -- Markus Kuhn
 	 */
-	CMOS_WRITE(save_control, RTC_CONTROL);
-	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+	CMOS_MCRTC_WRITE(save_control, MCRTC_CONTROL);
+	CMOS_MCRTC_WRITE(save_freq_select, MCRTC_FREQ_SELECT);
 
 	return retval;
 #endif	
@@ -214,27 +325,42 @@
  */
 static inline void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
 {
-	do_timer(regs);
-
-	/*
-	 * If we have an externally synchronized Linux clock, then update
-	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
-	 * called as close as possible to 500 ms before the new second starts.
-	 */
-	if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
-	    xtime.tv_usec > 500000 - (tick >> 1) &&
-	    xtime.tv_usec < 500000 + (tick >> 1))
-	  if (set_rtc_mmss(xtime.tv_sec) == 0)
-	    last_rtc_update = xtime.tv_sec;
-	  else
-	    last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
-#if 0
-	/* As we return to user mode fire off the other CPU schedulers.. this is 
-	   basically because we don't yet share IRQ's around. This message is
-	   rigged to be safe on the 386 - basically its a hack, so don't look
-	   closely for now.. */
-	smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0); 
-#endif	    
+  static int timeints = 0;
+  
+  do_timer(regs);
+
+  /*
+   * If we have an externally synchronized Linux clock, then update
+   * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+   * called as close as possible to 500 ms before the new second starts.
+   */
+  if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
+      xtime.tv_usec > 500000 - (tick >> 1) &&
+      xtime.tv_usec < 500000 + (tick >> 1))
+    if (set_rtc_mmss(xtime.tv_sec) == 0)
+      last_rtc_update = xtime.tv_sec;
+    else
+      last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+
+
+  /* use hard disk LED as a heartbeat instead -- much more useful
+     -- Cort */
+  switch(timeints)
+  {
+    /* act like an actual heart beat -- ie thump-thump-pause... */
+    case 0:
+    case 20:
+      hard_disk_LED(1);
+      break;
+    case 7:
+    case 27:
+      hard_disk_LED(0);
+      break;
+    case 100:
+      timeints = -1;
+      break;
+  }
+  timeints++;
 }
 
 /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
@@ -270,49 +396,52 @@
 
 unsigned long get_cmos_time(void)
 {
-	unsigned int year, mon, day, hour, min, sec;
-	int i;
-
-	if (isBeBox[0])
-	{
-#ifndef __powerpc__	
-	/* The Linux interpretation of the CMOS clock register contents:
-	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-	 * RTC registers show the second which has precisely just started.
-	 * Let's hope other operating systems interpret the RTC the same way.
-	 */
-	/* read RTC exactly on falling edge of update flag */
-	for (i = 0 ; i < 1000000 ; i++)	/* may take up to 1 second... */
-		if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
-			break;
-	for (i = 0 ; i < 1000000 ; i++)	/* must try at least 2.228 ms */
-		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
-			break;
-#endif			
-		do { /* Isn't this overkill ? UIP above should guarantee consistency */
-			sec = CMOS_MCRTC_READ(MCRTC_SECONDS);
-			min = CMOS_MCRTC_READ(MCRTC_MINUTES);
-			hour = CMOS_MCRTC_READ(MCRTC_HOURS);
-			day = CMOS_MCRTC_READ(MCRTC_DAY_OF_MONTH);
-			mon = CMOS_MCRTC_READ(MCRTC_MONTH);
-			year = CMOS_MCRTC_READ(MCRTC_YEAR);
-		} while (sec != CMOS_MCRTC_READ(MCRTC_SECONDS));
-	} else
+  unsigned int year, mon, day, hour, min, sec;
+  int i;
+  
+  if (_Processor == _PROC_IBM)
+  {
+    do { /* Isn't this overkill ? UIP above should guarantee consistency */
+      sec = CMOS_MCRTC_READ(MCRTC_SECONDS);
+      min = CMOS_MCRTC_READ(MCRTC_MINUTES);
+      hour = CMOS_MCRTC_READ(MCRTC_HOURS);
+      day = CMOS_MCRTC_READ(MCRTC_DAY_OF_MONTH);
+      mon = CMOS_MCRTC_READ(MCRTC_MONTH);
+      year = CMOS_MCRTC_READ(MCRTC_YEAR);
+    } while (sec != CMOS_MCRTC_READ(MCRTC_SECONDS));
+    BCD_TO_BIN(sec);
+    BCD_TO_BIN(min);
+    BCD_TO_BIN(hour);
+    BCD_TO_BIN(day);
+    BCD_TO_BIN(mon);
+    BCD_TO_BIN(year);
+  } else
+    if (_Processor == _PROC_Be)
+      {
+	do { /* Isn't this overkill ? UIP above should guarantee consistency */
+	  sec = CMOS_MCRTC_READ(MCRTC_SECONDS);
+	  min = CMOS_MCRTC_READ(MCRTC_MINUTES);
+	  hour = CMOS_MCRTC_READ(MCRTC_HOURS);
+	  day = CMOS_MCRTC_READ(MCRTC_DAY_OF_MONTH);
+	  mon = CMOS_MCRTC_READ(MCRTC_MONTH);
+	  year = CMOS_MCRTC_READ(MCRTC_YEAR);
+	} while (sec != CMOS_MCRTC_READ(MCRTC_SECONDS));
+      } else
 	{ /* Motorola PowerStack etc. */
-		do { /* Isn't this overkill ? UIP above should guarantee consistency */
-			sec = CMOS_READ(RTC_SECONDS);
-			min = CMOS_READ(RTC_MINUTES);
-			hour = CMOS_READ(RTC_HOURS);
-			day = CMOS_READ(RTC_DAY_OF_MONTH);
-			mon = CMOS_READ(RTC_MONTH);
-			year = CMOS_READ(RTC_YEAR);
-		} while (sec != CMOS_READ(RTC_SECONDS));
-		BCD_TO_BIN(sec);
-		BCD_TO_BIN(min);
-		BCD_TO_BIN(hour);
-		BCD_TO_BIN(day);
-		BCD_TO_BIN(mon);
-		BCD_TO_BIN(year);
+	  do { /* Isn't this overkill ? UIP above should guarantee consistency */
+	    sec = CMOS_READ(RTC_SECONDS);
+	    min = CMOS_READ(RTC_MINUTES);
+	    hour = CMOS_READ(RTC_HOURS);
+	    day = CMOS_READ(RTC_DAY_OF_MONTH);
+	    mon = CMOS_READ(RTC_MONTH);
+	    year = CMOS_READ(RTC_YEAR);
+	  } while (sec != CMOS_READ(RTC_SECONDS));
+	  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 0	
 printk("CMOS TOD - M/D/Y H:M:S = %d/%d/%d %d:%02d:%02d\n", mon, day, year, hour, min, sec);
@@ -324,13 +453,13 @@
 
 void time_init(void)
 {
-	void (*irq_handler)(int, struct pt_regs *);
-	xtime.tv_sec = get_cmos_time();
-	xtime.tv_usec = 0;
-
-	/* If we have the CPU hardware time counters, use them */
-	irq_handler = timer_interrupt;
-	if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL) != 0)
-		panic("Could not allocate timer IRQ!");
+  void (*irq_handler)(int, struct pt_regs *);
+  xtime.tv_sec = get_cmos_time();
+  xtime.tv_usec = 0;
+  
+  /* If we have the CPU hardware time counters, use them */
+  irq_handler = timer_interrupt;
+  if (request_irq(TIMER_IRQ, irq_handler, 0, "timer", NULL) != 0)
+    panic("Could not allocate timer IRQ!");
 }
 
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c
--- v2.1.15/linux/arch/ppc/kernel/traps.c	Mon Jul  8 11:27:43 1996
+++ linux/arch/ppc/kernel/traps.c	Wed Dec 18 10:49:52 1996
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1995  Gary Thomas
  *  Adapted for PowerPC by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
  */
 
 /*
@@ -17,7 +18,6 @@
 #include <linux/unistd.h>
 #include <linux/ptrace.h>
 #include <linux/malloc.h>
-#include <linux/ldt.h>
 #include <linux/user.h>
 #include <linux/a.out.h>
 
@@ -40,44 +40,62 @@
 void
 _exception(int signr, struct pt_regs *regs)
 {
-/*	dump_regs(regs);*/
-	force_sig(signr, current);
-	if (!user_mode(regs))
-	{
-		printk("Failure in kernel at PC: %x, MSR: %x\n", regs->nip, regs->msr);
-		while (1) ;
-	}
+  /*	dump_regs(regs);*/
+  force_sig(signr, current);
+  if (!user_mode(regs))
+    {
+      printk("Failure in kernel at PC: %x, MSR: %x\n", regs->nip, regs->msr);
+      while (1) ;
+    }
 }
 
 MachineCheckException(struct pt_regs *regs)
 {
-/*	printk("Machine check at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);*/
-	_exception(SIGSEGV, regs);	
+  printk("Machine check at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);
+  _exception(SIGSEGV, regs);	
 }
 
 ProgramCheckException(struct pt_regs *regs)
 {
-/*	printk("Program check at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);*/
-	if (current->flags & PF_PTRACED)
-	{
-		_exception(SIGTRAP, regs);
-	} else
-	{
-		_exception(SIGILL, regs);
-	}
+#if 0
+  printk("Program check at PC: %x[%x], SR: %x\n",
+	 regs->nip, va_to_phys(regs->nip), regs->msr);
+  #endif
+  if (current->flags & PF_PTRACED)
+  {
+    _exception(SIGTRAP, regs);
+  } else
+  {
+    _exception(SIGILL, regs);
+  }
 }
 
 SingleStepException(struct pt_regs *regs)
 {
-/*	printk("Single step at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);*/
 	regs->msr &= ~MSR_SE;  /* Turn off 'trace' bit */
 	_exception(SIGTRAP, regs);	
 }
 
 FloatingPointCheckException(struct pt_regs *regs)
 {
-/*	printk("Floating point check at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);*/
-	_exception(SIGFPE, regs);	
+  /* if fpu already on -- then exception was generated by an error */
+  if ( (unsigned long)(regs->msr) & (unsigned long)MSR_FP )
+  {
+    _exception(SIGFPE, regs);
+    return 0;
+  }
+
+#if 0
+  printk("fpu off -- turning on: %s pc %x fpscr %x msr %x ksp %x r1 %x\n",
+	 current->comm,regs->nip,regs->fpcsr,regs->msr,regs,regs->gpr[1]);
+#endif
+
+  /* if the fpu is off then turn it on and return */
+  regs->msr |= MSR_FP;
+  current->tss.fp_used++;
+  /* tells return_from_int to restore fp regs since fp was turned on
+     see head.S -- Cort */  
+  return MSR_FP;		
 }
 
 AlignmentException(struct pt_regs *regs)
@@ -88,11 +106,20 @@
 	_exception(SIGBUS, regs);	
 }
 
-bad_stack(struct pt_regs *regs)
+
+/* see CHECK_STACK macro in head.S for argument definitions */
+bad_stack(unsigned int r3, unsigned int r4, unsigned int r5, unsigned int r6)
 {
-/*	printk("Kernel stack overflow at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);
-	dump_regs(regs);*/
-	while (1) ;
+  /* r6 (was r1) kernel stack pointer */
+  /* r5 (was r2) kernel stack page */
+  /* r4 kernel stack magic */
+  /* r3 stack magic or ksp masked to page boundary */
+  printk("bad_stack(): Kernel stack bad.\n");
+  printk("ksp %x kpage %x stack magic %x r3 %x\n",
+	 r6,r5,r4,r3);
+  printk("current: %s/%d\n",
+	 current->comm,current->pid);
+  while(1);
 }
 
 dump_regs(struct pt_regs *regs)
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/usercpy.c linux/arch/ppc/kernel/usercpy.c
--- v2.1.15/linux/arch/ppc/kernel/usercpy.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/ppc/kernel/usercpy.c	Wed Dec 18 10:49:52 1996
@@ -0,0 +1,116 @@
+#include <linux/types.h>
+#include <asm/string.h>
+#include <asm/errno.h>
+#include <linux/sched.h>
+
+/*
+ * bad data accesses from these functions should be handled specially 
+ * since they are to user areas and may or may not be valid.
+ * on error -EFAULT should be returned.  -- Cort
+ */
+int __copy_tofrom_user_failure(void)
+{
+  current->tss.excount = 0;
+  return -EFAULT;
+}
+
+int __copy_tofrom_user(unsigned long to, unsigned long from, int size)
+{
+  /* setup exception handling stuff */
+  current->tss.excount++;
+  current->tss.expc = (unsigned long )__copy_tofrom_user_failure;
+  
+  if (memcpy( (void *)to, (void *)from, (size_t) size) == -EFAULT )
+  {
+    /* take down exception handler stuff */
+    current->tss.excount = 0;
+    return -EFAULT;
+  }
+  current->tss.excount = 0;
+  return 0; /* successful return */
+}
+
+/* Just like strncpy except in the return value:
+ *
+ * -EFAULT       if an exception occurs before the terminator is copied.
+ * N             if the buffer filled.
+ *
+ * Otherwise the length of the string is returned.
+ */
+asmlinkage int __strncpy_from_user_failure(void)
+{
+  current->tss.excount = 0;
+  return -EFAULT;
+}
+
+int __strncpy_from_user(unsigned long dest, unsigned long src, int count)
+{
+  int i = 0;
+  /* setup exception handling stuff */
+  current->tss.excount++;
+  current->tss.expc = (unsigned long )__strncpy_from_user_failure;
+  
+  while ( i != count )
+  {
+    *(char *)(dest+i) = *(char *)(src+i);
+    if ( *(char *)(src+i) == 0 )
+    {
+      return i;
+    }
+    i++;
+  }
+  *(char *)(dest+i) = (char)0;
+  /* take down exception handler stuff */
+  current->tss.excount = 0;
+  return i;
+}
+
+int __clear_user_failure(void)
+{
+  current->tss.excount = 0;
+  return -EFAULT;
+}
+int __clear_user(unsigned long addr, int size)
+{
+  /* setup exception handling stuff */
+  current->tss.excount++;
+  current->tss.expc = (unsigned long )__clear_user_failure;
+
+  if ((int)memset((void *)addr,(int)0, (__kernel_size_t)size) == -EFAULT )
+    {
+      /* take down exception handler stuff */
+      current->tss.excount = 0;
+      return -EFAULT;
+    }
+  /* take down exception handler stuff */
+  current->tss.excount = 0;
+  return size;
+}
+
+/*
+ * Return the length of the string including the NUL terminator
+ * (strlen+1) or zero if an error occured.
+ */
+size_t strlen_user_failure(void)
+{
+  current->tss.excount = 0;
+  return -EFAULT;
+}
+size_t strlen_user(char * s)
+{
+  size_t i;
+  /* setup exception handling stuff */
+  current->tss.excount++;
+  current->tss.expc = (unsigned long )strlen_user_failure;
+  
+  i = strlen(s)+1;
+  
+  if ( i == -EFAULT)
+    return -EFAULT;
+  
+  /* take down exception handler stuff */
+  current->tss.excount = 0;
+
+  return(i);
+}
+
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/lib/Makefile linux/arch/ppc/lib/Makefile
--- v2.1.15/linux/arch/ppc/lib/Makefile	Mon May 27 12:00:58 1996
+++ linux/arch/ppc/lib/Makefile	Wed Dec 18 10:49:52 1996
@@ -4,6 +4,7 @@
 
 L_TARGET = lib.o
 L_OBJS  = checksum.o cksum_support.o
+CC = gcc -I$(TOPDIR)/include
 
 ${L_TARGET}: $(L_OBJS)
 	$(LD) -r -o ${L_TARGET} $(L_OBJS)
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/lib/checksum.c linux/arch/ppc/lib/checksum.c
--- v2.1.15/linux/arch/ppc/lib/checksum.c	Mon May 27 12:00:58 1996
+++ linux/arch/ppc/lib/checksum.c	Wed Dec 18 10:49:52 1996
@@ -127,7 +127,7 @@
  *	Fold a partial checksum without adding pseudo headers
  */
 
-unsigned short csum_fold(unsigned int sum)
+unsigned int csum_fold(unsigned int sum)
 {
 	sum = (sum & 0xffff) + (sum >> 16);
 	sum = (sum & 0xffff) + (sum >> 16);
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c
--- v2.1.15/linux/arch/ppc/mm/fault.c	Mon Jul  8 11:27:43 1996
+++ linux/arch/ppc/mm/fault.c	Wed Dec 18 10:49:52 1996
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
  *  Ported to PPC by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu) 
  */
 
 #include <linux/config.h>
@@ -22,164 +23,71 @@
 
 extern void die_if_kernel(char *, struct pt_regs *, long);
 extern void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
+void new_page_fault(unsigned long address, unsigned long code, unsigned long text,
+		    struct pt_regs *regs);
+
 
 #undef SHOW_FAULTS
 #undef NOISY_INSTRFAULT
 #undef NOISY_DATAFAULT
 
+unsigned int probingmem = 0;
 #define NEWMM 1
 
-void
-DataAccessException(struct pt_regs *regs)
+void new_page_fault(unsigned long address, unsigned long ppc_code,
+		    unsigned long text, struct pt_regs *regs)
 {
-  pgd_t *dir;
-  pmd_t *pmd;
-  pte_t *pte;
-  int tries, mode = 0;
-  
-#ifdef NOISY_DATAFAULT
-  printk("Data fault on %x\n",regs->dar);
-#endif
-  
-  if (user_mode(regs)) mode |= 0x04;
-  if (regs->dsisr & 0x02000000) mode |= 0x02;  /* Load/store */
-  if (regs->dsisr & 0x08000000) mode |= 0x01;  /* Protection violation */
-  if (mode & 0x01)
-  {
-#ifdef NOISY_DATAFAULT
-    printk("Write Protect fault\n ");
-#endif
-    do_page_fault(regs, regs->dar, mode);
-#ifdef NOISY_DATAFAULT    
-    printk("Write Protect fault handled\n");
-#endif
-    return;
-  }
-
-    
-  for (tries = 0;  tries < 1;  tries++)
-  {
-    dir = pgd_offset(current->mm, regs->dar & PAGE_MASK);
-    if (dir)
-    {
-      pmd = pmd_offset(dir, regs->dar & PAGE_MASK);
-      if (pmd && pmd_present(*pmd))
-      {
-	pte = pte_offset(pmd, regs->dar & PAGE_MASK);
-	if (pte && pte_present(*pte))
-	{
-#if NOISY_DATAFAULT
-	  printk("Page mapped - PTE: %x[%x]\n", pte, *(long *)pte);
-#endif
-	  MMU_hash_page(&current->tss, regs->dar & PAGE_MASK, pte);
-	  /*MMU_hash_page2(current->mm, regs->dar & PAGE_MASK, pte);*/
-	  return;
-	}
-      }
-    } else
-    {
-#if NOISY_DATAFAULT
-      printk("No PGD\n");      
-#endif 
-    }
-    do_page_fault(regs, regs->dar, mode);
-  }
-}
+  struct vm_area_struct * vma;
+  struct mm_struct *mm = current->mm;
 
-void
-InstructionAccessException(struct pt_regs *regs)
-{
+  int intel_code = 0;
   pgd_t *dir;
   pmd_t *pmd;
   pte_t *pte;
-  int tries, mode = 0;
   
-#if NOISY_INSTRFAULT
-  printk("Instr fault on %x\n",regs->dar);
-#endif
-
-#ifdef NEWMM
-  if (!user_mode(regs))
-  {
-    
-    panic("InstructionAcessException in kernel mode. PC %x addr %x",
-	  regs->nip, regs->dar);
+  /*
+   *	bit 0 == 0 means no page found, 1 means protection fault
+   *	bit 1 == 0 means read, 1 means write
+   *	bit 2 == 0 means kernel, 1 means user-mode
+   */
+  if (user_mode(regs)) intel_code |= 0x04;
+  if (!text && (ppc_code & 0x02000000)) intel_code |= 0x02;  /* Load/store */
+  if (!text && (ppc_code & 0x08000000))
+  {
+    intel_code |= 0x01;  /* prot viol */
+    goto do_page;
   }
-#endif
-  if (user_mode(regs)) mode |= 0x04;
-  if (regs->dsisr & 0x02000000) mode |= 0x02;  /* Load/store */
-  if (regs->dsisr & 0x08000000) mode |= 0x01;  /* Protection violation */
   
-  if (mode & 0x01)
-  {
-    do_page_fault(regs, regs->dar, mode); 
-    return;
-  }
-  for (tries = 0;  tries < 1;  tries++)
+  dir = pgd_offset(mm, address & PAGE_MASK);
+  if (dir)
   {
-    dir = pgd_offset(current->mm, regs->dar & PAGE_MASK);
-    if (dir)
+    pmd = pmd_offset(dir, address & PAGE_MASK);
+    if (pmd && pmd_present(*pmd))
     {
-      pmd = pmd_offset(dir, regs->dar & PAGE_MASK); 
-      if (pmd && pmd_present(*pmd))
+      pte = pte_offset(pmd, address & PAGE_MASK);
+      if (pte && pte_present(*pte))
       {
- 	pte = pte_offset(pmd, regs->dar & PAGE_MASK); 
-	if (pte && pte_present(*pte))
-	  {
-	    
-	    MMU_hash_page(&current->tss, regs->dar & PAGE_MASK, pte); 
-	    /*	  MMU_hash_page2(current->mm, regs->dar & PAGE_MASK, pte);*/
-	    return;
-	  }
+	MMU_hash_page(&current->tss, address & PAGE_MASK, pte);
+	return;
       }
-    } else
-      {
-      }
-    do_page_fault(regs, regs->dar, mode);
+    }
   }
-}
-
-
-/*
- * This routine handles page faults.  It determines the address,
- * and the problem, and then passes it off to one of the appropriate
- * routines.
- *
- * The error_code parameter just the same as in the i386 version:
- *
- *	bit 0 == 0 means no page found, 1 means protection fault
- *	bit 1 == 0 means read, 1 means write
- *	bit 2 == 0 means kernel, 1 means user-mode
- */
-void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code)
-{
-  struct vm_area_struct * vma;
-  unsigned long page;
 
-  vma = find_vma(current, address);
+do_page:
+  down(&mm->mmap_sem);
+  vma = find_vma(current->mm, address);
   if (!vma)
-  {
     goto bad_area;
-  }
-
-  if (vma->vm_start <= address){
+  if (vma->vm_start <= address)
     goto good_area;
-  }
   if (!(vma->vm_flags & VM_GROWSDOWN))
-  {
     goto bad_area;
-  }
-  if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur)
-  {
+  if (expand_stack(vma, address))
     goto bad_area;
-  }
-  vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
-
-  vma->vm_start = (address & PAGE_MASK);
   
 good_area:
   /* a write */
-  if (error_code & 2) {
+  if (intel_code & 2) {
     if (!(vma->vm_flags & VM_WRITE))
     {
       goto bad_area;
@@ -187,32 +95,49 @@
   /* a read */
   } else {
     /* protection fault */
-    if (error_code & 1)
+    if (intel_code & 1)
     {
+      printk("prot fault\n");
       goto bad_area;
     }
     if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
     {
+      printk("no read or exec\n");      
       goto bad_area; 
     }
   }
-  handle_mm_fault(vma, address, error_code & 2);
-  flush_page(address);  /* Flush & Invalidate cache - note: address is OK now */  
+  handle_mm_fault(vma, address, intel_code & 2);
+  up(&mm->mmap_sem);  flush_page(address);  /* Flush & Invalidate cache - note: address is OK now */  
   return;
   
 bad_area:
+  up(&mm->mmap_sem);
+
+  /* Did we have an exception handler installed? */
+  if(current->tss.excount != 0) {
+    if(user_mode(regs)) {
+      printk("Exception signalled from user mode!\n");
+    } else {
+#if 0      
+      printk("Exception from kernel mode. pc %x expc %x count %d\n",
+	     regs->nip,current->tss.expc,current->tss.excount);
+#endif      
+      current->tss.excount = 0;
+      regs->gpr[3] = -EFAULT;
+      regs->nip = current->tss.expc;
+      return;
+    }
+  }
+  
   if (user_mode(regs))
   {
-/*    printk("Bad User Area: Addr %x PC %x Task %x pid %d %s\n",
-	   address,regs->nip, current,current->pid,current->comm);*/
-    send_sig(SIGSEGV, current, 1);
+    force_sig(SIGSEGV, current);
     return;
   }
   panic("KERNEL access of bad area PC %x address %x vm_flags %x\n",
 	regs->nip,address,vma->vm_flags);
 }
 
-
 va_to_phys(unsigned long address)
 {
 	pgd_t *dir;
@@ -240,25 +165,8 @@
 	return (0);
 }
 
-
-/*
- * See if an address should be valid in the current context.
- */
-valid_addr(unsigned long addr)
+inline void
+update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t _pte)
 {
-	struct vm_area_struct * vma;
-	for (vma = current->mm->mmap ; ; vma = vma->vm_next)
-	{
-		if (!vma)
-		{
-			return (0);
-		}
-		if (vma->vm_end > addr)
-			break;
-	}
-	if (vma->vm_start <= addr)
-	{
-		return (1);
-	}
-	return (0);
+   MMU_hash_page(&current->tss, address & PAGE_MASK, (pte *)&_pte);
 }
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.1.15/linux/arch/ppc/mm/init.c	Wed Oct  9 08:55:18 1996
+++ linux/arch/ppc/mm/init.c	Wed Dec 18 10:49:52 1996
@@ -3,6 +3,7 @@
  *
  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
  *  Ported to PPC by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
  */
 
 #include <linux/config.h>
@@ -17,86 +18,113 @@
 #include <linux/mman.h>
 #include <linux/mm.h>
 #include <linux/swap.h>
-
-#define SHOW_FAULTS
-#undef  SHOW_FAULTS
-
-#define SHOW_INVALIDATES
-#undef  SHOW_INVALIDATES
-
 #include <asm/pgtable.h>
+#include <asm/residual.h>
 
-extern pgd_t swapper_pg_dir[1024*8];
+extern pgd_t swapper_pg_dir[1024];
+extern unsigned long empty_zero_page[1024];
 
 extern void die_if_kernel(char *,struct pt_regs *,long);
 extern void show_net_buffers(void);
+void flush_hash_table(void);
+
+#undef HASHSTATS
+
+unsigned long _SDR1;		/* Hardware SDR1 image */
+PTE *Hash;
+int Hash_size, Hash_mask;
+unsigned long *end_of_DRAM;
+int cache_is_copyback = 1;
+int kernel_pages_are_copyback = 1;
+/* Note: these need to be in 'data' so they live over the boot */
+unsigned char *BeBox_IO_page = 0;
+unsigned long isBeBox[2] = {0, 0};
+
+#ifdef HASHSTATS
+extern unsigned long *hashhits;
+#endif
+
+
 
-/*
- * 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)
 {
 	panic("__bad_pagetable");
 }
+
 pte_t __bad_page(void)
 {
 	panic("__bad_page");
 }
-unsigned long __zero_page(void)
-{
-	extern char empty_zero_page[PAGE_SIZE];
-	bzero(empty_zero_page, PAGE_SIZE);
-	return (unsigned long) empty_zero_page;
-}
 
 void show_mem(void)
 {
-	int i,free = 0,total = 0,reserved = 0;
-	int shared = 0;
-
-	printk("Mem-info:\n");
-	show_free_areas();
-	printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
-	/*i = high_memory >> PAGE_SHIFT;*/
-	i = MAP_NR(high_memory);
-	while (i-- > 0) {
-		total++;
-		if (PageReserved(mem_map+i))
-			reserved++;
-		else if (!mem_map[i].count)
-			free++;
-		else
-			shared += mem_map[i].count-1;
-	}
-	printk("%d pages of RAM\n",total);
-	printk("%d free pages\n",free);
-	printk("%d reserved pages\n",reserved);
-	printk("%d pages shared\n",shared);
-	show_buffers();
+  unsigned long i,free = 0,total = 0,reserved = 0;
+  unsigned long shared = 0;
+  PTE *ptr;
+  unsigned long full = 0, overflow = 0;
+  unsigned int ti;
+
+  printk("Mem-info:\n");
+  show_free_areas();
+  printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
+  i = MAP_NR(high_memory);
+  while (i-- > 0) {
+    total++;
+    if (PageReserved(mem_map+i))
+      reserved++;
+    else if (!mem_map[i].count)
+      free++;
+    else
+      shared += mem_map[i].count-1;
+  }
+  printk("%lu pages of RAM\n",total);
+  printk("%lu free pages\n",free);
+  printk("%lu reserved pages\n",reserved);
+  printk("%lu pages shared\n",shared);
+  show_buffers();
 #ifdef CONFIG_NET
-	show_net_buffers();
+  show_net_buffers();
 #endif
+#ifdef HASHSTATS
+  printk("Hash Hits %u entries (buckets)\n",(Hash_size/sizeof(struct _PTE))/8);
+  for ( i = 0; i < (Hash_size/sizeof(struct _PTE))/8; i++ )
+  {
+    if ( hashhits[i] >= 20 )
+    {
+      printk("[%lu] \t %lu\n", i,hashhits[i]);
+    }
+  }
+#endif
+  
+  for ( ptr = Hash ; ptr <= Hash+Hash_size ; ptr++)
+  {
+    if (ptr->v)
+    {
+      full++;
+      if (ptr->h == 1)
+	overflow++;
+    }
+  }
+  printk("Hash Table: %dkB Buckets: %dk PTEs: %d/%d (%%%d full) %d overflowed\n",
+	 Hash_size>>10,	(Hash_size/(sizeof(PTE)*8)) >> 10,
+	 full,Hash_size/sizeof(PTE),
+	 (full*100)/(Hash_size/sizeof(PTE)),
+	 overflow);
+  printk(" Task  context    vsid0\n");
+  for ( ti = 0; ti < NR_TASKS ; ti++ );
+  {
+    if ( task[ti] )
+    {
+      printk("%5d %8x %8x\n",
+	     task[ti]->pid,task[ti]->mm->context,
+	     ((SEGREG *)task[ti]->tss.segs)[0].vsid);
+    }
+  }
+      
 }
 
 extern unsigned long free_area_init(unsigned long, unsigned long);
 
-/*
- * 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.
- */
 unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
 {
 	return free_area_init(start_mem, end_mem);
@@ -104,43 +132,46 @@
 
 void mem_init(unsigned long start_mem, unsigned long end_mem)
 {
-	int codepages = 0;
-	int datapages = 0;
-	unsigned long tmp;
-	extern int etext;
+  int codepages = 0;
+  int datapages = 0;
+  unsigned long tmp;
+  extern int etext;
+	
+  end_mem &= PAGE_MASK;
+  high_memory = (void *)end_mem;
+  max_mapnr = MAP_NR(end_mem);
+  /* clear the zero-page */
+  memset(empty_zero_page, 0, PAGE_SIZE);
 	
-	end_mem &= PAGE_MASK;
-	high_memory = end_mem;
-
 	/* mark usable pages in the mem_map[] */
-	start_mem = PAGE_ALIGN(start_mem);
+  start_mem = PAGE_ALIGN(start_mem);
 
-	for (tmp = KERNELBASE ; tmp < high_memory ; tmp += PAGE_SIZE)
-	{
-		if (tmp < start_mem)
-		{
-			set_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags);
-			if (tmp < (unsigned long) &etext)
-			{
-				codepages++;
-			} else
-			{
-				datapages++;
-			}
-			continue;
-		}
-		clear_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags);
-		mem_map[MAP_NR(tmp)].count = 1;
-		free_page(tmp);
-	}
-	tmp = nr_free_pages << PAGE_SHIFT;
-	printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n",
-		tmp >> 10,
-		((int)high_memory - (int)KERNELBASE) >> 10,
-		codepages << (PAGE_SHIFT-10),
-		datapages << (PAGE_SHIFT-10));
-	invalidate();
-	return;
+  for (tmp = KERNELBASE ; tmp < (long)high_memory ; tmp += PAGE_SIZE)
+    {
+      if (tmp < start_mem)
+	{
+	  set_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags);
+	  if (tmp < (unsigned long) &etext)
+	    {
+	      codepages++;
+	    } else
+	      {
+		datapages++;
+	      }
+	  continue;
+	}
+      clear_bit(PG_reserved, &mem_map[MAP_NR(tmp)].flags);
+      mem_map[MAP_NR(tmp)].count = 1;
+      free_page(tmp);
+    }
+  tmp = nr_free_pages << PAGE_SHIFT;
+  printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n",
+	 tmp >> 10,
+	 ((int)high_memory - (int)KERNELBASE) >> 10,
+	 codepages << (PAGE_SHIFT-10),
+	 datapages << (PAGE_SHIFT-10));
+  /*	invalidate();*/
+  return;
 }
 
 void si_meminfo(struct sysinfo *val)
@@ -203,7 +234,7 @@
    {
    	{
    		0x90000000>>17, 	/* bepi */
-		BL_16M, /* this should be set to amount of phys ram */
+		BL_256M, /* this gets set to amount of phys ram */
    		1,			/* vs */
    		0,			/* vp */
    	},
@@ -251,67 +282,11 @@
    	}
    };
 
-unsigned long _SDR1;		/* Hardware SDR1 image */
-PTE *Hash;
-int Hash_size, Hash_mask;
-unsigned long *end_of_DRAM;
-int cache_is_copyback = 1;
-int kernel_pages_are_copyback = 1;
-/* Note: these need to be in 'data' so they live over the boot */
-unsigned char *BeBox_IO_page = 0;
-unsigned long isBeBox[2] = {0, 0};
-
-#define NUM_MAPPINGS 128
-struct
-   {
-   	int va, pa, pg, task;
-   } last_mappings[NUM_MAPPINGS];
-int next_mapping = 0;
 
-/* Generic linked list */
-struct item
-   {
-   	struct item *next;
-   };
-   
-#ifndef NULL   
+#ifndef NULL
 #define NULL 0
 #endif
 
-#define MAX_CONTEXTS	16
-#define MAX_MMU_PAGES	8
-
-static struct item _free_pages;
-static char mmu_pages[(MAX_MMU_PAGES+1)*MMU_PAGE_SIZE];
-
-/*
- * Routines to support generic linked lists.
- */
-
-MMU_free_item(struct item *hdr, struct item *elem)
-{
-	if (hdr->next == (struct item *)NULL)
-	{ /* First item in list */
-		elem->next = (struct item *)NULL;
-	} else
-	{
-		elem->next = hdr->next;
-	}
-	hdr->next = elem;
-}
-
-struct item *
-MMU_get_item(struct item *hdr)
-{
-	struct item *item;
-	if ((item = hdr->next) != (struct item *)NULL)
-	{
-		item = hdr->next;
-		hdr->next = item->next;
-	}
-	return (item);
-}
-
 /*
  * This code is called to create a minimal mapped environment.
  * It is called with the MMU on, but with only a BAT register
@@ -319,276 +294,196 @@
  * the BAT mapping is withdrawn and all mappings must be complete.
  */
 
+
+
+
 extern char _start[], _end[];
  
-MMU_init()
+void MMU_init(void)
 {
-	int i, p;
-	SEGREG *segs;
-	printk("MMU init - started\n");
-	find_end_of_memory();
-	printk("  Start at 0x%08X, End at 0x%08X, Hash at 0x%08X\n", _start, _end, Hash);
-	_SDR1 = ((unsigned long)Hash & 0x00FFFFFF) | Hash_mask;
-	p = (int)mmu_pages;
-	p = (p + (MMU_PAGE_SIZE-1)) & ~(MMU_PAGE_SIZE-1);
-	_free_pages.next = (struct item *)NULL;
-	for (i = 0;  i < MAX_MMU_PAGES;  i++)
-	{
-		MMU_free_item(&_free_pages, (struct item *)p);
-		p += MMU_PAGE_SIZE;
-	}
-	/* Force initial page tables */
+  extern RESIDUAL res;
+  extern unsigned long resptr;
+  int i, p;
+  SEGREG *segs;
+  
+  /* copy residual data */
+  if ( resptr )
+    memcpy( &res, (void *)(resptr+KERNELBASE), sizeof(RESIDUAL) );
+  else
+    bzero( &res, sizeof(RESIDUAL) ); /* clearing bss probably clears this but... */
+  
+  end_of_DRAM = (unsigned long *)find_end_of_memory();
+  _SDR1 = ((unsigned long)Hash - KERNELBASE) | Hash_mask;
 #if 0	
-	swapper_pg_dir = (pgd_t *)MMU_get_page();
-#endif	
-	init_task.tss.pg_tables = (unsigned long *)swapper_pg_dir;
-	/* Segment registers */
-	segs = init_task.tss.segs;
-	for (i = 0;  i < 16;  i++)
-	{
-		segs[i].ks = 0;
-		segs[i].kp = 1;
-		segs[i].vsid = i;
-	}
-	/* Map kernel TEXT+DATA+BSS */
-	end_of_DRAM = (unsigned long *)Hash;
-	/* Hard map in any special local resources */
-	if (isBeBox[0])
-	{
-		/* Map in one page for the BeBox motherboard I/O */
-		end_of_DRAM = (unsigned long *)((unsigned long)end_of_DRAM - MMU_PAGE_SIZE);
+  printk("Hash      %08x\n",(unsigned long)Hash);
+  printk("Hash_mask %08x\n",Hash_mask);
+  printk("Hash_size %08x\n",Hash_size);	
+  printk("SDR1      %08x\n",_SDR1);
+#endif
+  /* Segment registers */
+  segs = (SEGREG *)init_task.tss.segs;
+  for (i = 0;  i < 16;  i++)
+  {
+    segs[i].ks = 0;
+    segs[i].kp = 1;
+#if 1
+    if ( i < 8 )
+      segs[i].vsid = i+10000;
+    else
+#else
+    if ( i < 8 )
+      segs[i].vsid = i<<5;
+#endif		  
+      segs[i].vsid = i;
+  }
+  
+  
+	
+  /* Hard map in any special local resources */
+  if (isBeBox[0])
+    {
+      /* Map in one page for the BeBox motherboard I/O */
+      end_of_DRAM = (unsigned long *)((unsigned long)end_of_DRAM - PAGE_SIZE);
 #if 0		
-		BeBox_IO_page = (unsigned char *)0x7FFFF000;
+      BeBox_IO_page = (unsigned char *)0x7FFFF000;
 #endif
 		BeBox_IO_page = (unsigned char *)end_of_DRAM;
-		MMU_map_page(&init_task.tss, BeBox_IO_page, 0x7FFFF000, PAGE_KERNEL);
 		MMU_disable_cache_for_page(&init_task.tss, BeBox_IO_page);
-	}
-	/* Other parts of the kernel expect ALL RAM to be mapped */	
-	for (i = (int)_start;  i < (int)end_of_DRAM;  i += MMU_PAGE_SIZE)
-	{
-		MMU_map_page(&init_task.tss, i, i & 0x00FFFFFF, PAGE_KERNEL);
-	}
-	/* Map hardware HASH table */
-	for (i = (int)Hash;  i < (int)Hash+Hash_size;  i += MMU_PAGE_SIZE)
-	{
-		MMU_map_page(&init_task.tss, i, i & 0x00FFFFFF, PAGE_KERNEL);
-	}
-#if 0 /* I'm not sure this is necessary */
-	/* Clear all DRAM not explicitly used by kernel */
-	bzero(_end, (unsigned long)end_of_DRAM-(unsigned long)_end);
-#endif
-	printk("MMU init - done!\n");
-}
-
-pte *
-MMU_get_page()
-{
-	pte *pg;
-	if ((pg = (pte *)MMU_get_item(&_free_pages)))
-	{
-		bzero((char *)pg, MMU_PAGE_SIZE);
-	}
-	printk("MMU Allocate Page at %08X\n", pg);
-	return(pg);
-}
-
-MMU_map_page(struct thread_struct *tss, unsigned long va, unsigned long pa, int flags)
-{
-	pte *pd, *pg;
-#if 0
-if (va < (unsigned long)0x90000000)	
-  printk("Thread: %x, Map VA: %08x -> PA: %08X, Flags: %x\n", tss, va, pa, flags);
-#endif
-	if ((pte **)tss->pg_tables == (pte **)NULL)
-	{ /* Allocate upper level page map */
-		(pte **)tss->pg_tables = (pte **)MMU_get_page();
-		if ((pte **)tss->pg_tables == (pte **)NULL)
-		{
-			_panic("Out of MMU pages (PD)\n");
-		}
-	}
-	/* Use upper 10 bits of VA to index the first level map */
-	pd = ((pte **)tss->pg_tables)[(va>>PD_SHIFT)&PD_MASK];
-	pd = (pte *)((int)pd & 0xFFFFF000);
-	if (pd == (pte *)NULL)
-	{ /* Need to allocate second-level table */
-		pd = (pte *)MMU_get_page();
-		if (pd == (pte *)NULL)
-		{
-			_panic("Out of MMU pages (PG)\n");
-		}
-		((pte **)tss->pg_tables)[(va>>PD_SHIFT)&PD_MASK] = (pte *)((unsigned long)pd | _PAGE_TABLE);
-	}
-	/* Use middle 10 bits of VA to index the second-level map */
-	pg = &pd[(va>>PT_SHIFT)&PT_MASK];
-	*(long *)pg = 0;  /* Clear out entry */
-	pg->page_num = pa>>PG_SHIFT;
-	pg->flags = flags;
-	MMU_hash_page(tss, va, pg);
+    }
 }
 
 /*
  * Insert(create) a hardware page table entry
  */
-MMU_hash_page(struct thread_struct *tss, unsigned long va, pte *pg)
+int inline MMU_hash_page(struct thread_struct *tss, unsigned long va, pte *pg)
 {
-	int hash, page_index, segment, i, h, _h, api, vsid, perms;
-	PTE *_pte, *empty, *slot;
-	PTE *slot0, *slot1;
-	extern char _etext;
-/* TEMP */
-if (va < KERNELBASE)		
-{
-	last_mappings[next_mapping].va = va;
-	last_mappings[next_mapping].pa = pg?*(int *)pg:0;
-	last_mappings[next_mapping].pg = pg;
-	last_mappings[next_mapping].task = current->pid;
-	if (++next_mapping == NUM_MAPPINGS) next_mapping = 0;
-}
-/* TEMP */	
-	page_index = ((int)va & 0x0FFFF000) >> 12;
-	segment = (unsigned int)va >> 28;
-	api = page_index >> 10;
-	vsid = ((SEGREG *)tss->segs)[segment].vsid;
-	empty = slot = (PTE *)NULL;
-	for (_h = 0;  _h < 2;  _h++)
-	{
-		hash = page_index ^ vsid;		
-		if (_h)
-		{
-			hash = ~hash;  /* Secondary hash uses ones-complement */
-		}
-		hash &= 0x3FF | (Hash_mask << 10);
-		hash *= 8;  /* Eight entries / hash bucket */
-		_pte = &Hash[hash];
-		/* Save slot addresses in case we have to purge */
-		if (_h)
-		{
-			slot1 = _pte;
-		} else
-		{
-			slot0 = _pte;
-		}
-		for (i = 0;  i < 8;  i++, _pte++)
-		{
-			if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api)
-			{ /* Found it! */
-				h = _h;
-				slot = _pte;
-				goto found_it;
-			}
-			if ((empty == (PTE *)NULL) && !_pte->v)
-			{
-				h = _h;
-				empty = _pte;
-			}
-		}
-	}
-	if (slot == (PTE *)NULL)
-	{
-		if (pg == (pte *)NULL)
-		{
-			return (0);
-		}
-		if (empty == (PTE *)NULL)
-		{ /* Table is totally full! */
-printk("Map VA: %08X, Slot: %08X[%08X/%08X], H: %d\n", va, slot, slot0, slot1, h);
-printk("Slot0:\n");
-_pte = slot0;
-for (i = 0;  i < 8;  i++, _pte++)
-{
-	printk("  V: %d, VSID: %05x, H: %d, RPN: %04x, R: %d, C: %d, PP: %x\n", _pte->v, _pte->vsid, _pte->h, _pte->rpn, _pte->r, _pte->c, _pte->pp);
-}
-printk("Slot1:\n");
-_pte = slot1;
-for (i = 0;  i < 8;  i++, _pte++)
-{
-	printk("  V: %d, VSID: %05x, H: %d, RPN: %04x, R: %d, C: %d, PP: %x\n", _pte->v, _pte->vsid, _pte->h, _pte->rpn, _pte->r, _pte->c, _pte->pp);
-}
-printk("Last mappings:\n");
-for (i = 0;  i < NUM_MAPPINGS;  i++)
-{
-	printk("  VA: %08x, PA: %08X, TASK: %08X\n",
-		last_mappings[next_mapping].va,
-		last_mappings[next_mapping].pa,
-		last_mappings[next_mapping].task);
-	if (++next_mapping == NUM_MAPPINGS) next_mapping = 0;
-}
-			_panic("Hash table full!\n");
-		}
-		slot = empty;
-	}
+  int hash, page_index, segment, i, h, _h, api, vsid, perms;
+  PTE *_pte, *empty, *slot;
+  PTE *slot0, *slot1;
+  extern char _etext;
+  page_index = ((int)va & 0x0FFFF000) >> 12;
+  segment = (unsigned int)va >> 28;
+  api = page_index >> 10;
+  vsid = ((SEGREG *)tss->segs)[segment].vsid;
+  empty = slot = (PTE *)NULL;
+  
+  if ( (va <= _etext) && (va >= KERNELBASE))
+  {
+    printk("MMU_hash_page: called on kernel page mapped with bats va %x\n",
+	   va);
+  }
+
+  /* check first hash bucket */
+  h = 0;
+  hash = page_index ^ vsid;
+  hash &= 0x3FF | (Hash_mask << 10);
+  hash *= 8;			/* 8 entries in each bucket */
+  _pte = &Hash[hash];
+  slot0 = _pte;
+  for (i = 0;  i < 8;  i++, _pte++)
+    {
+      if (_pte->v && _pte->vsid == vsid && _pte->h == h && _pte->api == api)
+	{
+	  slot = _pte;
+	  goto found_it;
+	}
+      if ((empty == NULL) && (!_pte->v))
+	{
+	  empty = _pte;
+	  _h = h;
+	}
+    }
+
+  /* check second hash bucket */
+  h = 1;
+  hash = page_index ^ vsid;
+  hash = ~hash;
+  hash &= 0x3FF | (Hash_mask << 10);
+  hash *= 8;			/* 8 entries in each bucket */
+  _pte = &Hash[hash];
+  slot1 = _pte;
+  for (i = 0;  i < 8;  i++, _pte++)
+    {
+      if (_pte->v && _pte->vsid == vsid && _pte->h == h && _pte->api == api)
+	{
+	  slot = _pte;
+	  goto found_it;
+	}
+      if ((empty == NULL) && (!_pte->v))
+	{
+	  empty = _pte;
+	  _h = h;
+	}
+    }
+
+  if (empty == (PTE *)NULL)
+  { 
+#if 1
+    printk("Both hash buckets full! va %x vsid %x current %s (%d)\n",
+	   va,vsid,current->comm,current->pid);
+#endif
+    slot = slot1;
+    h = 1;
+  }
+  else
+  {
+    slot = empty;
+    h = _h;
+  }
 found_it:
-#if 0
-printk("Map VA: %08X, Slot: %08X[%08X/%08X], H: %d\n", va, slot, slot0, slot1, h);	
-#endif
-	_tlbie(va); /* Clear TLB */
-	if (pg)
-	{ /* Fill in table */
-		slot->v = 1;
-		slot->vsid = vsid;
-		slot->h = h;
-		slot->api = api;
-		if (((pg->page_num << 12) & 0xF0000000) == KERNELBASE)
-		{
-			slot->rpn = pg->page_num - (KERNELBASE>>12);
-		} else
-		{
-			slot->rpn = pg->page_num;
-		}
-		slot->r = 0;
-		slot->c = 0;
-		slot->i = 0;
-		slot->g = 0;
-		if (cache_is_copyback)
-		{
-			if (kernel_pages_are_copyback || (pg->flags & _PAGE_USER) || (va < (unsigned long)&_etext))
-			{ /* All User & Kernel TEXT pages are copy-back */
-				slot->w = 0;
-				slot->m = 1;
-			} else
-			{ /* Kernel DATA pages are write-thru */
-				slot->w = 1;
-				slot->m = 0;
-			}
-		} else
-		{
-			slot->w = 1;
-			slot->m = 0;
-		}
-		if (pg->flags & _PAGE_USER)
-		{
-			if (pg->flags & _PAGE_RW)
-			{ /* Read/write page */
-				perms = PP_RWRW;
-			} else
-			{ /* Read only page */
-				perms = PP_RWRX;
-				perms = PP_RXRX;
-			}
-		} else
-		{ /* Kernel pages */
-			perms = PP_RWRW;
-			perms = PP_RWXX;
-		}
-#ifdef SHOW_FAULTS
-if (va < KERNELBASE)		
-printk("VA: %08X, PA: %08X, Flags: %x, Perms: %d, Vsid: %x\n", va, pg->page_num<<12, pg->flags, perms, vsid);
+#ifdef HASHSTATS
+  hashhits[hash]++;
 #endif
-		slot->pp = perms;
-		return (0);
+  _tlbie(va); /* Clear TLB */
+    /* Fill in table */
+      slot->v = 1;
+      slot->vsid = vsid;
+      slot->h = h;
+      slot->api = api;
+      if (((pg->page_num << 12) & 0xF0000000) == KERNELBASE)
+	{
+	  slot->rpn = pg->page_num - (KERNELBASE>>12);
 	} else
-	{ /* Pull entry from tables */
-		int flags = 0;
-		if (slot->r) flags |= _PAGE_ACCESSED;
-		if (slot->c) flags |= _PAGE_DIRTY;
-		slot->v = 0;
-#ifdef SHOW_FAULTS
-printk("Pull VA: %08X, Flags: %x\n", va, flags);
-#endif
-		return (flags);
-	}
+	  {
+	    slot->rpn = pg->page_num;
+	  }
+      slot->r = 0;
+      slot->c = 0;
+      slot->i = 0;
+      slot->g = 0;
+      if (cache_is_copyback)
+	{
+	  if (kernel_pages_are_copyback || (pg->flags & _PAGE_USER) || (va < (unsigned long)&_etext))
+	    { /* All User & Kernel TEXT pages are copy-back */
+	      slot->w = 0;
+	      slot->m = 1;
+	    } else
+	      { /* Kernel DATA pages are write-thru */
+		slot->w = 1;
+		slot->m = 0;
+	      }
+	} else
+	  {
+	    slot->w = 1;
+	    slot->m = 0;
+	  }
+      if (pg->flags & _PAGE_USER)
+	{
+	  if (pg->flags & _PAGE_RW)
+	    { /* Read/write page */
+	      perms = PP_RWRW;
+	    } else
+	      { /* Read only page */
+		perms = PP_RWRX;
+		perms = PP_RXRX;
+	      }
+	} else
+	  { /* Kernel pages */
+	    perms = PP_RWRW;
+	    perms = PP_RWXX;
+	  }
+      slot->pp = perms;
+      return (0);
 }
 
 /*
@@ -644,11 +539,11 @@
 	slot->m = 0;
 }
 
+
 /*
- * Invalidate a hardware [hash] page table entry
- * Note: this should never be called [currently] for kernel addresses.
+ * invalidate a hardware hash table pte
  */
-MMU_invalidate_page(struct mm_struct *mm, unsigned long va, pte *pg)
+inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va)
 {
 	int hash, page_index, segment, i, h, _h, api, vsid, perms;
 	PTE *_pte, *slot;
@@ -657,7 +552,6 @@
 	segment = (unsigned int)va >> 28;
 	api = page_index >> 10;
 	vsid = mm->context | segment;
-	slot = (PTE *)NULL;
 	for (_h = 0;  _h < 2;  _h++)
 	{
 		hash = page_index ^ vsid;		
@@ -676,283 +570,145 @@
 				if (_pte->r) flags |= _PAGE_ACCESSED;
 				if (_pte->c) flags |= _PAGE_DIRTY;
 				_pte->v = 0;
-#ifdef SHOW_FAULTS
-printk("Pull VA: %08X, Flags: %x\n", va, flags);
-#endif
 				return (flags);
 			}
 		}
 	}
+	_tlbie(va);
 	return (flags);
 }
 
-/*
- * Invalidate the MMU [hardware] tables (for current task?)
- */
-void
-invalidate(void)
-{
-	int i, j, flags;
-	unsigned long address;
-	pgd_t *pgd;
-	pte_t *_pte;
-	static long _invalidates;
-#ifdef SHOW_INVALIDATES
-printk("invalidate()\n");
-#endif
-	_invalidates++;
-#if 0 /* Unnecessary */
-	_tlbia();  /* Flush TLB entries */
-#endif
-	pgd = pgd_offset(current->mm, 0);
-	if (!pgd) return;  /* No map? */
-	address = 0;
-	for (i = 0 ; (i < PTRS_PER_PGD) && (address < KERNELBASE); i++)
-	{
-		if (*(long *)pgd)
-		{
-			/* I know there are only two levels, but the macros don't */
-			_pte = pte_offset(pmd_offset(pgd,0),0);
-			if (_pte)
-			{
-				for (j = 0;  j < PTRS_PER_PTE;  j++)
-				{
-					if (pte_present(*_pte))
-					{
-						flags = MMU_hash_page(&current->tss, address, 0);
-						((pte *)_pte)->flags |= flags;
-					}
-					_pte++;
-					address += PAGE_SIZE;
-				}
-			} else
-			{
-				address += PAGE_SIZE*PTRS_PER_PTE;
-			}
-		} else
-		{
-			address += PAGE_SIZE*PTRS_PER_PTE;
-		}
-		pgd++;
-	}
-} 
 
-/*
- * Invalidate the MMU [hardware] tables (for current task?)
- */
-void
+inline void
+flush_cache_all(void)
+{
+}
+inline void
 flush_cache_mm(struct mm_struct *mm)
 {
-	int i, j, flags;
-	unsigned long address;
-	pgd_t *pgd;
-	pte_t *_pte;
-	static long _invalidates;
-#ifdef SHOW_INVALIDATES
-printk("invalidate_mm(%x)\n", mm);
-#endif
-if (!mm) return;	
-	_invalidates++;
-#if 0 /* Unnecessary */
-	_tlbia();  /* Flush TLB entries */
-#endif
-	pgd = pgd_offset(mm, 0);
-	if (!pgd) return;  /* No map? */
-	address = 0;
-	for (i = 0 ; (i < PTRS_PER_PGD) && (address < KERNELBASE); i++)
-	{
-		if (*(long *)pgd)
-		{
-			/* I know there are only two levels, but the macros don't */
-			_pte = pte_offset(pmd_offset(pgd,0),0);
-			if (_pte)
-			{
-				for (j = 0;  j < PTRS_PER_PTE;  j++)
-				{
-					if (pte_present(*_pte))
-					{
-						flags = MMU_invalidate_page(mm, address, 0);
-						((pte *)_pte)->flags |= flags;
-					}
-					_pte++;
-					address += PAGE_SIZE;
-				}
-			} else
-			{
-				address += PAGE_SIZE*PTRS_PER_PTE;
-			}
-		} else
-		{
-			address += PAGE_SIZE*PTRS_PER_PTE;
-		}
-		pgd++;
-	}
 } 
-
-/*
- * Invalidate the MMU [hardware] tables (for current task?)
- */
-void
+inline void
 flush_cache_page(struct vm_area_struct *vma, long va)
 {
-	int i, j, flags;
-	unsigned long address;
-	pgd_t *pgd;
-	pte_t *_pte;
-	static long _invalidates;
-	struct mm_struct *mm = vma->vm_mm;
-#ifdef SHOW_INVALIDATES
-printk("invalidate_page(%x[%x], %x)\n", vma, mm, va);
-#endif
-if (!mm) return;  /* In case VMA lookup fails */	
-	_invalidates++;
-#if 0 /* Unnecessary */
-	_tlbia();  /* Flush TLB entries */
-#endif
-/* Note: this could be MUCH better */
-	pgd = pgd_offset(mm, 0);
-	if (!pgd) return;  /* No map? */
-	address = 0;
-	for (i = 0 ; (i < PTRS_PER_PGD) && (address < KERNELBASE); i++)
-	{
-		if (*(long *)pgd)
-		{
-			/* I know there are only two levels, but the macros don't */
-			_pte = pte_offset(pmd_offset(pgd,0),0);
-			if (_pte)
-			{
-				for (j = 0;  j < PTRS_PER_PTE;  j++)
-				{
-					if ((va == address) && pte_present(*_pte))
-					{
-						flags = MMU_invalidate_page(mm, address, 0);
-						((pte *)_pte)->flags |= flags;
-					}
-					_pte++;
-					address += PAGE_SIZE;
-				}
-			} else
-			{
-				address += PAGE_SIZE*PTRS_PER_PTE;
-			}
-		} else
-		{
-			address += PAGE_SIZE*PTRS_PER_PTE;
-		}
-		pgd++;
-	}
 } 
-
-/*
- * Invalidate the MMU [hardware] tables (for current task?)
- */
-void
+inline void
 flush_cache_range(struct mm_struct *mm, unsigned long va_start, unsigned long va_end)
 {
-	int i, j, flags;
-	unsigned long address;
-	pgd_t *pgd;
-	pte_t *_pte;
-	static long _invalidates;
-#ifdef SHOW_INVALIDATES
-printk("invalidate_range(%x, %x, %x)\n", mm, va_start, va_end);
-#endif
-if (!mm) return;	
-	_invalidates++;
-#if 0 /* Unnecessary */
-	_tlbia();  /* Flush TLB entries */
-#endif
-/* Note: this could be MUCH better */
-	pgd = pgd_offset(mm, 0);
-	if (!pgd) return;  /* No map? */
-	address = 0;
-	for (i = 0 ; (i < PTRS_PER_PGD) && (address < KERNELBASE); i++)
-	{
-		if (*(long *)pgd)
-		{
-			/* I know there are only two levels, but the macros don't */
-			_pte = pte_offset(pmd_offset(pgd,0),0);
-			if (_pte)
-			{
-				for (j = 0;  j < PTRS_PER_PTE;  j++)
-				{
-					if ((va_start <= address) && (va_end > address) && pte_present(*_pte))
-					{
-						flags = MMU_invalidate_page(mm, address, 0);
-						((pte *)_pte)->flags |= flags;
-					}
-					_pte++;
-					address += PAGE_SIZE;
-				}
-			} else
-			{
-				address += PAGE_SIZE*PTRS_PER_PTE;
-			}
-		} else
-		{
-			address += PAGE_SIZE*PTRS_PER_PTE;
-		}
-		pgd++;
-	}
 } 
 
-void
+inline void
 cache_mode(char *str, int *ints)
 {
 	cache_is_copyback = ints[0];
 }
 
-_verify_addr(long va)
+/*
+ * TLB flushing:
+ *
+ *  - flush_tlb() flushes the current mm struct TLBs
+ *  - flush_tlb_all() flushes all processes TLBs
+ *  - 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
+ *
+ * since the hardware hash table functions as an extension of the
+ * tlb as far as the linux tables are concerned, flush them too.
+ *    -- Cort
+ */
+inline void
+flush_tlb(void)
 {
-	int hash, page_index, segment, i, h, _h, api, vsid, perms;
-	struct thread_struct *tss = &current->tss;
-	PTE *_pte, *empty, *slot;
-	PTE *slot0, *slot1;
-	page_index = ((int)va & 0x0FFFF000) >> 12;
-	segment = (unsigned int)va >> 28;
-	api = page_index >> 10;
-	vsid = ((SEGREG *)tss->segs)[segment].vsid;
-	empty = slot = (PTE *)NULL;
-	printk("Segment = %x/%x\n", *(long *)&tss->segs[segment], _get_SRx(segment));
-	for (_h = 0;  _h < 2;  _h++)
-	{
-		hash = page_index ^ vsid;		
-		if (_h)
-		{
-			hash = ~hash;  /* Secondary hash uses ones-complement */
-		}
-		hash &= 0x3FF | (Hash_mask << 10);
-		hash *= 8;  /* Eight entries / hash bucket */
-		_pte = &Hash[hash];
-/*		dump_buf(_pte, 64);*/
-		for (i = 0;  i < 8;  i++, _pte++)
-		{
-			if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api)
-			{ /* Found it! */
-				h = _h;
-				slot = _pte;
-				printk("Found at %x\n", slot);
-				goto found_it;
-			}
-			if ((empty == (PTE *)NULL) && !_pte->v)
-			{
-				h = _h;
-				empty = _pte;
-			}
-		}
-	}
-found_it:	
+  PTE *ptep;
+  int context = current->mm->context;
+  struct vm_area_struct *v;
+  unsigned int i;
+  
+  v = current->mm->mmap;
+
+  /* for every virtual memory address in the current context -- flush
+     the hash table */
+  while ( v != NULL )
+  {
+    for ( i = v->vm_start ; i <= v->vm_end; i += PAGE_SIZE)
+    {
+      MMU_invalidate_page(v->vm_mm,i);
+    }
+    v = v->vm_next;
+  }
+
+  _tlbia();
+}
+
+/* flush all tlb/hash table entries except for kernels
+
+   although the kernel is mapped with the bats, it's dynamic areas
+   obtained via kmalloc are mapped by the seg regs
+                      -- Cort
+   */
+inline void
+flush_tlb_all(void)
+{
+  PTE *ptep;
+
+  /* flush hash table */
+  for ( ptep = Hash ; ptep < (PTE *)((unsigned long)Hash+Hash_size) ; ptep++ )
+  {
+    /* if not kernel vsids 0-7 (vsid greater than that for process 0)*/
+    if ( (ptep->vsid > 7 ) && (ptep->v))
+    {
+      ptep->v = 0;
+    }
+  }
+
+  _tlbia();
+}
+
+inline void
+flush_tlb_mm(struct mm_struct *mm)
+{
+  PTE *ptep;
+  int context = mm->context;
+  struct vm_area_struct *v;
+  unsigned int i;
+
+  v = mm->mmap;
+  while ( v != NULL )
+  {
+    for ( i = v->vm_start ; i <= v->vm_end; i += PAGE_SIZE)
+    {
+      MMU_invalidate_page(v->vm_mm,i);
+    }
+    v = v->vm_next;
+  }
+
+  _tlbia();
 }
 
-flush_cache_all()
+
+inline void
+flush_tlb_page(struct vm_area_struct *vma, long vmaddr)
 {
-	printk("flush_cache_all()\n");
-	invalidate();
+  MMU_invalidate_page(vma->vm_mm,vmaddr);
 }
 
-flush_tlb_all() {}
-flush_tlb_mm() {}
-flush_tlb_page() {}
-flush_tlb_range() {}
-flush_page_to_ram() {}
 
+/* for each page addr in the range, call mmu_invalidat_page()
+   if the range is very large and the hash table is small it might be faster to
+   do a search of the hash table and just invalidate pages that are in the range
+   but that's for study later.
+        -- Cort
+   */
+inline void
+flush_tlb_range(struct mm_struct *mm, long start, long end)
+{
+  long i;
+  for ( i = PAGE_ALIGN(start-PAGE_SIZE) ; i < PAGE_ALIGN(end) ; i += PAGE_SIZE)
+  {
+    MMU_invalidate_page(mm,i);
+  }
+}
+
+inline void
+flush_page_to_ram(unsigned long page)
+{
+}
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/Makefile linux/arch/sparc/Makefile
--- v2.1.15/linux/arch/sparc/Makefile	Sun Apr 21 12:30:29 1996
+++ linux/arch/sparc/Makefile	Fri Dec 13 11:37:30 1996
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.20 1996/04/16 08:02:50 davem Exp $
+# $Id: Makefile,v 1.21 1996/11/13 05:09:12 davem Exp $
 # sparc/Makefile
 #
 # Makefile for the architecture dependent flags and dependencies on the
@@ -29,6 +29,9 @@
 
 LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc/prom/promlib.a \
 	$(TOPDIR)/arch/sparc/lib/lib.a
+
+INITOBJ = $(TOPDIR)/arch/sparc/kernel/initobj.o
+FINITOBJ = $(TOPDIR)/arch/sparc/kernel/finitobj.o
 
 ifdef CONFIG_AP1000
 SUBDIRS := $(SUBDIRS) arch/sparc/ap1000
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/boot/README linux/arch/sparc/boot/README
--- v2.1.15/linux/arch/sparc/boot/README	Mon May  6 12:26:03 1996
+++ linux/arch/sparc/boot/README	Thu Jan  1 02:00:00 1970
@@ -1,21 +0,0 @@
-This directory will contain the code necessary to compile and link the
-/boot program which is necessary to boot on the Sparc.  This program
-is real ugly and it knows too much.  It must be able to not only boot
-off of the root partition but also be able to netboot.  This means
-that it knows about RPC and NFS (bleech, yuck, eeewwwww!!) so that it
-can remote mount the root directory to fetch the kernel.  Also it must
-be able to ARP for its IP address and who its boot server is.  I
-think I'm getting sick.
-
-Regardless for now I will concentrate on the low-level stuff necessary
-to get the thing going.  This means the low-level entry code, etc.
-The prom knows how to get "us" if we have the proper boot blocks,
-actually the boot blocks live in our logical partition on a hard drive
-whereas over NFS this isn't applicable.  We have the boot blocks in
-our data area either way because we can be dual purpose.
-
-More will come....
-
-Hopefully I can write this such that it will work on almost all SUN
-machines in existence.  We'll see ;(
-
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/boot/bare.S linux/arch/sparc/boot/bare.S
--- v2.1.15/linux/arch/sparc/boot/bare.S	Thu Apr 25 13:22:05 1996
+++ linux/arch/sparc/boot/bare.S	Thu Jan  1 02:00:00 1970
@@ -1,160 +0,0 @@
-/* $Id: bare.S,v 1.4 1996/04/23 01:53:40 davem Exp $
- * base.S:      Ugly low-level boot program entry code.  The job of this
- *              module is to parse the boot flags, try to mount the remote
- *              root filesystem and load the kernel into virtual memory.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include "bare.h"
-#include <asm/ptrace.h>
-
-	.data
-	.globl C_LABEL(romvec)
-	.globl C_LABEL(idp_ptr)
-
-C_LABEL(romvec):
-	.word 0
-C_LABEL(idp_ptr):
-	.word 0
-
-	.text
-	.align 8
-	.globl C_LABEL(first_adr_in_text)
-
-C_LABEL(first_adr_in_text):
-
-	/* Grrr, boot block, scratching my head... */
-	.globl C_LABEL(b_block)       /* Start of actual boot block */
-	.globl C_LABEL(b_block_size)  /* In bytes */
-	.globl C_LABEL(b_block_cksum) /* Checksum of boot block bytes */
-
-	b	start_of_execution    /* XXX Hack */
-	nop
-
-	.align	8
-C_LABEL(b_block):	
-	.skip	(BOOTBLOCK_NENTRIES * BOOTBLOCK_ENTSIZE)
-
-C_LABEL(b_block_size):
-	.word	0
-
-C_LABEL(b_block_cksum):
-	.word	0
-
-/* Ok, the prom has left in %o0 the PROM pointer.  We leave it here
- * for when we jump into the kernel.  So save out of this window before
- * you dick with %o0.  As far as I know we could be loaded *anywhere*, so
- * we relocate ourselves to the "linked" location.  Self modifying code rules.
- */
-
-start_of_execution:
-	sethi	%hi(C_LABEL(first_adr_in_text)), %o1		! This is our top
-	or	%o1, %lo(C_LABEL(first_adr_in_text)), %o1	! of stack too.
-	sub	%o1, REGWIN_SZ, %o1
-	add	%o1, 0x7, %o1
-	andn	%o1, 0x7, %o1
-	save	%o1, 0x0, %sp					! save is an add
-here:
-	call	there
-	sethi	%hi(here), %o4
-there:	
-	sub	%o7, here-C_LABEL(first_adr_in_text), %o5
-	or	%o4, %lo(here), %o4
-	cmp	%o4, %o7
-	be	loaded_ok
-	nop
-
-	/* Gotta relocate, compute our size sans bss segment. */
-	set	C_LABEL(edata)+4, %o3
-	set	C_LABEL(first_adr_in_text), %o2
-	sub	%o3, %o2, %o3
-rel_loop:
-	ld	[%o5], %o4
-	add	%o5, 0x4, %o5
-	st	%o4, [%o2]
-	subcc	%o3, 0x4, %o3
-	bg	rel_loop
-	add	%o2, 0x4, %o2
-
-	/* Pray that we are now in a sane place in memory */
-	sethi	%hi(loaded_ok), %o2
-	or	%o2, %lo(loaded_ok), %o2
-	jmp	%o2
-	nop
-
-loaded_ok:
-	/* Save the PROM pointer */
-	sethi	%hi(C_LABEL(romvec)), %o1
-	or	%o1, %lo(C_LABEL(romvec)), %o1
-	st	%i0, [%o1]
-
-	/* Build a PSR we can live with */
-	rd	%psr, %o1
-
-#if 0
-	andn	%o1, PSR_PIL, %o1
-	sethi	%hi(SANE_PSR), %g4
-	or	%g4, %lo(SANE_PSR), %g4
-	or	%o1, %g4, %o1
-#endif
-
-	/* V8 book says this works to calculate num_windows */
-	sethi	%hi(0xffffffff), %g2
-	rd	%wim, %g3
-	or	%g2, %lo(0xffffffff), %g2
-	wr	%g2, 0x0, %wim
-	WRITE_PAUSE
-
-	rd	%wim, %g4
-	WRITE_PAUSE
-
-	wr	%g3, 0x0, %wim
-	WRITE_PAUSE
-
-	/* Restore old %psr */
-	wr	%o1, 0x0, %psr
-	WRITE_PAUSE
-
-	or	%g0, 0x0, %g3
-1:
-	srl	%g4, 0x1, %g4
-	subcc	%g4, 0x0, %g0
-	bne	1b
-	add	%g3, 0x1, %g3
-	
-	/* %g3 now contains nwindows */
-	sethi	%hi(C_LABEL(nwindows)), %o4
-	st	%g3, [%o4 + %lo(C_LABEL(nwindows))]
-
-	/* Now zero out our bss segment, lord knows the nasty prom monster
-	 * didn't do it for us.
-	 */
-	sethi	%hi(C_LABEL(end)), %g1
-	or	%g1, %lo(C_LABEL(end)), %g1
-	add	%g1, 0x4, %g1
-	sethi	%hi(C_LABEL(edata)), %g2
-	or	%g2, %lo(C_LABEL(edata)), %g2
-
-	/* Slow, inefficient, who cares, this is messy boot code */
-bzero_bss_loop:
-	st	%g0, [%g2]
-	add	%g2, 0x4, %g2
-	cmp	%g2, %g1
-	bl	bzero_bss_loop
-	nop
-
-	call	C_LABEL(init_me)	! Fun with empirical constants and prom
-	nop
-
-	/* Dump back into the prom */
-get_me_out_of_here:
-	set	C_LABEL(romvec), %g2
-	ld	[%g2], %g2
-	ld	[%g2 + 0x74], %g2
-	restore
-	call	%g2
-	nop
-
-
-
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/boot/bare.h linux/arch/sparc/boot/bare.h
--- v2.1.15/linux/arch/sparc/boot/bare.h	Sat Nov 25 02:57:42 1995
+++ linux/arch/sparc/boot/bare.h	Thu Jan  1 02:00:00 1970
@@ -1,18 +0,0 @@
-/* $Id: bare.h,v 1.2 1995/11/25 00:57:41 davem Exp $
- * bare.h:  Defines for the low level entry code of the BOOT program.
- *          We include in the head.h stuff that the real kernel uses
- *          and this saves a lot of repetition here.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <asm/head.h>
-#include <asm/psr.h>
-#include <asm/cprefix.h>
-
-#define     SANE_PIL  (0xd00)    /* No interrupts except clock and unmaskable NMI's */
-#define     SANE_PSR  (SANE_PIL|PSR_S|PSR_ET)
-
-#define     BOOTBLOCK_NENTRIES   0x40      /* Number of entries in the boot block */
-#define     BOOTBLOCK_ENTSIZE    0x04      /* Size in bytes of each boot block entry */
-
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/boot/empirical.h linux/arch/sparc/boot/empirical.h
--- v2.1.15/linux/arch/sparc/boot/empirical.h	Thu Apr 25 13:22:05 1996
+++ linux/arch/sparc/boot/empirical.h	Thu Jan  1 02:00:00 1970
@@ -1,8 +0,0 @@
-/* $Id: empirical.h,v 1.2 1996/04/23 01:53:42 davem Exp $
- * empirical.h:  Nasty hacks....
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#define DEF_BOGO     25
-
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/boot/init_me.c linux/arch/sparc/boot/init_me.c
--- v2.1.15/linux/arch/sparc/boot/init_me.c	Sun Apr 21 17:32:01 1996
+++ linux/arch/sparc/boot/init_me.c	Thu Jan  1 02:00:00 1970
@@ -1,69 +0,0 @@
-/* $Id: init_me.c,v 1.3 1996/04/21 10:30:09 davem Exp $
- * init_me.c:  Initialize empirical constants and gather some info from
- *             the boot prom.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <asm/openprom.h>  /* For property declarations and the prom structs */
-#include <asm/oplib.h>
-#include <asm/vac-ops.h>
-
-#include "empirical.h"   /* Don't ask... */
-
-#define DEBUG_INIT_ME    /* Tell me what's going on */
-
-unsigned int nwindows;   /* Set in bare.S */
-unsigned int nwindowsm1;
-unsigned int pac_or_vac; /* 0 means "dunno" 1 means "VAC" 2 means "PAC" */
-unsigned int pvac_size;  /* Use the same two variables for a PAC and VAC */
-unsigned int pvac_linesize;
-unsigned int pac_size;
-int num_segmaps;
-int num_contexts;
-unsigned int BOGOMIPS;        /* bogosity without the VAC cache on */
-unsigned int BOGOMIPS_WCACHE; /* bogosity with the VAC cache */
-unsigned int delay_factor;
-
-extern int prom_node_root;
-void (*printk)(const char *str, ...);
-
-void init_me(void)
-{
-	unsigned int grrr;
-
-	printk = romvec->pv_printf;
-	prom_node_root = prom_nextnode(0);
-	prom_getprop(prom_node_root, "mmu-npmg", &num_segmaps,
-		     sizeof(unsigned int));
-
-	pvac_size = prom_getint_default(prom_node_root, "vac-size", 65536);
-
-	pvac_linesize = prom_getint_default(prom_node_root, "vac-linesize", 16);
-	
-	grrr = prom_getint_default(prom_node_root, "mips-on", 0);
-	if(!grrr) {
-		grrr = prom_getint_default(prom_node_root, "clock-frequency", 0);
-		if(grrr > 15000000 && grrr < 100000000) {
-			BOGOMIPS = 3;
-			BOGOMIPS_WCACHE = grrr / 1000000;
-		} else {
-			BOGOMIPS = DEF_BOGO;
-			BOGOMIPS_WCACHE = DEF_BOGO;
-		}
-	} else (BOGOMIPS_WCACHE = grrr, 
-		BOGOMIPS = prom_getint(prom_node_root, "mips-off"));
-
-#ifdef DEBUG_INIT_ME
-	(*(romvec->pv_printf))("\nBOGOMIPS        %d\n", (int) BOGOMIPS);
-	(*(romvec->pv_printf))("BOGOMIPS_WCACHE %d\n", (int) BOGOMIPS_WCACHE);
-	(*(romvec->pv_printf))("pvac_size        %d\n", (int) pvac_size);
-	(*(romvec->pv_printf))("pvac_linesize    %d\n", (int) pvac_linesize);
-	(*(romvec->pv_printf))("num_segmaps     %d\n", (int) num_segmaps);
-#endif
-
-	delay_factor = (BOGOMIPS > 3) ? ((BOGOMIPS - 2) >> 1) : 11;
-
-	(*(romvec->pv_printf))("\nLILO: \n");
-	return;
-}
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/config.in linux/arch/sparc/config.in
--- v2.1.15/linux/arch/sparc/config.in	Tue Nov 12 15:56:02 1996
+++ linux/arch/sparc/config.in	Fri Dec 13 11:37:30 1996
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.23 1996/10/28 01:24:40 davem Exp $
+# $Id: config.in,v 1.29 1996/12/08 08:13:34 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -62,6 +62,7 @@
 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
 fi
 
 tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
@@ -88,6 +89,9 @@
 	dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
 	dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
 	dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
+	if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then
+	  bool '  Enable vendor-specific extentions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR
+	fi
 	dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
 
 	comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
@@ -100,6 +104,7 @@
 	comment 'SCSI low-level drivers'
 
 	bool 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI
+	tristate 'PTI Qlogic,ISP Driver' CONFIG_SCSI_QLOGICPTI $CONFIG_SCSI
 	endmenu
 fi
 endmenu
@@ -122,7 +127,8 @@
 		  bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6
 		fi
 		bool 'Sun LANCE support' CONFIG_SUNLANCE
-		bool 'Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL
+		tristate 'Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL
+		tristate 'Sun QuadEthernet support' CONFIG_SUNQE
 #		bool 'FDDI driver support' CONFIG_FDDI
 #		if [ "$CONFIG_FDDI" = "y" ]; then
 #		fi
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v2.1.15/linux/arch/sparc/defconfig	Tue Nov 12 15:56:02 1996
+++ linux/arch/sparc/defconfig	Fri Dec 13 11:37:30 1996
@@ -71,12 +71,15 @@
 #
 # Networking options
 #
+CONFIG_NETLINK=y
+CONFIG_RTNETLINK=y
 CONFIG_FIREWALL=y
 CONFIG_NET_ALIAS=y
 CONFIG_INET=y
 CONFIG_IP_FORWARD=y
 CONFIG_IP_MULTICAST=y
 CONFIG_IP_FIREWALL=y
+# CONFIG_IP_FIREWALL_NETLINK is not set
 # CONFIG_IP_FIREWALL_VERBOSE is not set
 CONFIG_IP_MASQUERADE=y
 
@@ -90,6 +93,7 @@
 CONFIG_NET_IPIP=m
 # CONFIG_IP_MROUTE is not set
 CONFIG_IP_ALIAS=m
+# CONFIG_ARPD is not set
 
 #
 # (it is safe to leave these untouched)
@@ -109,7 +113,6 @@
 CONFIG_ATALK=m
 # CONFIG_AX25 is not set
 # CONFIG_BRIDGE is not set
-# CONFIG_NETLINK is not set
 
 #
 # SCSI support
@@ -122,6 +125,7 @@
 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=y
 
 #
@@ -134,6 +138,7 @@
 # SCSI low-level drivers
 #
 CONFIG_SCSI_SUNESP=y
+CONFIG_SCSI_QLOGICPTI=m
 
 #
 # Network device support
@@ -150,7 +155,8 @@
 CONFIG_SLIP_SMART=y
 # CONFIG_SLIP_MODE_SLIP6 is not set
 CONFIG_SUNLANCE=y
-CONFIG_HAPPYMEAL=y
+CONFIG_HAPPYMEAL=m
+CONFIG_SUNQE=m
 
 #
 # Filesystems
@@ -170,7 +176,7 @@
 CONFIG_RNFS_BOOTP=y
 CONFIG_RNFS_RARP=y
 CONFIG_SMB_FS=m
-CONFIG_SMB_LONG=y
+CONFIG_SMB_WIN95=y
 CONFIG_NCP_FS=m
 CONFIG_ISO9660_FS=y
 CONFIG_HPFS_FS=m
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/Makefile linux/arch/sparc/kernel/Makefile
--- v2.1.15/linux/arch/sparc/kernel/Makefile	Tue Nov 12 15:56:02 1996
+++ linux/arch/sparc/kernel/Makefile	Fri Dec 13 11:37:30 1996
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.34 1996/09/21 04:07:31 davem Exp $
+# $Id: Makefile,v 1.35 1996/11/13 05:09:15 davem Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -27,7 +27,7 @@
 
 endif
 
-all: kernel.o head.o
+all: kernel.o head.o initobj.o finitobj.o
 
 O_TARGET := kernel.o
 IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o
@@ -36,7 +36,7 @@
 	    sys_sparc.o sunos_asm.o sparc-stub.o systbls.o sys_sunos.o  \
 	    sunos_ioctl.o time.o windows.o cpu.o devices.o \
 	    sclow.o solaris.o tadpole.o tick14.o ptrace.o sys_solaris.o \
-	    unaligned.o
+	    unaligned.o muldiv.o
 
 OX_OBJS  := sparc_ksyms.o
 
@@ -48,8 +48,6 @@
 O_OBJS += auxio.o
 endif
 
-all: kernel.o head.o
-
 ifdef SMP
 
 head.o: head.S
@@ -61,5 +59,12 @@
 	$(CC) -D__ASSEMBLY__ -ansi -c $*.S -o $*.o
 
 endif
+
+initobj.o: initobj.S
+	$(CC) -D__ASSEMBLY__ -ansi -c initobj.S -o initobj.o
+
+finitobj.o: initobj.S
+	$(CC) -D__ASSEMBLY__ -ansi -c finitobj.S -o finitobj.o
+
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/auxio.c linux/arch/sparc/kernel/auxio.c
--- v2.1.15/linux/arch/sparc/kernel/auxio.c	Tue Nov 12 15:56:02 1996
+++ linux/arch/sparc/kernel/auxio.c	Fri Dec 13 11:37:30 1996
@@ -3,6 +3,7 @@
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <linux/init.h>
 #include <asm/oplib.h>
 #include <asm/io.h>
 #include <asm/auxio.h>
@@ -10,8 +11,7 @@
 /* Probe and map in the Auxiliary I/O register */
 unsigned char *auxio_register;
 
-void
-auxio_probe(void)
+__initfunc(void auxio_probe(void))
 {
 	int node, auxio_nd;
 	struct linux_prom_registers auxregs[1];
@@ -27,6 +27,11 @@
 		node = prom_getchild(node);
 		auxio_nd = prom_searchsiblings(node, "auxio");
 		if(!auxio_nd) {
+			if(prom_searchsiblings(node, "leds")) {
+				/* VME chassis sun4m machine, no auxio exists. */
+				auxio_register = 0;
+				return;
+			}
 			prom_printf("Cannot find auxio node, cannot continue...\n");
 			prom_halt();
 		}
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/cpu.c linux/arch/sparc/kernel/cpu.c
--- v2.1.15/linux/arch/sparc/kernel/cpu.c	Tue Nov 12 15:56:02 1996
+++ linux/arch/sparc/kernel/cpu.c	Fri Dec 13 11:37:30 1996
@@ -5,7 +5,7 @@
  */
 
 #include <linux/kernel.h>
-
+#include <linux/init.h>
 #include <asm/oplib.h>
 #include <asm/page.h>
 #include <asm/head.h>
@@ -66,7 +66,7 @@
   { 5, 5, "reserved"},
   { 5, 6, "reserved"},
   { 5, 7, "No FPU"},
-  { 9, 3, "Weitek on-chip FPU"},
+  { 9, 3, "Fujitsu or Weitek on-chip FPU"},
 };
 
 #define NSPARCFPU  (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info))
@@ -84,7 +84,7 @@
   { 1, 3, "Cypress/ROSS CY7C611"},
   /* Ross Technologies HyperSparc */
   { 1, 0xf, "ROSS HyperSparc RT620"},
-  { 1, 0xe, "ROSS HyperSparc RT625"},
+  { 1, 0xe, "ROSS HyperSparc RT625 or RT626"},
   /* ECL Implementation, CRAY S-MP Supercomputer... AIEEE! */
   /* Someone please write the code to support this beast! ;) */
   { 2, 0, "Bipolar Integrated Technology - B5010"},
@@ -101,10 +101,10 @@
   { 7, 0, "Harvest VLSI Design Center, Inc. - unknown"},
   /* Gallium arsenide 200MHz, BOOOOGOOOOMIPS!!! */
   { 8, 0, "Systems and Processes Engineering Corporation (SPEC)"},
-  { 9, 0, "Weitek Power-UP"},
-  { 9, 1, "Weitek Power-UP"},
-  { 9, 2, "Weitek Power-UP"},
-  { 9, 3, "Weitek Power-UP"},
+  { 9, 0, "Fujitsu or Weitek Power-UP"},
+  { 9, 1, "Fujitsu or Weitek Power-UP"},
+  { 9, 2, "Fujitsu or Weitek Power-UP"},
+  { 9, 3, "Fujitsu or Weitek Power-UP"},
   { 0xa, 0, "UNKNOWN CPU-VENDOR/TYPE"},
   { 0xb, 0, "UNKNOWN CPU-VENDOR/TYPE"},
   { 0xc, 0, "UNKNOWN CPU-VENDOR/TYPE"},
@@ -120,8 +120,7 @@
 
 unsigned int fsr_storage;
 
-void
-cpu_probe(void)
+__initfunc(void cpu_probe(void))
 {
 	int psr_impl, psr_vers, fpu_vers;
 	int i, cpuid;
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/devices.c linux/arch/sparc/kernel/devices.c
--- v2.1.15/linux/arch/sparc/kernel/devices.c	Tue Nov 12 15:56:02 1996
+++ linux/arch/sparc/kernel/devices.c	Fri Dec 13 11:37:30 1996
@@ -7,6 +7,7 @@
 #include <linux/kernel.h>
 #include <linux/tasks.h>
 #include <linux/config.h>
+#include <linux/init.h>
 
 #include <asm/page.h>
 #include <asm/oplib.h>
@@ -20,8 +21,8 @@
 extern void clock_stop_probe(void); /* tadpole.c */
 extern void sun4c_probe_memerr_reg(void);
 
-unsigned long
-device_scan(unsigned long mem_start)
+__initfunc(unsigned long
+device_scan(unsigned long mem_start))
 {
 	char node_str[128];
 	int nd, prom_node_cpu, thismid;
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/entry.S linux/arch/sparc/kernel/entry.S
--- v2.1.15/linux/arch/sparc/kernel/entry.S	Tue Nov 12 15:56:02 1996
+++ linux/arch/sparc/kernel/entry.S	Fri Dec 13 11:37:30 1996
@@ -1,9 +1,10 @@
-/* $Id: entry.S,v 1.116 1996/10/27 08:35:47 davem Exp $
+/* $Id: entry.S,v 1.126 1996/12/10 06:06:12 davem Exp $
  * arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1996 Eddie C. Dost   (ecd@skynet.be)
  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
  */
 
 #include <linux/config.h>
@@ -20,6 +21,7 @@
 #include <asm/vaddrs.h>
 #include <asm/memreg.h>
 #include <asm/page.h>
+#include <asm/pgtsun4c.h>
 #include <asm/winmacro.h>
 #include <asm/signal.h>
 
@@ -81,6 +83,7 @@
 	/* We are increasing PIL, so two writes. */
 	or	%l0, PSR_PIL, %l0
 	wr	%l0, 0, %psr
+	WRITE_PAUSE
 	wr	%l0, PSR_ET, %psr
 	WRITE_PAUSE
 
@@ -248,6 +251,7 @@
 	/* Set all IRQs off. */
 	or	%l0, PSR_PIL, %l4
 	wr	%l4, 0x0, %psr
+	WRITE_PAUSE
 	wr	%l4, PSR_ET, %psr
 	WRITE_PAUSE
 
@@ -337,12 +341,15 @@
 	or	%l0, PSR_PIL, %g2
 	add	%l5, 0x1, %l4
 	wr	%g2, 0x0, %psr
+	WRITE_PAUSE
 	st	%l4, [%l6 + %lo(C_LABEL(intr_count))]
 	wr	%g2, PSR_ET, %psr
+	WRITE_PAUSE
 	mov	%l7, %o0		! irq level
 	call	C_LABEL(handler_irq)
 	 add	%sp, REGWIN_SZ, %o1	! pt_regs ptr
 	wr	%l0, PSR_ET, %psr
+	WRITE_PAUSE
 	st	%l5, [%l6 + %lo(C_LABEL(intr_count))]
 	LEAVE_IRQ
 	RESTORE_ALL
@@ -390,7 +397,7 @@
 mna_handler:
 	andcc	%l0, PSR_PS, %g0
 	be	mna_fromuser
-	 ld	[%l1], %l7
+	 nop
 
 	SAVE_ALL
 	ENTER_SYSCALL
@@ -398,7 +405,7 @@
 	wr	%l0, PSR_ET, %psr
 	WRITE_PAUSE
 
-	mov	%l7, %o1
+	ld	[%l1], %o1
 	call	C_LABEL(kernel_unaligned_trap)
 	 add	%sp, REGWIN_SZ, %o0
 
@@ -411,7 +418,7 @@
 	wr	%l0, PSR_ET, %psr		! re-enable traps
 	WRITE_PAUSE
 
-	mov	%l7, %o1
+	ld	[%l1], %o1
 	call	C_LABEL(user_unaligned_trap)
 	 add	%sp, REGWIN_SZ, %o0
 
@@ -865,12 +872,18 @@
 C_LABEL(num_context_patch2_16):		mov	0x10, %l7
 
 	.align	4
-	.globl	C_LABEL(sun4c_kernel_buckets_patch_32)
-C_LABEL(sun4c_kernel_buckets_patch_32):	andn	%l7, 256, %l3
+	.globl	C_LABEL(vac_linesize_patch_32)
+C_LABEL(vac_linesize_patch_32):		subcc	%l7, 32, %l7
+
+	.align	4
+	.globl	C_LABEL(vac_hwflush_patch1_on), C_LABEL(vac_hwflush_patch2_on)
+C_LABEL(vac_hwflush_patch1_on):		subcc	%l7, (PAGE_SIZE - 4), %l7
+C_LABEL(vac_hwflush_patch2_on):		sta	%g0, [%l3 + %l7] ASI_HWFLUSHSEG
 
 	.globl	C_LABEL(invalid_segment_patch1), C_LABEL(invalid_segment_patch2)
 	.globl	C_LABEL(num_context_patch1), C_LABEL(num_context_patch2)
-	.globl	C_LABEL(sun4c_kernel_buckets_patch)
+	.globl	C_LABEL(vac_linesize_patch), C_LABEL(vac_hwflush_patch1)
+	.globl	C_LABEL(vac_hwflush_patch2)
 
 	.align	4
 	.globl	sun4c_fault
@@ -878,47 +891,115 @@
 	sethi	%hi(AC_SYNC_ERR), %l4
 	add	%l4, 0x4, %l6			! AC_SYNC_VA in %l6
 	lda	[%l6] ASI_CONTROL, %l5		! Address
-	lda	[%l4] ASI_CONTROL, %l6
+	lda	[%l4] ASI_CONTROL, %l6		! Error, retained for a bit
 
 	andn	%l5, 0xfff, %l5			! Encode all info into l7
-	srl	%l6, 14, %l6
+	srl	%l6, 14, %l4
 
-	and	%l6, 2, %l6
-	or	%l5, %l6, %l6
+	and	%l4, 2, %l4
+	or	%l5, %l4, %l4
 
-	or	%l6, %l7, %l7			! l7 = [addr,write,txtfault]
+	or	%l4, %l7, %l7			! l7 = [addr,write,txtfault]
 
 	andcc	%l0, PSR_PS, %g0
 	be	sun4c_fault_fromuser
 	 andcc	%l7, 1, %g0			! Text fault?
 
 	be	1f
-	 sethi	%hi(KERNBASE), %l6
+	 sethi	%hi(KERNBASE), %l4
 
 	mov	%l1, %l5			! PC
 
 1:
-	cmp	%l5, %l6
+	cmp	%l5, %l4
 	blu	sun4c_fault_fromuser
-	 sethi	%hi(0xfffc0000), %l4		! SUN4C_REAL_PGDIR_MASK
+	 sethi	%hi(~((1 << SUN4C_REAL_PGDIR_SHIFT) - 1)), %l4
 
-	and	%l5, %l4, %l5
+	/* If the kernel references a bum kernel pointer, or a pte which
+	 * points to a non existant page in ram, we will run this code
+	 * _forever_ and lock up the machine!!!!! So we must check for
+	 * this condition, the AC_SYNC_ERR bits are what we must examine.
+	 * Also a parity error would make this happen as well.  So we just
+	 * check that we are in fact servicing a tlb miss and not some
+	 * other type of fault for the kernel.
+	 */
+	andcc	%l6, 0x80, %g0
+	be	sun4c_fault_fromuser
+	 and	%l5, %l4, %l5
 
 	lduba	[%l5] ASI_SEGMAP, %l4
 C_LABEL(invalid_segment_patch1):
 	cmp	%l4, 0x7f
 	bne	1f
-	 sethi	%hi(C_LABEL(sun4c_kernel_next)), %l4
+	 sethi	%hi(C_LABEL(sun4c_kfree_ring)), %l4
+	or	%l4, %lo(C_LABEL(sun4c_kfree_ring)), %l4
+	ld	[%l4 + 0x10], %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--
+
+	ld	[%l4 + 0x00], %l6	! entry = sun4c_kfree_ring.ringhd.next
+	st	%l5, [%l6 + 0x08]	! entry->vaddr = address
+
+	ld	[%l6 + 0x00], %l3	! next = entry->next
+	ld	[%l6 + 0x04], %l7	! entry->prev
+
+	st	%l7, [%l3 + 0x04]	! next->prev = entry->prev
+	st	%l3, [%l7 + 0x00]	! entry->prev->next = next
 
-	ld	[%l4 + %lo(C_LABEL(sun4c_kernel_next))], %l6	! entry
+	sethi	%hi(C_LABEL(sun4c_kernel_ring)), %l4
+	or	%l4, %lo(C_LABEL(sun4c_kernel_ring)), %l4
+					! head = &sun4c_kernel_ring.ringhd
 
-	ld	[%l6], %l3		! entry->vaddr
-	cmp	%l3, 0			! is this segment available?
-	be	4f			! Yes, use it.
-	 st	%l5, [%l6]		! entry->vaddr = address
+	ld	[%l4 + 0x00], %l7	! head->next
 
-	! use entry->vaddr to unmap the old segment
-	mov	%l3, %l5
+	st	%l4, [%l6 + 0x04]	! entry->prev = head
+	st	%l7, [%l6 + 0x00]	! entry->next = head->next
+	st	%l6, [%l7 + 0x04]	! head->next->prev = entry
+
+	st	%l6, [%l4 + 0x00]	! head->next = entry
+
+	ld	[%l4 + 0x10], %l3
+	inc	%l3			! sun4c_kernel_ring.num_entries++
+	b	4f
+	 st	%l3, [%l4 + 0x10]
+
+2:
+	or	%l4, %lo(C_LABEL(sun4c_kernel_ring)), %l4
+					! head = &sun4c_kernel_ring.ringhd
+
+	ld	[%l4 + 0x04], %l6	! entry = head->prev
+
+	ld	[%l6 + 0x08], %l3	! tmp = entry->vaddr
+
+	! Flush segment from the cache.
+	sethi	%hi((64 * 1024)), %l7
+1:
+C_LABEL(vac_hwflush_patch1):
+C_LABEL(vac_linesize_patch):
+	subcc	%l7, 16, %l7
+	bg	1b
+C_LABEL(vac_hwflush_patch2):
+	 sta	%g0, [%l3 + %l7] ASI_FLUSHSEG
+
+	st	%l5, [%l6 + 0x08]	! entry->vaddr = address
+
+	ld	[%l6 + 0x00], %l5	! next = entry->next
+	ld	[%l6 + 0x04], %l7	! entry->prev
+
+	st	%l7, [%l5 + 0x04]	! next->prev = entry->prev
+	st	%l5, [%l7 + 0x00]	! entry->prev->next = next
+	st	%l4, [%l6 + 0x04]	! entry->prev = head
+
+	ld	[%l4 + 0x00], %l7	! head->next
+
+	st	%l7, [%l6 + 0x00]	! entry->next = head->next
+	st	%l6, [%l7 + 0x04]	! head->next->prev = entry
+	st	%l6, [%l4 + 0x00]	! head->next = entry
+
+	mov	%l3, %l5		! address = tmp
 
 C_LABEL(num_context_patch1):
 	mov	0x08, %l7
@@ -939,22 +1020,16 @@
 
 	! reload the entry
 
-	sethi	%hi(C_LABEL(sun4c_kernel_next)), %l4
-	ld	[%l4 + %lo(C_LABEL(sun4c_kernel_next))], %l6
+	sethi	%hi(C_LABEL(sun4c_kernel_ring)), %l4
+	ld	[%l4 + %lo(C_LABEL(sun4c_kernel_ring))], %l6
 
-	ld	[%l6], %l5	! restore address from entry->vaddr
+	ld	[%l6 + 0x08], %l5	! restore address from entry->vaddr
 
 4:
-	! advance sun4c_kernel_next
-	add	%l6, 8, %l7
-C_LABEL(sun4c_kernel_buckets_patch):
-	andn	%l7, 128, %l3
-	st	%l3, [%l4 + %lo(C_LABEL(sun4c_kernel_next))]
-
 C_LABEL(num_context_patch2):
 	mov	0x08, %l7
 
-	ldub	[%l6 + 0x4], %l4	! entry->pseg
+	ldub	[%l6 + 0x0c], %l4	! entry->pseg
 
 	sethi	%hi(AC_CONTEXT), %l3
 	lduba	[%l3] ASI_CONTROL, %l6
@@ -968,17 +1043,17 @@
 	stba	%l6, [%l3] ASI_CONTROL
 
 1:
-	sethi	%hi(0xfe200000), %l4		! SUN4C_VMALLOC_START
+	sethi	%hi(SUN4C_VMALLOC_START), %l4
 	cmp	%l5, %l4
 
 	bgeu	1f
-	 mov	0x40, %l7	! SUN4C_REAL_PGDIR_SIZE / PAGE_SIZE
+	 mov	1 << (SUN4C_REAL_PGDIR_SHIFT - PAGE_SHIFT), %l7
 
 	sethi	%hi(KERNBASE), %l6
 
 	sub	%l5, %l6, %l4
 	srl	%l4, PAGE_SHIFT, %l4
-	sethi	%hi(0xf3000000), %l3		! SUN4C_PAGE_KERNEL
+	sethi	%hi((SUN4C_PAGE_KERNEL & 0xf4000000)), %l3
 	or	%l3, %l4, %l3
 
 	sethi	%hi(PAGE_SIZE), %l4
@@ -990,22 +1065,19 @@
 	bne	2b
 	 add	%l5, %l4, %l5
 
-	/* Restore condition codes */
-	wr	%l0, 0x0, %psr
-	WRITE_PAUSE
-	jmp	%l1
-	 rett	%l2
+	b	7f
+	 sethi	%hi(C_LABEL(sun4c_kernel_faults)), %l4
 
 1:
-	srl	%l5, 22, %l3			! SUN4C_PGDIR_SHIFT
+	srl	%l5, SUN4C_PGDIR_SHIFT, %l3
 	sethi	%hi(C_LABEL(swapper_pg_dir)), %l4
 	or	%l4, %lo(C_LABEL(swapper_pg_dir)), %l4
 	sll	%l3, 2, %l3
 	ld	[%l4 + %l3], %l4
-	andn	%l4, 0xfff, %l4			! PAGE_MASK
+	and	%l4, PAGE_MASK, %l4
 
-	srl	%l5, PAGE_SHIFT - 2, %l6
-	and	%l6, 0xffc, %l6			! (SUN4C_PTRS_PER_PTE - 1) << 2
+	srl	%l5, (PAGE_SHIFT - 2), %l6
+	and	%l6, ((SUN4C_PTRS_PER_PTE - 1) << 2), %l6
 	add	%l6, %l4, %l6
 
 	sethi	%hi(PAGE_SIZE), %l4
@@ -1018,6 +1090,12 @@
 	bne	2b
 	 add	%l5, %l4, %l5
 
+	sethi	%hi(C_LABEL(sun4c_kernel_faults)), %l4
+7:
+	ld	[%l4 + %lo(C_LABEL(sun4c_kernel_faults))], %l3
+	inc	%l3
+	st	%l3, [%l4 + %lo(C_LABEL(sun4c_kernel_faults))]
+
 	/* Restore condition codes */
 	wr	%l0, 0x0, %psr
 	WRITE_PAUSE
@@ -1216,8 +1294,10 @@
 flush_patch_two:
 	FLUSH_ALL_KERNEL_WINDOWS;
 	rd	%psr, %g4
+	WRITE_PAUSE
 	mov	SIGCHLD, %o0			! arg0:	clone flags
 	rd	%wim, %g5
+	WRITE_PAUSE
 	mov	%fp, %o1			! arg1:	usp
 	std	%g4, [%curptr + THREAD_FORK_KPSR]
 	add	%sp, REGWIN_SZ, %o2		! arg2:	pt_regs ptr
@@ -1231,10 +1311,12 @@
 flush_patch_three:
 	FLUSH_ALL_KERNEL_WINDOWS;
 	rd	%psr, %g4
+	WRITE_PAUSE
 
 	/* arg0,1: flags,usp  -- loaded already */
 	cmp	%o1, 0x0			! Is new_usp NULL?
 	rd	%wim, %g5
+	WRITE_PAUSE
 	be,a	1f
 	 mov	%fp, %o1			! yes, use callers usp
 	andn	%o1, 7, %o1			! no, align to 8 bytes
@@ -1262,8 +1344,8 @@
 
 	.globl	syscall_is_too_hard
 syscall_is_too_hard:
-	rd	%wim, %l3
-	SAVE_ALL
+	SAVE_ALL_HEAD
+	 rd	%wim, %l3
 	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr
@@ -1297,7 +1379,7 @@
 	bgeu	1f
 	 ld	[%sp + REGWIN_SZ + PT_PSR], %g3
 
-	/* System call success, clear Carry condition code. */		
+	/* System call success, clear Carry condition code. */
 	andn	%g3, %g2, %g3
 	clr	%l6
 	b	2f
@@ -1317,13 +1399,13 @@
 	ld	[%curptr + 0x14], %g2
 	andcc	%g2, 0x20, %g0
 	be,a	3f
-	 ld	[%sp + REGWIN_SZ + PT_NPC], %l1	/* pc  = npc   */
+	 ld	[%sp + REGWIN_SZ + PT_NPC], %l1 /* pc = npc */
 
 	call	C_LABEL(syscall_trace)
 	 nop
 
 	/* Advance the pc and npc over the trap instruction. */
-	ld	[%sp + REGWIN_SZ + PT_NPC], %l1	/* pc  = npc   */
+	ld	[%sp + REGWIN_SZ + PT_NPC], %l1 /* pc = npc */
 3:
 	add	%l1, 0x4, %l2			/* npc = npc+4 */
 	st	%l1, [%sp + REGWIN_SZ + PT_PC]
@@ -1334,38 +1416,30 @@
 	 * Solaris system calls and indirect system calls enter here.
          *
 	 * I have named the solaris indirect syscalls like that because
-	*  it seems like Solaris has some fast path syscalls that can
+	 * it seems like Solaris has some fast path syscalls that can
 	 * be handled as indirect system calls. - mig
 	 */
-	
-	.align  4
-	.globl  solaris_indirect_syscall
-solaris_indirect_syscall:
-	/* sethi done on the macro */
-        /* or %l7, %lo(C_LABEL(sys_call_table)), %l7; -- really needed? */
+
+linux_syscall_for_solaris:
+	sethi	%hi(sys_call_table), %l7
+	b	linux_sparc_syscall
+	 or	%l7, %lo(sys_call_table), %l7
 	
 	.align	4
 	.globl	solaris_syscall
 solaris_syscall:
-	/* Direct access to user regs, must faster. */
-	cmp	%g1, NR_SYSCALLS
-	blu,a	1f
-#ifdef OLD_SOLARIS
-	 sll	%g1, 2, %l4
-#else
-	 nop
-#endif
-	sethi	%hi(C_LABEL(sys_ni_syscall)), %l7
-	b	solaris_is_too_hard
-	 or	%l7, %lo(C_LABEL(sys_ni_syscall)), %l7
-1:
-#ifdef OLD_SOLARIS
-	ld	[%l7 + %l4], %l7
-#endif
-	.globl	solaris_is_too_hard
-solaris_is_too_hard:
-	rd	%wim, %l3
-	SAVE_ALL
+	cmp	%g1,59
+	be	linux_syscall_for_solaris
+	 cmp	%g1,2
+	be	linux_syscall_for_solaris
+	 cmp    %g1,42
+	be      linux_syscall_for_solaris
+	 cmp	%g1,119
+	be,a	linux_syscall_for_solaris
+	 mov	2, %g1
+1:	
+	SAVE_ALL_HEAD
+	 rd	%wim, %l3
 	ENTER_SYSCALL
 
 	wr	%l0, PSR_ET, %psr
@@ -1378,14 +1452,10 @@
 	mov	%i0, %l5
 	mov	%i3, %o3
 	mov	%i4, %o4
-#ifdef OLD_SOLARIS
-	call	%l7
-	 mov	%i5, %o5
-#else
 	mov	%i5, %o5
+
 	call	C_LABEL(do_solaris_syscall)
 	 add	%sp, REGWIN_SZ, %o0
-#endif
 
 	st	%o0, [%sp + REGWIN_SZ + PT_I0]
 	set	PSR_C, %g2
@@ -1404,22 +1474,31 @@
 	 * Also, get abs(errno) to return to the process.
 	 */
 	sub	%g0, %o0, %o0
-	sethi	%hi(C_LABEL(solaris_xlatb_rorl)), %o3
-	or	%o3, %lo(C_LABEL(solaris_xlatb_rorl)), %o3
-	sll	%o0, 2, %o0
-	ld	[%o3 + %o0], %o0
 	mov	1, %l6
 	st	%o0, [%sp + REGWIN_SZ + PT_I0]
 	or	%g3, %g2, %g3
 	st	%g3, [%sp + REGWIN_SZ + PT_PSR]
 
-	/* Advance the pc and npc over the trap instruction. */
+	/* Advance the pc and npc over the trap instruction.
+	 * If the npc is unaligned (has a 1 in the lower byte), it means
+	 * the kernel does not want us to play magic (ie, skipping over
+	 * traps).  Mainly when the Solaris code wants to set some PC and
+	 * nPC (setcontext).
+	 */
 2:
 	ld	[%sp + REGWIN_SZ + PT_NPC], %l1	/* pc  = npc   */
-	add	%l1, 0x4, %l2			/* npc = npc+4 */
+	andcc	%l1, 1, %g0
+	bne	1f
+	 add	%l1, 0x4, %l2			/* npc = npc+4 */
 	st	%l1, [%sp + REGWIN_SZ + PT_PC]
 	b	ret_trap_entry
 	 st	%l2, [%sp + REGWIN_SZ + PT_NPC]
+
+	/* kernel knows what it is doing, fixup npc and continue */
+1:
+	sub	%l1, 1, %l1
+ 	b	ret_trap_entry	
+	 st	%l1, [%sp + REGWIN_SZ + PT_NPC]
 
 	/* {net, open}bsd system calls enter here... */
 	.align	4
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/etrap.S linux/arch/sparc/kernel/etrap.S
--- v2.1.15/linux/arch/sparc/kernel/etrap.S	Tue Nov 12 15:56:02 1996
+++ linux/arch/sparc/kernel/etrap.S	Fri Dec 13 11:37:30 1996
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.21 1996/10/11 00:59:40 davem Exp $
+/* $Id: etrap.S,v 1.22 1996/12/03 08:44:33 jj Exp $
  * etrap.S: Sparc trap window preparation for entry into the
  *          Linux kernel.
  *
@@ -90,15 +90,12 @@
 
 	/* See if we are in the trap window. */
 	andcc	%t_twinmask, %t_wim, %g0
-	be	1f
+	bne	trap_setup_kernel_spill		! in trap window, clean up
 	 nop
 
-	b,a	trap_setup_kernel_spill		! in trap window, clean up
-
 	/* Trap from kernel with a window available.
 	 * Just do it...
 	 */
-1:
 	jmpl	%t_retpc + 0x8, %g0	! return to caller
 	 mov	%t_kstack, %sp		! jump onto new stack
 
@@ -106,15 +103,15 @@
 	ld	[%curptr + THREAD_UMASK], %g1
 	orcc	%g0, %g1, %g0
 	bne	trap_setup_user_spill	! there are some user windows, yuck
-	 nop
-
-		/* Spill from kernel, but only kernel windows, adjust
-		 * %wim and go.
-		 */
-		srl	%t_wim, 0x1, %g2	! begin computation of new %wim
-tsetup_patch1:	sll	%t_wim, 0x7, %t_wim	! patched on 7 window Sparcs
-		or	%t_wim, %g2, %g2
-tsetup_patch2:	and	%g2, 0xff, %g2		! patched on 7 window Sparcs
+	/* Spill from kernel, but only kernel windows, adjust
+	 * %wim and go.
+	 */
+	 srl	%t_wim, 0x1, %g2	! begin computation of new %wim
+tsetup_patch1:
+	sll	%t_wim, 0x7, %t_wim	! patched on 7 window Sparcs
+	or	%t_wim, %g2, %g2
+tsetup_patch2:
+	and	%g2, 0xff, %g2		! patched on 7 window Sparcs
 
 	save	%g0, %g0, %g0
 
@@ -148,48 +145,52 @@
 	bne	trap_setup_user_spill		! yep we are
 	 orn	%g0, %t_twinmask, %g1		! negate trap win mask into %g1
 
-		/* Trap from user, but not into the invalid window.
-		 * Calculate new umask.  The way this works is,
-		 * any window from the %wim at trap time until
-		 * the window right before the one we are in now,
-		 * is a user window.  A diagram:
-		 *
-		 *      7 6 5 4 3 2 1 0    window number
-		 *      ---------------
-		 *        I     L T        mnemonic
-		 *
-		 * Window 'I' is the invalid window in our example,
-		 * window 'L' is the window the user was in when
-		 * the trap occurred, window T is the trap window
-		 * we are in now.  So therefore, windows 5, 4 and
-		 * 3 are user windows.  The following sequence
-		 * computes the user winmask to represent this.
-		 */
-		subcc	%t_wim, %t_twinmask, %g2
-		bneg,a	1f
-		 sub	%g2, 0x1, %g2
+	/* Trap from user, but not into the invalid window.
+	 * Calculate new umask.  The way this works is,
+	 * any window from the %wim at trap time until
+	 * the window right before the one we are in now,
+	 * is a user window.  A diagram:
+	 *
+	 *      7 6 5 4 3 2 1 0    window number
+	 *      ---------------
+	 *        I     L T        mnemonic
+	 *
+	 * Window 'I' is the invalid window in our example,
+	 * window 'L' is the window the user was in when
+	 * the trap occurred, window T is the trap window
+	 * we are in now.  So therefore, windows 5, 4 and
+	 * 3 are user windows.  The following sequence
+	 * computes the user winmask to represent this.
+	 */
+	subcc	%t_wim, %t_twinmask, %g2
+	bneg,a	1f
+	 sub	%g2, 0x1, %g2
 1:
-		andn	%g2, %t_twinmask, %g2
-tsetup_patch3:	and	%g2, 0xff, %g2			! patched on 7win Sparcs
-		st	%g2, [%curptr + THREAD_UMASK]	! store new umask
+	andn	%g2, %t_twinmask, %g2
+tsetup_patch3:
+	and	%g2, 0xff, %g2			! patched on 7win Sparcs
+	st	%g2, [%curptr + THREAD_UMASK]	! store new umask
 
-		jmpl	%t_retpc + 0x8, %g0		! return to caller
-		 mov	%t_kstack, %sp			! and onto kernel stack
+	jmpl	%t_retpc + 0x8, %g0		! return to caller
+	 mov	%t_kstack, %sp			! and onto kernel stack
 
 trap_setup_user_spill:
-		/* A spill occurred from either kernel or user mode
-		 * and there exist some user windows to deal with.
-		 * A mask of the currently valid user windows
-		 * is in %g1 upon entry to here.
-		 */
-
-tsetup_patch4:	and	%g1, 0xff, %g1		! patched on 7win Sparcs, mask
-		srl	%t_wim, 0x1, %g2	! compute new %wim
-tsetup_patch5:	sll	%t_wim, 0x7, %t_wim	! patched on 7win Sparcs
-		or	%t_wim, %g2, %g2	! %g2 is new %wim
-tsetup_patch6:	and	%g2, 0xff, %g2		! patched on 7win Sparcs
-		andn	%g1, %g2, %g1		! clear this bit in %g1
-		st	%g1, [%curptr + THREAD_UMASK]
+	/* A spill occurred from either kernel or user mode
+	 * and there exist some user windows to deal with.
+	 * A mask of the currently valid user windows
+	 * is in %g1 upon entry to here.
+	 */
+
+tsetup_patch4:
+	and	%g1, 0xff, %g1		! patched on 7win Sparcs, mask
+	srl	%t_wim, 0x1, %g2	! compute new %wim
+tsetup_patch5:
+	sll	%t_wim, 0x7, %t_wim	! patched on 7win Sparcs
+	or	%t_wim, %g2, %g2	! %g2 is new %wim
+tsetup_patch6:
+	and	%g2, 0xff, %g2		! patched on 7win Sparcs
+	andn	%g1, %g2, %g1		! clear this bit in %g1
+	st	%g1, [%curptr + THREAD_UMASK]
 
 	save	%g0, %g0, %g0
 
@@ -199,27 +200,9 @@
 	 * routine.
 	 */
 	.globl	C_LABEL(tsetup_mmu_patchme)
-C_LABEL(tsetup_mmu_patchme):	b	C_LABEL(tsetup_sun4c_stackchk)
-				 andcc	%sp, 0x7, %g0
-
-trap_setup_user_stack_is_bolixed:
-	/* From user/kernel into invalid window w/bad user
-	 * stack. Save bad user stack, and return to caller.
-	 */
-	SAVE_BOLIXED_USER_STACK(curptr, g3)
-	restore	%g0, %g0, %g0
-
-	jmpl	%t_retpc + 0x8, %g0
-	 mov	%t_kstack, %sp
-
-trap_setup_good_ustack:
-	STORE_WINDOW(sp)
-
-trap_setup_finish_up:
-	restore %g0, %g0, %g0
-
-	jmpl	%t_retpc + 0x8, %g0
-	 mov	%t_kstack, %sp
+C_LABEL(tsetup_mmu_patchme):
+	b	C_LABEL(tsetup_sun4c_stackchk)
+	 andcc	%sp, 0x7, %g0
 
 	/* Architecture specific stack checking routines.  When either
 	 * of these routines are called, the globals are free to use
@@ -231,23 +214,17 @@
 	.globl	C_LABEL(tsetup_sun4c_stackchk)
 C_LABEL(tsetup_sun4c_stackchk):
 	/* Done by caller: andcc %sp, 0x7, %g0 */
-	be	1f
+	bne	trap_setup_user_stack_is_bolixed
 	 sra	%sp, 29, %glob_tmp
 
-	b,a	trap_setup_user_stack_is_bolixed
-
-1:
 	add	%glob_tmp, 0x1, %glob_tmp
 	andncc	%glob_tmp, 0x1, %g0
-	be	1f
+	bne	trap_setup_user_stack_is_bolixed
 	 and	%sp, 0xfff, %glob_tmp		! delay slot
 
-	b,a	trap_setup_user_stack_is_bolixed
-
 	/* See if our dump area will be on more than one
 	 * page.
 	 */
-1:
 	add	%glob_tmp, 0x38, %glob_tmp
 	andncc	%glob_tmp, 0xff8, %g0
 	be	tsetup_sun4c_onepage		! only one page to check
@@ -257,45 +234,50 @@
 	/* Is first page ok permission wise? */
 	srl	%glob_tmp, 29, %glob_tmp
 	cmp	%glob_tmp, 0x6
-	be	1f
+	bne	trap_setup_user_stack_is_bolixed
 	 add	%sp, 0x38, %glob_tmp		/* Is second page in vma hole? */
 
-	b,a	trap_setup_user_stack_is_bolixed
-
-1:
 	sra	%glob_tmp, 29, %glob_tmp
 	add	%glob_tmp, 0x1, %glob_tmp
 	andncc	%glob_tmp, 0x1, %g0
-	be	1f
+	bne	trap_setup_user_stack_is_bolixed
 	 add	%sp, 0x38, %glob_tmp
 
-	b,a	trap_setup_user_stack_is_bolixed
-
-1:
 	lda	[%glob_tmp] ASI_PTE, %glob_tmp
 
 tsetup_sun4c_onepage:
 	srl	%glob_tmp, 29, %glob_tmp
 	cmp	%glob_tmp, 0x6				! can user write to it?
-	be	trap_setup_good_ustack			! success
+	bne	trap_setup_user_stack_is_bolixed	! failure
 	 nop
 
-	b,a	trap_setup_user_stack_is_bolixed
+	STORE_WINDOW(sp)
+
+	restore %g0, %g0, %g0
+
+	jmpl	%t_retpc + 0x8, %g0
+	 mov	%t_kstack, %sp
 
 	.globl	C_LABEL(tsetup_srmmu_stackchk)
 C_LABEL(tsetup_srmmu_stackchk):
 	/* Check results of callers andcc %sp, 0x7, %g0 */
 	sethi	%hi(C_LABEL(page_offset)), %glob_tmp
-	be	1f
+	bne	trap_setup_user_stack_is_bolixed
 	 ld	[%glob_tmp + %lo(C_LABEL(page_offset))], %glob_tmp
 
-	b,a	trap_setup_user_stack_is_bolixed
-1:
 	cmp	%glob_tmp, %sp
-	bgu,a	1f
+	bleu,a	1f
 	 lda	[%g0] ASI_M_MMUREGS, %glob_tmp		! read MMU control
 
-	b,a	trap_setup_user_stack_is_bolixed
+trap_setup_user_stack_is_bolixed:
+	/* From user/kernel into invalid window w/bad user
+	 * stack. Save bad user stack, and return to caller.
+	 */
+	SAVE_BOLIXED_USER_STACK(curptr, g3)
+	restore	%g0, %g0, %g0
+
+	jmpl	%t_retpc + 0x8, %g0
+	 mov	%t_kstack, %sp
 
 1:
 	/* Clear the fault status and turn on the no_fault bit. */
@@ -313,7 +295,11 @@
 	mov	AC_M_SFSR, %glob_tmp
 	lda	[%glob_tmp] ASI_M_MMUREGS, %glob_tmp	! save away status of winstore
 	andcc	%glob_tmp, 0x2, %g0			! did we fault?
-	be,a	trap_setup_finish_up + 0x4		! cool beans, success
-	 restore %g0, %g0, %g0
+	bne	trap_setup_user_stack_is_bolixed	! failure
+	 nop
+
+	restore %g0, %g0, %g0
+
+	jmpl	%t_retpc + 0x8, %g0
+	 mov	%t_kstack, %sp
 
-	b,a	trap_setup_user_stack_is_bolixed	! we faulted, ugh
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/finitobj.S linux/arch/sparc/kernel/finitobj.S
--- v2.1.15/linux/arch/sparc/kernel/finitobj.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/kernel/finitobj.S	Fri Dec 13 11:37:30 1996
@@ -0,0 +1,9 @@
+#if defined (__svr4__) || defined (__ELF__)
+
+	.section	".text.init",#alloc,#execinstr
+	.globl	text_init_end
+text_init_end:
+	.section	".data.init",#alloc,#write
+	.globl	data_init_end
+data_init_end:
+#endif
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/head.S linux/arch/sparc/kernel/head.S
--- v2.1.15/linux/arch/sparc/kernel/head.S	Tue Nov 12 15:56:02 1996
+++ linux/arch/sparc/kernel/head.S	Fri Dec 13 11:37:30 1996
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.70 1996/10/31 06:28:29 davem Exp $
+/* $Id: head.S,v 1.74 1996/12/08 08:18:59 davem Exp $
  * head.S: The initial boot code for the Sparc port of Linux.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -8,6 +8,7 @@
 
 #include <linux/version.h>
 #include <linux/config.h>
+#include <linux/init.h>
 
 #include <asm/cprefix.h>
 #include <asm/head.h>
@@ -162,7 +163,7 @@
 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_bada7:INDIRECT_SOLARIS_SYSCALL(156)
+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)
 t_badb1:BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5)
@@ -737,6 +738,10 @@
 		jmpl	%g1, %g0
 		 nop
 
+/* The code above should be at beginning and we have to take care about
+ * short jumps, as branching to .text.init section from .text is usually
+ * impossible */
+		__INIT
 /* Acquire boot time privileged register values, this will help debugging.
  * I figure out and store nwindows and nwindowsm1 later on.
  */
@@ -852,7 +857,22 @@
 		 nop
 
 sun4m_init:
-	/* All sun4m processors can do hw mul/div/rem, patch 'em. */
+	/* XXX Fucking Cypress... */
+	lda	[%g0] ASI_M_MMUREGS, %g5
+	srl	%g5, 28, %g4
+
+	cmp	%g4, 1
+	bne	1f
+	 srl	%g5, 24, %g4
+
+	and	%g4, 0xf, %g4
+	cmp	%g4, 7		/* This would be a HyperSparc. */
+
+	bne	2f
+	 nop
+
+1:
+
 #define PATCH_IT(dst, src)	\
 	set	(dst), %g5;	\
 	set	(src), %g4;	\
@@ -902,7 +922,7 @@
  * clear them so we don't get magic faults later on.
  */
 /* This sucks, apparently this makes Vikings call prom panic, will fix later */
-
+2:
 		rd	%psr, %o1
 		srl	%o1, 28, %o1		! Get a type of the CPU
 
@@ -1128,6 +1148,8 @@
 		ld	[%g7 + 0x74], %o0
 		call	%o0			! Get us out of here...
 		 nop				! Apparently Solaris is better.
+
+/* Ok, now we continue in the .data/.text sections */
 
 	.data
 	.align 4
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/idprom.c linux/arch/sparc/kernel/idprom.c
--- v2.1.15/linux/arch/sparc/kernel/idprom.c	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/idprom.c	Fri Dec 13 11:37:30 1996
@@ -1,4 +1,4 @@
-/* $Id: idprom.c,v 1.21 1996/10/12 13:12:48 davem Exp $
+/* $Id: idprom.c,v 1.22 1996/11/13 05:09:25 davem Exp $
  * idprom.c: Routines to load the idprom into kernel addresses and
  *           interpret the data contained within.
  *
@@ -7,6 +7,7 @@
 
 #include <linux/kernel.h>
 #include <linux/types.h>
+#include <linux/init.h>
 
 #include <asm/oplib.h>
 #include <asm/idprom.h>
@@ -35,12 +36,12 @@
 { "Sun4c SparcStation IPX", (SM_SUN4C | SM_4C_IPX) },
 /* Finally, early Sun4m's */
 { "Sun4m SparcSystem600", (SM_SUN4M | SM_4M_SS60) },
-{ "Sun4m SparcStation10", (SM_SUN4M | SM_4M_SS50) },
+{ "Sun4m SparcStation10/20", (SM_SUN4M | SM_4M_SS50) },
 { "Sun4m SparcStation5", (SM_SUN4M | SM_4M_SS40) },
 /* One entry for the OBP arch's which are sun4d, sun4e, and newer sun4m's */
 { "Sun4M OBP based system", (SM_SUN4M_OBP | 0x0) } };
 
-static void display_system_type(unsigned char machtype)
+__initfunc(static void display_system_type(unsigned char machtype))
 {
 	char sysname[128];
 	register int i;
@@ -63,7 +64,7 @@
 }
 
 /* Calculate the IDPROM checksum (xor of the data bytes). */
-static unsigned char calc_idprom_cksum(struct idprom *idprom)
+__initfunc(static unsigned char calc_idprom_cksum(struct idprom *idprom))
 {
 	unsigned char cksum, i, *ptr = (unsigned char *)idprom;
 
@@ -74,7 +75,7 @@
 }
 
 /* Create a local IDPROM copy, verify integrity, and display information. */
-void idprom_init(void)
+__initfunc(void idprom_init(void))
 {
 	prom_get_idprom((char *) &idprom_buffer, sizeof(idprom_buffer));
 
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/initobj.S linux/arch/sparc/kernel/initobj.S
--- v2.1.15/linux/arch/sparc/kernel/initobj.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/kernel/initobj.S	Fri Dec 13 11:37:30 1996
@@ -0,0 +1,18 @@
+#include <asm/errno.h>
+
+#if defined (__svr4__) || defined (__ELF__)
+
+	.section	".text.init",#alloc,#execinstr
+	.globl	text_init_begin
+text_init_begin:
+	.section	".data.init",#alloc,#write
+	.globl	data_init_begin
+data_init_begin:
+#endif
+
+	.section	".fixup",#alloc,#execinstr
+	.globl	__ret_efault
+__ret_efault:
+	ret
+	 restore %g0, -EFAULT, %o0
+
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/irq.c linux/arch/sparc/kernel/irq.c
--- v2.1.15/linux/arch/sparc/kernel/irq.c	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/irq.c	Fri Dec 13 11:37:30 1996
@@ -1,4 +1,4 @@
-/*  $Id: irq.c,v 1.53 1996/10/16 12:30:18 zaitcev Exp $
+/*  $Id: irq.c,v 1.57 1996/11/30 02:13:53 davem Exp $
  *  arch/sparc/kernel/irq.c:  Interrupt request handling routines. On the
  *                            Sparc the IRQ's are basically 'cast in stone'
  *                            and you are supposed to probe the prom's device
@@ -20,6 +20,7 @@
 #include <linux/interrupt.h>
 #include <linux/malloc.h>
 #include <linux/random.h>
+#include <linux/init.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -139,7 +140,8 @@
 	}
 	if (dev_id) {
 		for (; action; action = action->next) {
-			if (action->dev_id == dev_id) break;
+			if (action->dev_id == dev_id)
+				break;
 			tmp = action;
 		}
 		if (!action) {
@@ -205,9 +207,6 @@
 	cpu_irq = irq & NR_IRQS;
 	action = *(cpu_irq + irq_action);
 	kstat.interrupts[cpu_irq]++;
-#if 0
-	printk("I<%d,%d,%d>", smp_processor_id(), irq, smp_proc_in_lock[smp_processor_id()]);
-#endif
 	do {
 		if (!action || !action->handler)
 			unexpected_irq(irq, 0, regs);
@@ -244,6 +243,7 @@
 			panic("Trying to register fast irq as shared.\n");
 
 		/* Anyway, someone already owns it so cannot be made fast. */
+		printk("request_fast_irq: Trying to register yet already owned.\n");
 		return -EBUSY;
 	}
 
@@ -296,6 +296,7 @@
 	action->mask = 0;
 	action->name = devname;
 	action->dev_id = NULL;
+	action->next = NULL;
 
 	*(cpu_irq + irq_action) = action;
 
@@ -329,6 +330,7 @@
 			printk("Attempt to mix fast and slow interrupts on IRQ%d denied\n", irq);
 			return -EBUSY;
 		}   
+		action = NULL;		/* Or else! */
 	}
 
 	save_and_cli(flags);
@@ -389,7 +391,7 @@
  *
  */
 
-void init_IRQ(void)
+__initfunc(void init_IRQ(void))
 {
 	extern void sun4c_init_IRQ( void );
 	extern void sun4m_init_IRQ( void );
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/muldiv.c linux/arch/sparc/kernel/muldiv.c
--- v2.1.15/linux/arch/sparc/kernel/muldiv.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/kernel/muldiv.c	Fri Dec 13 11:37:30 1996
@@ -0,0 +1,215 @@
+/* $Id: muldiv.c,v 1.3 1996/11/26 10:00:28 jj Exp $
+ * muldiv.c: Hardware multiply/division illegal instruction trap
+ *		for sun4c/sun4 (which do not have those instructions)
+ *
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+/* #define DEBUG_MULDIV */
+
+static inline int has_imm13(int insn)
+{
+	return (insn & 0x2000);
+}
+
+static inline int is_foocc(int insn)
+{
+	return (insn & 0x800000);
+}
+
+static inline int sign_extend_imm13(int imm)
+{
+	return imm << 19 >> 19;
+}
+
+static inline void advance(struct pt_regs *regs)
+{
+	regs->pc   = regs->npc;
+	regs->npc += 4;
+}
+
+static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2,
+				       unsigned int rd)
+{
+	if(rs2 >= 16 || rs1 >= 16 || rd >= 16) {
+		/* Wheee... */
+		__asm__ __volatile__("save %sp, -0x40, %sp\n\t"
+				     "save %sp, -0x40, %sp\n\t"
+				     "save %sp, -0x40, %sp\n\t"
+				     "save %sp, -0x40, %sp\n\t"
+				     "save %sp, -0x40, %sp\n\t"
+				     "save %sp, -0x40, %sp\n\t"
+				     "save %sp, -0x40, %sp\n\t"
+				     "restore; restore; restore; restore;\n\t"
+				     "restore; restore; restore;\n\t");
+	}
+}
+
+#define fetch_reg(reg, regs) ({							\
+	struct reg_window *win;							\
+	register unsigned long ret;						\
+										\
+	if (!(reg)) ret = 0;							\
+	else if((reg) < 16) {							\
+		ret = regs->u_regs[(reg)];					\
+	} else {								\
+		/* Ho hum, the slightly complicated case. */			\
+		win = (struct reg_window *)regs->u_regs[UREG_FP];		\
+		if (get_user (ret, &win->locals[(reg) - 16])) return -1;	\
+	}									\
+	ret;									\
+})
+
+static inline unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs)
+{
+	struct reg_window *win;
+
+	if(!reg)
+		return NULL;
+	else if(reg < 16)
+		return &regs->u_regs[reg];
+	win = (struct reg_window *) regs->u_regs[UREG_FP];
+	return &win->locals[reg - 16];
+}
+
+extern void handle_hw_divzero (struct pt_regs *regs, unsigned long pc,
+			       unsigned long npc, unsigned long psr);
+
+/* Should return 0 if mul/div emulation succeeded and SIGILL should not be issued */
+int do_user_muldiv(struct pt_regs *regs, unsigned long pc)
+{
+	unsigned int insn;
+	int inst;
+	unsigned int rs1, rs2, rdv;
+	unsigned long *rd;
+
+	if (!pc) return -1; /* This happens to often, I think */
+	if (get_user (insn, (unsigned int *)pc)) return -1;
+	if ((insn & 0xc1400000) != 0x80400000) return -1;
+	inst = ((insn >> 19) & 0xf);
+	if ((inst & 0xe) != 10 && (inst & 0xe) != 14) return -1;
+	/* Now we know we have to do something with umul, smul, udiv or sdiv */
+	rs1 = (insn >> 14) & 0x1f;
+	rs2 = insn & 0x1f;
+	rdv = (insn >> 25) & 0x1f;
+	if(has_imm13(insn)) {
+		maybe_flush_windows(rs1, 0, rdv);
+		rs2 = sign_extend_imm13(insn);
+	} else {
+		maybe_flush_windows(rs1, rs2, rdv);
+		rs2 = fetch_reg(rs2, regs);
+	}
+	rs1 = fetch_reg(rs1, regs);
+	rd = fetch_reg_addr(rdv, regs);
+	switch (inst) {
+	case 10: /* umul */
+#ifdef DEBUG_MULDIV	
+		printk ("unsigned muldiv: 0x%x * 0x%x = ", rs1, rs2);
+#endif		
+		__asm__ __volatile__ ("\n\t"
+			"mov	%0, %%o0\n\t"
+			"call	.umul\n\t"
+			" mov	%1, %%o1\n\t"
+			"mov	%%o0, %0\n\t"
+			"mov	%%o1, %1\n\t" : "=r" (rs1), "=r" (rs2) : : "o0", "o1", "o2", "o3", "o4", "o5", "o7");
+#ifdef DEBUG_MULDIV
+		printk ("0x%x%08x\n", rs2, rs1);
+#endif
+		if (rd) {
+			if (put_user (rs1, rd)) return -1;
+		}
+		regs->y = rs2;
+		break;
+	case 11: /* smul */
+#ifdef DEBUG_MULDIV
+		printk ("signed muldiv: 0x%x * 0x%x = ", rs1, rs2);
+#endif
+		__asm__ __volatile__ ("\n\t"
+			"mov	%0, %%o0\n\t"
+			"call	.mul\n\t"
+			" mov	%1, %%o1\n\t"
+			"mov	%%o0, %0\n\t"
+			"mov	%%o1, %1\n\t" : "=r" (rs1), "=r" (rs2) : : "o0", "o1", "o2", "o3", "o4", "o5", "o7");
+#ifdef DEBUG_MULDIV
+		printk ("0x%x%08x\n", rs2, rs1);
+#endif
+		if (rd) {
+			if (put_user (rs1, rd)) return -1;
+		}
+		regs->y = rs2;
+		break;
+	case 14: /* udiv */
+#ifdef DEBUG_MULDIV
+		printk ("unsigned muldiv: 0x%x%08x / 0x%x = ", regs->y, rs1, rs2);
+#endif
+		if (!rs2) {
+#ifdef DEBUG_MULDIV
+			printk ("DIVISION BY ZERO\n");
+#endif
+			handle_hw_divzero (regs, pc, regs->npc, regs->psr);
+			return 0;
+		}
+		__asm__ __volatile__ ("\n\t"
+			"mov	%2, %%o0\n\t"
+			"mov	%0, %%o1\n\t"
+			"mov	%%g0, %%o2\n\t"
+			"call	__udivdi3\n\t"
+			" mov	%1, %%o3\n\t"
+			"mov	%%o1, %0\n\t"
+			"mov	%%o0, %1\n\t" : "=r" (rs1), "=r" (rs2) : "r" (regs->y) : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3");
+#ifdef DEBUG_MULDIV
+		printk ("0x%x\n", rs1);
+#endif
+		if (rd)
+                        if (put_user (rs1, rd)) return -1;
+		break;
+	case 15: /* sdiv */
+#ifdef DEBUG_MULDIV
+		printk ("signed muldiv: 0x%x%08x / 0x%x = ", regs->y, rs1, rs2);
+#endif
+		if (!rs2) {
+#ifdef DEBUG_MULDIV
+			printk ("DIVISION BY ZERO\n");
+#endif
+			handle_hw_divzero (regs, pc, regs->npc, regs->psr);
+			return 0;
+		}
+		__asm__ __volatile__ ("\n\t"
+			"mov	%2, %%o0\n\t"
+			"mov	%0, %%o1\n\t"
+			"mov	%%g0, %%o2\n\t"
+			"call	__divdi3\n\t"
+			" mov	%1, %%o3\n\t"
+			"mov	%%o1, %0\n\t"
+			"mov	%%o0, %1\n\t" : "=r" (rs1), "=r" (rs2) : "r" (regs->y) : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3");
+#ifdef DEBUG_MULDIV
+		printk ("0x%x\n", rs1);
+#endif
+		if (rd)
+                        if (put_user (rs1, rd)) return -1;
+		break;
+	}
+	if (is_foocc (insn)) {
+		regs->psr &= ~PSR_ICC;
+		if ((inst & 0xe) == 14) {
+			/* ?div */
+			if (rs2) regs->psr |= PSR_V;
+		}
+		if (!rs1) regs->psr |= PSR_Z;
+		if (((int)rs1) < 0) regs->psr |= PSR_N;
+#ifdef DEBUG_MULDIV
+		printk ("psr muldiv: %08x\n", regs->psr);
+#endif
+	}
+	advance(regs);
+	return 0;
+}
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- v2.1.15/linux/arch/sparc/kernel/process.c	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/process.c	Fri Dec 13 11:37:31 1996
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.77 1996/11/03 08:25:43 davem Exp $
+/*  $Id: process.c,v 1.83 1996/12/10 07:38:39 davem Exp $
  *  linux/arch/sparc/kernel/process.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -40,6 +40,8 @@
 
 #ifndef __SMP__
 
+#define SUN4C_FAULT_HIGH 100
+
 /*
  * the idle loop on a Sparc... ;)
  */
@@ -51,6 +53,36 @@
 	/* endless idle loop with no priority at all */
 	current->counter = -100;
 	for (;;) {
+		if (sparc_cpu_model == sun4c) {
+			static int count = HZ;
+			static unsigned long last_jiffies = 0;
+			static unsigned long last_faults = 0;
+			static unsigned long fps = 0;
+			unsigned long now;
+			unsigned long faults;
+			unsigned long flags;
+
+			extern unsigned long sun4c_kernel_faults;
+			extern void sun4c_grow_kernel_ring(void);
+
+			save_and_cli(flags);
+			now = jiffies;
+			count -= (now - last_jiffies);
+			last_jiffies = now;
+			if (count < 0) {
+				count += HZ;
+				faults = sun4c_kernel_faults;
+				fps = (fps + (faults - last_faults)) >> 1;
+				last_faults = faults;
+#if 0
+				printk("kernel faults / second = %d\n", fps);
+#endif
+				if (fps >= SUN4C_FAULT_HIGH) {
+					sun4c_grow_kernel_ring();
+				}
+			}
+			restore_flags(flags);
+		}
 		schedule();
 	}
 	return 0;
@@ -273,6 +305,8 @@
 	current->tss.sstk_info.cur_status = 0;
 	current->tss.sstk_info.the_stack = 0;
 
+	/* No new signal delivey by default */
+	current->tss.new_signal = 0;
 #ifndef __SMP__
 	if(last_task_used_math == current) {
 #else
@@ -292,6 +326,7 @@
 	mmu_flush_hook();
 	/* Now, this task is no longer a kernel thread. */
 	current->tss.flags &= ~SPARC_FLAG_KTHREAD;
+	current->tss.current_ds = USER_DS;
 }
 
 static __inline__ void copy_regs(struct pt_regs *dst, struct pt_regs *src)
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/rtrap.S linux/arch/sparc/kernel/rtrap.S
--- v2.1.15/linux/arch/sparc/kernel/rtrap.S	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/rtrap.S	Fri Dec 13 11:37:31 1996
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.39 1996/10/28 07:49:01 davem Exp $
+/* $Id: rtrap.S,v 1.40 1996/12/10 06:06:18 davem Exp $
  * rtrap.S: Return from Sparc trap low-level code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -69,8 +69,10 @@
 	be	1f
 	 sethi	%hi(C_LABEL(need_resched)), %twin_tmp1
 
+	wr	%t_psr, 0x0, %psr
+	WRITE_PAUSE
 	b	ret_trap_kernel
-	 wr	%t_psr, 0x0, %psr
+	 nop
 
 1:
 	ld	[%twin_tmp1 + %lo(C_LABEL(need_resched))], %g2
@@ -99,6 +101,7 @@
 	clr	%l6
 ret_trap_continue:
 	wr	%t_psr, 0x0, %psr
+	WRITE_PAUSE
 
 	ld	[%curptr + THREAD_W_SAVED], %twin_tmp1
 	orcc	%g0, %twin_tmp1, %g0
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/setup.c linux/arch/sparc/kernel/setup.c
--- v2.1.15/linux/arch/sparc/kernel/setup.c	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/setup.c	Fri Dec 13 11:37:31 1996
@@ -1,4 +1,4 @@
-/*  $Id: setup.c,v 1.75 1996/10/12 12:37:27 davem Exp $
+/*  $Id: setup.c,v 1.76 1996/11/13 05:09:32 davem Exp $
  *  linux/arch/sparc/kernel/setup.c
  *
  *  Copyright (C) 1995  David S. Miller (davem@caip.rutgers.edu)
@@ -23,6 +23,7 @@
 #include <linux/major.h>
 #include <linux/string.h>
 #include <linux/blk.h>
+#include <linux/init.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -140,7 +141,7 @@
  * Process kernel command line switches that are specific to the
  * SPARC or that require special low-level processing.
  */
-static void process_switch(char c)
+__initfunc(static void process_switch(char c))
 {
 	switch (c) {
 	case 'd':
@@ -159,7 +160,7 @@
 	}
 }
 
-static void boot_flags_init(char *commands)
+__initfunc(static void boot_flags_init(char *commands))
 {
 	while (*commands) {
 		/* Move to the start of the next "argument". */
@@ -224,13 +225,13 @@
  * physical memory probe as on the alpha.
  */
 
-extern void load_mmu(void);
 extern int prom_probe_memory(void);
 extern void sun4c_probe_vac(void);
 extern char cputypval;
 extern unsigned long start, end;
 extern void panic_setup(char *, int *);
 extern unsigned long srmmu_endmem_fixup(unsigned long);
+extern unsigned long sun_serial_setup(unsigned long);
 
 extern unsigned short root_flags;
 extern unsigned short root_dev;
@@ -251,8 +252,8 @@
 
 static struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } };
 
-void setup_arch(char **cmdline_p,
-	unsigned long * memory_start_p, unsigned long * memory_end_p)
+__initfunc(void setup_arch(char **cmdline_p,
+	unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
 	int total, i, packed;
 
@@ -384,6 +385,7 @@
 	init_task.mm->mmap->vm_end = *memory_end_p;
 	init_task.tss.kregs = &fake_swapper_regs;
 
+	*memory_start_p = sun_serial_setup(*memory_start_p); /* set this up ASAP */
 	{
 		extern int serial_console;  /* in console.c, of course */
 #if !CONFIG_SUN_SERIAL
@@ -435,6 +437,7 @@
 	return sprintf(buffer, "cpu\t\t: %s\n"
             "fpu\t\t: %s\n"
             "promlib\t\t: Version %d Revision %d\n"
+            "prom\t\t: %d.%d\n"
             "type\t\t: %s\n"
 	    "ncpus probed\t: %d\n"
 	    "ncpus active\t: %d\n"
@@ -454,9 +457,9 @@
             sparc_cpu_type[cpuid],
             sparc_fpu_type[cpuid],
 #if CONFIG_AP1000
-            0, 0,
+            0, 0, 0, 0
 #else
-            romvec->pv_romvers, prom_rev,
+            romvec->pv_romvers, prom_rev, romvec->pv_printrev >> 16, (short)romvec->pv_printrev,
 #endif
             &cputypval,
 	    linux_num_cpus, smp_num_cpus,
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c
--- v2.1.15/linux/arch/sparc/kernel/signal.c	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/signal.c	Fri Dec 13 11:37:31 1996
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.57 1996/10/31 00:59:01 davem Exp $
+/*  $Id: signal.c,v 1.64 1996/12/03 08:44:34 jj Exp $
  *  linux/arch/sparc/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -19,23 +19,63 @@
 #include <asm/bitops.h>
 #include <asm/ptrace.h>
 #include <asm/svr4.h>
+#include <asm/pgtable.h>
 
 #define _S(nr) (1<<((nr)-1))
 
 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
 
 asmlinkage int sys_waitpid(pid_t pid, unsigned long *stat_addr, int options);
+extern void fpload(unsigned long *fpregs, unsigned long *fsr);
 asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs,
 			 unsigned long orig_o0, int ret_from_syscall);
 
 /* This turned off for production... */
-/* #define DEBUG_FATAL_SIGNAL 1 */
+/* #define DEBUG_SIGNALS 1 */
 
-#ifdef DEBUG_FATAL_SIGNAL
-extern void instruction_dump (unsigned long *pc);
-#endif
+/* Signal frames: the original one (compatible with SunOS):
+ *
+ * Set up a signal frame... Make the stack look the way SunOS
+ * expects it to look which is basically:
+ *
+ * ---------------------------------- <-- %sp at signal time
+ * Struct sigcontext
+ * Signal address
+ * Ptr to sigcontext area above
+ * Signal code
+ * The signal number itself
+ * One register window
+ * ---------------------------------- <-- New %sp
+ */
+struct signal_sframe {
+	struct reg_window sig_window;
+	int sig_num;
+	int sig_code;
+	struct sigcontext *sig_scptr;
+	int sig_address;
+	struct sigcontext sig_context;
+};
+
+/* 
+ * And the new one, intended to be used for Linux applications only
+ * (we have enough in there to work with clone).
+ * All the interesting bits are in the info field.
+ */
+
+struct new_signal_frame {
+	struct      sparc_stackf ss;
+	struct      reg_window sig_window;
+	__siginfo_t info;
+	unsigned    long __pad;
+	unsigned    long insns [2];
+};
 
-/* atomically swap in the new signal mask, and wait for a signal.
+/* Align macros */
+#define SF_ALIGNEDSZ  (((sizeof(struct signal_sframe) + 7) & (~7)))
+#define NF_ALIGNEDSZ  (((sizeof(struct new_signal_frame) + 7) & (~7)))
+
+/*
+ * atomically swap in the new signal mask, and wait for a signal.
  * This is really tricky on the Sparc, watch out...
  */
 asmlinkage inline void _sigpause_common(unsigned int set, struct pt_regs *regs)
@@ -76,14 +116,49 @@
 	_sigpause_common(regs->u_regs[UREG_I0], regs);
 }
 
+void do_new_sigreturn (struct pt_regs *regs)
+{
+	struct new_signal_frame *sf;
+	unsigned long up_psr;
+	
+	sf = (struct new_signal_frame *) regs->u_regs [UREG_FP];
+	/* 1. Make sure we are not getting garbage from the user */
+	if (verify_area (VERIFY_READ, sf, sizeof (*sf))){
+		do_exit (SIGSEGV);
+		return;
+	}
+	if (((uint) sf) & 3){
+		do_exit (SIGSEGV);
+		return;
+	}
+	if ((sf->info.si_regs.pc | sf->info.si_regs.npc) & 3){
+		do_exit (SIGSEGV);
+		return;
+	}
+	
+	/* 2. Restore the state */
+	up_psr = regs->psr;
+	memcpy (regs, &sf->info.si_regs, sizeof (struct pt_regs));
+
+	/* User can only change condition codes in %psr. */
+	regs->psr = (up_psr & ~(PSR_ICC)) | (regs->psr & PSR_ICC);
+	
+	if (regs->psr & PSR_EF)
+		fpload (&sf->info.si_float_regs [0], &sf->info.si_fsr);
+	current->blocked = sf->info.si_mask & _BLOCKABLE;
+}
+
 asmlinkage void do_sigreturn(struct pt_regs *regs)
 {
-	struct sigcontext *scptr =
-		(struct sigcontext *) regs->u_regs[UREG_I0];
+	struct sigcontext *scptr;
 	unsigned long pc, npc, psr;
 
 	synchronize_user_stack();
-
+	if (current->tss.new_signal){
+		do_new_sigreturn (regs);
+		return;
+	}
+	scptr = (struct sigcontext *) regs->u_regs[UREG_I0];
 	/* Check sanity of the user arg. */
 	if(verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext)) ||
 	   (((unsigned long) scptr) & 3)) {
@@ -113,29 +188,6 @@
 	regs->psr |= (psr & PSR_ICC);
 }
 
-/* Set up a signal frame... Make the stack look the way SunOS
- * expects it to look which is basically:
- *
- * ---------------------------------- <-- %sp at signal time
- * Struct sigcontext
- * Signal address
- * Ptr to sigcontext area above
- * Signal code
- * The signal number itself
- * One register window
- * ---------------------------------- <-- New %sp
- */
-struct signal_sframe {
-	struct reg_window sig_window;
-	int sig_num;
-	int sig_code;
-	struct sigcontext *sig_scptr;
-	int sig_address;
-	struct sigcontext sig_context;
-};
-/* To align the structure properly. */
-#define SF_ALIGNEDSZ  (((sizeof(struct signal_sframe) + 7) & (~7)))
-
 /* Checks if the fp is valid */
 int invalid_frame_pointer (void *fp, int fplen)
 {
@@ -161,7 +213,7 @@
 	sframep = (struct signal_sframe *) regs->u_regs[UREG_FP];
 	sframep = (struct signal_sframe *) (((unsigned long) sframep)-SF_ALIGNEDSZ);
 	if (invalid_frame_pointer (sframep, sizeof(*sframep))){
-#if 0 /* fills up the console logs during crashme runs, yuck... */
+#ifdef DEBUG_SIGNALS /* fills up the console logs during crashme runs, yuck... */
 		printk("%s [%d]: User has trashed signal stack\n",
 		       current->comm, current->pid);
 		printk("Sigstack ptr %p handler at pc<%08lx> for sig<%d>\n",
@@ -217,6 +269,56 @@
 	regs->npc = (regs->pc + 4);
 }
 
+/* To align the structure properly. */
+
+static inline void
+new_setup_frame(struct sigaction *sa, struct pt_regs *regs, int signo, unsigned long oldmask)
+{
+	struct new_signal_frame *sf;
+
+	/* 1. Make sure everything is clean */
+	synchronize_user_stack();
+	sf = (struct new_signal_frame *) regs->u_regs[UREG_FP];
+	sf = (struct new_signal_frame *) (((unsigned long) sf)-NF_ALIGNEDSZ);
+	
+	if (invalid_frame_pointer (sf, sizeof(struct new_signal_frame))){
+		do_exit(SIGILL);
+		return;
+	}
+
+	if (current->tss.w_saved != 0){
+		printk ("Ay Caramba!  w_saved not zero!\n");
+		do_exit (SIGILL);
+		return;
+	}
+
+	/* 2. Save the state current process state */
+	memcpy (&sf->info.si_regs, regs, sizeof (struct pt_regs));
+	if (regs->psr & PSR_EF){
+		fpsave (&sf->info.si_float_regs [0], &sf->info.si_fsr,
+			&sf->info.si_fpqueue[0], &sf->info.si_fpqdepth);
+	}
+	sf->info.si_mask = oldmask;
+	memcpy (sf, (char *) regs->u_regs [UREG_FP], sizeof (struct reg_window));
+	
+	/* 3. return to kernel instructions */
+	sf->insns [0] = 0x821020d8; /* mov __NR_sigreturn,%g1 */
+	sf->insns [1] = 0x91d02010; /* t 0x10 */
+
+	/* 4. signal handler back-trampoline and parameters */
+	regs->u_regs[UREG_FP] = (unsigned long) sf;
+	regs->u_regs[UREG_I0] = signo;
+	regs->u_regs[UREG_I1] = (unsigned long) &sf->info;
+	regs->u_regs[UREG_I7] = (unsigned long) (&(sf->insns[0]) - 2);
+
+	/* 5. signal handler */
+	regs->pc = (unsigned long) sa->sa_handler;
+	regs->npc = (regs->pc + 4);
+
+	/* Flush cache, replace this with a generic thingie */
+	flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
+}
+
 /* Setup a Solaris stack frame */
 static inline void
 setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc,
@@ -235,7 +337,7 @@
 	sfp = (svr4_signal_frame_t *) (((unsigned long) sfp)-SVR4_SF_ALIGNED);
 
 	if (invalid_frame_pointer (sfp, sizeof (*sfp))){
-#if 0
+#ifdef DEBUG_SIGNALS
 		printk ("Invalid stack frame\n");
 #endif
 		do_exit(SIGILL);
@@ -265,8 +367,8 @@
 	__put_user(regs->y, &((*gr) [SVR4_Y]));
 	
 	/* Copy g [1..7] and o [0..7] registers */
-	copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (uint) * 7);
-	copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (uint) * 8);
+	copy_to_user(&(*gr)[SVR4_G1], &regs->u_regs [UREG_G1], sizeof (long) * 7);
+	copy_to_user(&(*gr)[SVR4_O0], &regs->u_regs [UREG_I0], sizeof (long) * 8);
 
 	/* Setup sigaltstack, FIXME */
 	__put_user(0xdeadbeef, &uc->stack.sp);
@@ -313,6 +415,9 @@
 	regs->pc = (unsigned long) sa->sa_handler;
 	regs->npc = (regs->pc + 4);
 
+#ifdef DEBUG_SIGNALS
+	printk ("Solaris-frame: %x %x\n", (int) regs->pc, (int) regs->npc);
+#endif
 	/* Arguments passed to signal handler */
 	if (regs->u_regs [14]){
 		struct reg_window *rw = (struct reg_window *) regs->u_regs [14];
@@ -321,11 +426,9 @@
 		__put_user(si, &rw->ins [1]);
 		__put_user(uc, &rw->ins [2]);
 		__put_user(sfp, &rw->ins [6]);	/* frame pointer */
-#if 0
 		regs->u_regs[UREG_I0] = signr;
 		regs->u_regs[UREG_I1] = (uint) si;
 		regs->u_regs[UREG_I2] = (uint) uc;
-#endif
 	}
 }
 
@@ -407,20 +510,21 @@
 		do_exit (SIGSEGV);
 	}
 	/* Retrieve information from passed ucontext */
+	    /* note that nPC is ored a 1, this is used to inform entry.S */
+	    /* that we don't want it to mess with our PC and nPC */
 	__get_user(current->blocked, &c->sigmask.sigbits [0]);
 	current->blocked &= _BLOCKABLE;
 	regs->pc = pc;
-	regs->npc = npc;
+	regs->npc = npc | 1;
 	__get_user(regs->y, &((*gr) [SVR4_Y]));
 	__get_user(psr, &((*gr) [SVR4_PSR]));
 	regs->psr &= ~(PSR_ICC);
 	regs->psr |= (psr & PSR_ICC);
 
 	/* Restore g[1..7] and o[0..7] registers */
-	copy_from_user(&regs->u_regs [UREG_G1], &(*gr)[SVR4_G1], sizeof (uint) * 7);
-	copy_from_user(&regs->u_regs [UREG_I0], &(*gr)[SVR4_O0], sizeof (uint) * 8);
+	copy_from_user(&regs->u_regs [UREG_G1], &(*gr)[SVR4_G1], sizeof (long) * 7);
+	copy_from_user(&regs->u_regs [UREG_I0], &(*gr)[SVR4_O0], sizeof (long) * 8);
 
-	printk ("Setting PC=%lx nPC=%lx\n", regs->pc, regs->npc);
 	return -EINTR;
 }
 
@@ -430,9 +534,12 @@
 {
 	if(svr4_signal)
 		setup_svr4_frame(sa, regs->pc, regs->npc, regs, signr, oldmask);
-	else
-		setup_frame(sa, regs->pc, regs->npc, regs, signr, oldmask);
-
+	else {
+		if (current->tss.new_signal)
+			new_setup_frame (sa, regs, signr, oldmask);
+		else
+			setup_frame(sa, regs->pc, regs->npc, regs, signr, oldmask);
+	}
 	if(sa->sa_flags & SA_ONESHOT)
 		sa->sa_handler = NULL;
 	if(!(sa->sa_flags & SA_NOMASK))
@@ -525,6 +632,11 @@
 					if(current->binfmt->core_dump(signr, regs))
 						signr |= 0x80;
 				}
+#ifdef DEBUG_SIGNALS
+				/* Very useful to debug dynamic linker problems */
+				printk ("Sig ILL going...\n");
+				show_regs (regs);
+#endif
 				/* fall through */
 			default:
 				current->signal |= _S(signr & 0x7f);
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c
--- v2.1.15/linux/arch/sparc/kernel/smp.c	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/smp.c	Fri Dec 13 11:37:31 1996
@@ -558,6 +558,9 @@
 void smp_flush_page_to_ram(unsigned long page)
 { xc1((smpfunc_t) local_flush_page_to_ram, page); }
 
+void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
+{ xc2((smpfunc_t) local_flush_sig_insns, (unsigned long) mm, insn_addr); }
+
 /* Reschedule call back. */
 void smp_reschedule_irq(void)
 {
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/solaris.c linux/arch/sparc/kernel/solaris.c
--- v2.1.15/linux/arch/sparc/kernel/solaris.c	Sun Apr 21 12:30:31 1996
+++ linux/arch/sparc/kernel/solaris.c	Fri Dec 13 11:37:31 1996
@@ -10,6 +10,8 @@
 #include <asm/errno.h>
 #include <asm/solerrno.h>
 
+#if 0
+/* Not used - actually translated in iBCS */
 unsigned long solaris_xlatb_rorl[] = {
 	0, SOL_EPERM, SOL_ENOENT, SOL_ESRCH, SOL_EINTR, SOL_EIO,
 	SOL_ENXIO, SOL_E2BIG, SOL_ENOEXEC, SOL_EBADF, SOL_ECHILD,
@@ -33,6 +35,7 @@
 	SOL_ESRMNT, SOL_ECOMM, SOL_EPROTO, SOL_EMULTIHOP, SOL_EINVAL,
 	SOL_EREMCHG, SOL_ENOSYS
 };
+#endif
 
 extern asmlinkage int sys_open(const char *,int,int);
 
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/sparc_ksyms.c linux/arch/sparc/kernel/sparc_ksyms.c
--- v2.1.15/linux/arch/sparc/kernel/sparc_ksyms.c	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/sparc_ksyms.c	Fri Dec 13 11:37:31 1996
@@ -1,4 +1,4 @@
-/* $Id: sparc_ksyms.c,v 1.24 1996/10/27 08:36:08 davem Exp $
+/* $Id: sparc_ksyms.c,v 1.30 1996/12/03 08:44:44 jj Exp $
  * arch/sparc/kernel/ksyms.c: Sparc specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -24,9 +24,11 @@
 #include <asm/mostek.h>
 #include <asm/ptrace.h>
 #include <asm/user.h>
+#include <asm/uaccess.h>
 #ifdef CONFIG_SBUS
 #include <asm/sbus.h>
 #endif
+#include <asm/a.out.h>
 
 struct poll {
 	int fd;
@@ -50,8 +52,7 @@
 extern int __memcmp(const void *, const void *, __kernel_size_t);
 extern int __strncmp(const char *, const char *, __kernel_size_t);
 
-extern int __copy_to_user(unsigned long to, unsigned long from, int size);
-extern int __copy_from_user(unsigned long to, unsigned long from, int size);
+extern int __copy_user(unsigned long to, unsigned long from, int size);
 extern int __clear_user(unsigned long addr, int size);
 extern int __strncpy_from_user(unsigned long dest, unsigned long src, int count);
 
@@ -86,6 +87,7 @@
 	X(syscall_count),
 #endif
 	X(page_offset),
+	X(stack_top),
 
 	X(udelay),
 	X(mstk48t02_regs),
@@ -95,8 +97,16 @@
 	X(request_fast_irq),
 	X(sparc_alloc_io),
 	X(sparc_free_io),
+	X(mmu_v2p),
 	X(mmu_unlockarea),
 	X(mmu_lockarea),
+	X(mmu_get_scsi_sgl),
+	X(mmu_get_scsi_one),
+	X(mmu_release_scsi_sgl),
+	X(mmu_release_scsi_one),
+	X(sparc_dvma_malloc),
+	X(sun4c_unmapioaddr),
+	X(srmmu_unmapioaddr),
 	X(SBus_chain),
 
 	/* Solaris/SunOS binary compatibility */
@@ -125,6 +135,9 @@
 	X(prom_apply_obio_ranges),
 	X(prom_getname),
 	X(prom_feval),
+	X(prom_getstring),
+	X(prom_apply_sbus_ranges),
+	X(prom_getintdefault),
 	X(romvec),
 
 	/* sparc library symbols */
@@ -158,10 +171,14 @@
 	X(__strncmp),
 
 	/* Moving data to/from userspace. */
-	X(__copy_to_user),
-	X(__copy_from_user),
+	X(__copy_user),
 	X(__clear_user),
 	X(__strncpy_from_user),
+
+	/* No version information on this, heavily used in inline asm,
+	 * and will always be 'void __ret_efault(void)'.
+	 */
+	XNOVERS(__ret_efault),
 
 	/* No version information on these, as gcc produces such symbols. */
 	XNOVERS(memcmp),
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/sparc_namei.c linux/arch/sparc/kernel/sparc_namei.c
--- v2.1.15/linux/arch/sparc/kernel/sparc_namei.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/kernel/sparc_namei.c	Fri Dec 13 11:37:31 1996
@@ -0,0 +1,61 @@
+/* $Id: sparc_namei.c,v 1.2 1996/12/12 09:39:25 jj Exp $
+ * linux/arch/sparc/kernel/sparc_namei.c
+ *
+ * Routines to handle famous /usr/gnemul/s*.
+ * Included from linux/fs/namei.c
+ */
+
+
+#define BSD_EMUL "usr/gnemul/sunos/"
+#define SOL_EMUL "usr/gnemul/solaris/"
+
+static int dir_namei(const char *pathname, int *namelen, const char **name,
+                     struct inode * base, struct inode **res_inode);
+static int _namei(const char * pathname, struct inode * base,
+                  int follow_links, struct inode ** res_inode);
+int open_namei(const char * pathname, int flag, int mode,
+               struct inode ** res_inode, struct inode * base);
+                     
+static int sparc_namei(const char ** pathname, struct inode ** base,
+		int follow_links, struct inode ** res_inode)
+{
+	struct inode *emul_ino;
+	int namelen;
+	const char *name;
+	int error;
+	
+	while (**pathname == '/')
+		(*pathname)++;
+	current->fs->root->i_count++;
+	if (dir_namei (current->personality & PER_BSD ? BSD_EMUL : SOL_EMUL, 
+		       &namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) {
+		*res_inode = NULL;
+		if ((error = _namei (*pathname, emul_ino, follow_links, res_inode)) >= 0 && *res_inode) {
+			return 0;
+		}
+	}
+	*base = current->fs->root;
+	(*base)->i_count++;
+	return -ENOTDIR;
+}
+
+static int sparc_open_namei(const char ** pathname, int flag, int mode,
+		struct inode ** res_inode, struct inode ** base)
+{
+	struct inode *emul_ino;
+	int namelen;
+	const char *name;
+	
+	while (**pathname == '/')
+		(*pathname)++;
+	current->fs->root->i_count++;
+	if (dir_namei (current->personality & PER_BSD ? BSD_EMUL : SOL_EMUL, 
+		       &namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) {
+		*res_inode = NULL;
+		if (open_namei (*pathname, flag /* & ~O_CREAT */, mode, res_inode, emul_ino) >= 0 && *res_inode)
+			return 0;
+	}
+	*base = current->fs->root;
+	(*base)->i_count++;
+	return -ENOTDIR;
+}
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/sun4c_irq.c linux/arch/sparc/kernel/sun4c_irq.c
--- v2.1.15/linux/arch/sparc/kernel/sun4c_irq.c	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/sun4c_irq.c	Fri Dec 13 11:37:31 1996
@@ -17,6 +17,7 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/malloc.h>
+#include <linux/init.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -120,7 +121,7 @@
 	/* Errm.. not sure how to do this.. */
 }
 
-static void sun4c_init_timers(void (*counter_fn)(int, void *, struct pt_regs *))
+__initfunc(static void sun4c_init_timers(void (*counter_fn)(int, void *, struct pt_regs *)))
 {
 	int irq;
 
@@ -155,7 +156,7 @@
 static void sun4c_nop(void) {}
 #endif
 
-void sun4c_init_IRQ(void)
+__initfunc(void sun4c_init_IRQ(void))
 {
 	struct linux_prom_registers int_regs[2];
 	int ie_node;
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/sun4m_irq.c linux/arch/sparc/kernel/sun4m_irq.c
--- v2.1.15/linux/arch/sparc/kernel/sun4m_irq.c	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/sun4m_irq.c	Fri Dec 13 11:37:31 1996
@@ -18,6 +18,7 @@
 #include <linux/smp.h>
 #include <linux/interrupt.h>
 #include <linux/malloc.h>
+#include <linux/init.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -195,7 +196,7 @@
 }
 #endif /* HANDLE_LVL14_IRQ */
 
-static void sun4m_init_timers(void (*counter_fn)(int, void *, struct pt_regs *))
+__initfunc(static void sun4m_init_timers(void (*counter_fn)(int, void *, struct pt_regs *)))
 {
 	int reg_count, irq, cpu;
 	struct linux_prom_registers cnt_regs[PROMREG_MAX];
@@ -266,7 +267,7 @@
 	}
 }
 
-void sun4m_init_IRQ(void)
+__initfunc(void sun4m_init_IRQ(void))
 {
 	int ie_node,i;
 	struct linux_prom_registers int_regs[PROMREG_MAX];
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/sunos_asm.S linux/arch/sparc/kernel/sunos_asm.S
--- v2.1.15/linux/arch/sparc/kernel/sunos_asm.S	Sun Apr 21 12:30:31 1996
+++ linux/arch/sparc/kernel/sunos_asm.S	Fri Dec 13 11:37:31 1996
@@ -1,4 +1,4 @@
-/* $Id: sunos_asm.S,v 1.12 1996/04/03 02:14:57 davem Exp $
+/* $Id: sunos_asm.S,v 1.14 1996/12/04 18:25:48 jj Exp $
  * sunos_asm.S: SunOS system calls which must have a low-level
  *              entry point to operate correctly.
  *
@@ -15,53 +15,44 @@
 	.text
 	.align 4
 
+	/* When calling ret_sys_call, %o0 should contain the same
+	 * value as in [%sp + REGWIN_SZ + PT_I0] */
+
 	/* SunOS getpid() returns pid in %o0 and ppid in %o1 */
 	.globl	C_LABEL(sunos_getpid)
 C_LABEL(sunos_getpid):
-	call	C_LABEL(sys_getpid)
-	 nop
-
-	st	%o0, [%sp + REGWIN_SZ + PT_I0]
-
 	call	C_LABEL(sys_getppid)
-	 nop	
+	 nop
 
-	st	%o0, [%sp + REGWIN_SZ + PT_I1]
+	call	C_LABEL(sys_getpid)
+	 st	%o0, [%sp + REGWIN_SZ + PT_I1]
 
 	b	C_LABEL(ret_sys_call)
-	 nop
+	 st	%o0, [%sp + REGWIN_SZ + PT_I0]
 
 	/* SunOS getuid() returns uid in %o0 and euid in %o1 */
 	.globl	C_LABEL(sunos_getuid)
 C_LABEL(sunos_getuid):
-	call	C_LABEL(sys_getuid)
-	 nop
-
-	st	%o0, [%sp + REGWIN_SZ + PT_I0]
-
 	call	C_LABEL(sys_geteuid)
 	 nop
 
-	st	%o0, [%sp + REGWIN_SZ + PT_I1]
+	call	C_LABEL(sys_getuid)
+	 st	%o0, [%sp + REGWIN_SZ + PT_I1]
 
 	b	C_LABEL(ret_sys_call)
-	 nop
+	 st	%o0, [%sp + REGWIN_SZ + PT_I0]
 
 	/* SunOS getgid() returns gid in %o0 and egid in %o1 */
 	.globl	C_LABEL(sunos_getgid)
 C_LABEL(sunos_getgid):
-	call	C_LABEL(sys_getgid)
-	 nop
-
-	st	%o0, [%sp + REGWIN_SZ + PT_I0]
-
 	call	C_LABEL(sys_getegid)
 	 nop
 
-	st	%o0, [%sp + REGWIN_SZ + PT_I1]
+	call	C_LABEL(sys_getgid)
+	 st	%o0, [%sp + REGWIN_SZ + PT_I1]
 
 	b	C_LABEL(ret_sys_call)
-	 nop
+	 st	%o0, [%sp + REGWIN_SZ + PT_I0]
 
 	/* SunOS's execv() call only specifies the argv argument, the
 	 * environment settings are the same as the calling processes.
@@ -74,7 +65,4 @@
 	 add	%sp, REGWIN_SZ, %o0
 
 	b	C_LABEL(ret_sys_call)
-	 nop
-
-	 
-
+	 ld	[%sp + REGWIN_SZ + PT_I0], %o0
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/switch.S linux/arch/sparc/kernel/switch.S
--- v2.1.15/linux/arch/sparc/kernel/switch.S	Mon May  6 12:26:03 1996
+++ linux/arch/sparc/kernel/switch.S	Thu Jan  1 02:00:00 1970
@@ -1,96 +0,0 @@
-/* $Id: switch.S,v 1.18 1996/04/03 02:15:00 davem Exp $
- * switch.S: Sparc task switch code.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <asm/head.h>
-#include <asm/asi.h>
-#include <asm/contregs.h>
-#include <asm/cprefix.h>
-#include <asm/psr.h>
-#include <asm/asmmacro.h>
-#include <asm/ptrace.h>
-#include <asm/winmacro.h>
-
-#define sw_ntask     g1
-#define sw_psr       g4
-#define sw_wim       g5
-#define sw_tmp       g6
-#define sw_ctx       g7
-
-/* Context switch code.  The new process's task_struct
- * ptr is passed as the first parameter.
- *
- * First successful task switch 05/13/95 21:52:37
- */
-	.align 4
-	.globl	C_LABEL(sparc_switch_to)
-C_LABEL(sparc_switch_to):
-	mov	%o0, %sw_ntask
-
-	/* Save kernel state. */
-	FLUSH_ALL_KERNEL_WINDOWS; 
-	STORE_WINDOW(sp)
-	rd	%psr, %sw_psr
-	LOAD_CURRENT(sw_tmp, sw_wim)
-	rd	%wim, %sw_wim
-	std	%sw_psr, [%sw_tmp + THREAD_KPSR]
-	std	%sp, [%sw_tmp + THREAD_KSP]
-
-	/* Load new kernel state. */
-	wr	%sw_psr, PSR_ET, %psr
-	WRITE_PAUSE
-#ifdef __SMP__
-	GET_PROCESSOR_OFFSET(sw_psr)
-	set	C_LABEL(current_set), %sw_tmp
-	st	%sw_ntask, [%sw_tmp + %sw_psr]
-#else
-	sethi	%hi(C_LABEL(current_set)), %sw_tmp
-	st	%sw_ntask, [%sw_tmp + %lo(C_LABEL(current_set))]
-#endif
-	ldd	[%sw_ntask + THREAD_KPSR], %sw_psr
-	wr	%sw_psr, PSR_ET, %psr
-	WRITE_PAUSE
-	wr	%sw_wim, 0x0, %wim
-	WRITE_PAUSE
-	ldd	[%sw_ntask + THREAD_KSP], %sp
-	LOAD_WINDOW(sp)
-
-	wr	%sw_psr, 0x0, %psr		! traps back on
-	WRITE_PAUSE
-
-	retl
-	 nop
-
-
-#ifdef __SMP__
-	/* Because of nasty register windows this is the only way
-	 * to start a processor into its cpu_idle() thread.
-	 */
-
-	.globl	C_LABEL(sparc_cpusched)
-C_LABEL(sparc_cpusched):
-	LOAD_CURRENT(g1, g2)
-	rd	%psr, %g7
-
-	wr	%g7, PSR_ET, %psr
-	WRITE_PAUSE
-
-	ldd	[%g1 + THREAD_KPSR], %g2
-
-	wr	%g2, PSR_ET, %psr
-	WRITE_PAUSE
-
-	wr	%g3, 0x0, %wim
-	WRITE_PAUSE
-
-	ldd	[%g1 + THREAD_KSP], %sp
-	LOAD_WINDOW(sp)
-
-	wr	%g2, 0x0, %psr
-	WRITE_PAUSE
-
-	retl
-	 nop
-#endif
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/sys_sparc.c linux/arch/sparc/kernel/sys_sparc.c
--- v2.1.15/linux/arch/sparc/kernel/sys_sparc.c	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/sys_sparc.c	Fri Dec 13 11:37:31 1996
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.25 1996/11/03 20:58:07 davem Exp $
+/* $Id: sys_sparc.c,v 1.28 1996/12/12 09:39:25 jj Exp $
  * linux/arch/sparc/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -179,39 +179,15 @@
 			return -ENOMEM;
 		}
 	}
-	retval = do_mmap(file, addr, len, prot, flags, off);
-	return retval;
-}
 
-extern int do_open_namei(const char * pathname, int flag, int mode,
-               struct inode ** res_inode, struct inode * base);
+	/* See asm-sparc/uaccess.h */
+	if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE)))
+		return -EINVAL;
 
-#define BSD_EMUL "/usr/gnemul/sunos"
-#define SOL_EMUL "/usr/gnemul/solaris"
-
-int
-open_namei(const char * pathname, int flag, int mode,
-               struct inode ** res_inode, struct inode * base)
-{
-	if (!base && (current->personality & (PER_BSD|PER_SVR4)) && *pathname == '/'){
-		struct inode *emul_ino;
-		const char   *p = pathname;
-		char *emul_path = current->personality & PER_BSD ? BSD_EMUL : SOL_EMUL;
-		int v;
-
-		while (*p == '/')
-			p++;
-		
-		if (do_open_namei (emul_path, flag, mode, &emul_ino, NULL) >= 0 && emul_ino){
-			v = do_open_namei (p, flag, mode, res_inode, emul_ino);
-			if (v >= 0)
-				return v;
-		}
-	}
-	return do_open_namei (pathname, flag, mode, res_inode, base);
+	retval = do_mmap(file, addr, len, prot, flags, off);
+	return retval;
 }
 
-
 /* we come to here via sys_nis_syscall so it can setup the regs argument */
 asmlinkage unsigned long
 c_sys_nis_syscall (struct pt_regs *regs)
@@ -235,3 +211,16 @@
 #endif
 }
 
+extern int
+sys_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction);
+
+asmlinkage int
+sparc_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction)
+{
+    if (signum >= 0){
+	return sys_sigaction (signum, action, oldaction);
+    } else {
+	current->tss.new_signal = 1;
+	return sys_sigaction (-signum, action, oldaction);
+    }
+}
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.1.15/linux/arch/sparc/kernel/sys_sunos.c	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/sys_sunos.c	Fri Dec 13 11:37:31 1996
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.61 1996/11/03 20:58:11 davem Exp $
+/* $Id: sys_sunos.c,v 1.65 1996/12/10 07:08:09 tridge Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -107,6 +107,11 @@
 		addr = 0;
 	ret_type = flags & _MAP_NEW;
 	flags &= ~_MAP_NEW;
+
+	/* See asm-sparc/uaccess.h */
+	if((len > (TASK_SIZE - PAGE_SIZE)) || (addr > (TASK_SIZE-len-PAGE_SIZE)))
+		return -EINVAL;
+
 	retval = do_mmap(file, addr, len, prot, flags, off);
 	if(ret_type)
 		return retval;
@@ -178,7 +183,7 @@
 	freepages >>= 1;
 	freepages += nr_free_pages;
 	freepages += nr_swap_pages;
-	freepages -= max_mapnr >> 4;
+	freepages -= num_physpages >> 4;
 	freepages -= (newbrk-oldbrk) >> PAGE_SHIFT;
 	if (freepages < 0)
 		return -ENOMEM;
@@ -1153,26 +1158,82 @@
 asmlinkage int sunos_sigaction(int signum, const struct sigaction *action,
 	struct sigaction *oldaction)
 {
-	struct sigaction tmp_sa;
+	struct sigaction tmp_sa, *tmp_sap;
 	const  int sigaction_size = sizeof (struct sigaction) - sizeof (void *);
 	int err;
 	int old_fs;
-	
-	if(copy_from_user(&tmp_sa, action, sigaction_size))
-		return -EFAULT;
-	if (tmp_sa.sa_flags & SUNOS_SV_INTERRUPT)
-		tmp_sa.sa_flags &= ~SUNOS_SV_INTERRUPT;
-	else
-		tmp_sa.sa_flags |= SA_RESTART;
-	old_fs = get_fs ();
-	set_fs (get_ds ());
-	err = sys_sigaction (signum, &tmp_sa, oldaction);
+
+	current->personality |= PER_BSD;
+
+	if (action) {
+		if(copy_from_user(&tmp_sa, action, sigaction_size))
+			return -EFAULT;
+		if (oldaction) {
+			err = verify_area(VERIFY_WRITE,oldaction,sigaction_size);
+			if (err)
+				return err;
+		}
+			
+		if (tmp_sa.sa_flags & SUNOS_SV_INTERRUPT)
+			tmp_sa.sa_flags &= ~SUNOS_SV_INTERRUPT;
+		else
+			tmp_sa.sa_flags |= SA_RESTART;
+		old_fs = get_fs ();
+		set_fs (get_ds ());
+		tmp_sap = &tmp_sa;
+	} else {
+		tmp_sap = action;
+	}
+
+	err = sys_sigaction (signum, tmp_sap, oldaction);
+
 	if (err == 0 && oldaction){
 		if (oldaction->sa_flags & SA_RESTART)
 			oldaction->sa_flags &= ~SA_RESTART;
 		else
 			oldaction->sa_flags |= SUNOS_SV_INTERRUPT;
 	}
-	set_fs (old_fs);
+	if (action)
+		set_fs (old_fs);
 	return err;
+}
+
+
+extern asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int optlen);
+extern asmlinkage int sys_getsockopt(int fd, int level, int optname, char *optval, int *optlen);
+
+asmlinkage int sunos_setsockopt(int fd, int level, int optname, char *optval,
+				int optlen)
+{
+	int tr_opt = optname;
+
+	if (level == SOL_IP)
+	{
+		/*
+		 *	Multicast socketopts (ttl, membership)
+		 */
+		if (tr_opt >=2 && tr_opt <= 6)
+		{
+			tr_opt += 30;
+		}
+	}
+	return sys_setsockopt(fd, level, tr_opt, optval, optlen);
+}
+
+asmlinkage int sunos_getsockopt(int fd, int level, int optname, char *optval,
+				int *optlen)
+{
+	int tr_opt = optname;
+
+	if (level == SOL_IP)
+	{
+		/*
+		 *	Multicast socketopts (ttl, membership)
+		 */
+		if (tr_opt >=2 && tr_opt <= 6)
+		{
+			tr_opt += 30;
+		}
+	}
+	return sys_getsockopt(fd, level, tr_opt, optval, optlen);
 }
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/systbls.S linux/arch/sparc/kernel/systbls.S
--- v2.1.15/linux/arch/sparc/kernel/systbls.S	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/systbls.S	Fri Dec 13 11:37:31 1996
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.51 1996/11/03 20:58:04 davem Exp $
+/* $Id: systbls.S,v 1.54 1996/12/03 08:44:37 jj Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -111,7 +111,7 @@
 	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_newuname), C_LABEL(sys_init_module)
 	.long C_LABEL(sys_personality), C_LABEL(sys_prof), C_LABEL(sys_break)
 	.long C_LABEL(sys_lock), C_LABEL(sys_mpx), C_LABEL(sys_ulimit)
-	.long C_LABEL(sys_getppid), C_LABEL(sys_sigaction), C_LABEL(sys_sgetmask)
+	.long C_LABEL(sys_getppid), C_LABEL(sparc_sigaction), C_LABEL(sys_sgetmask)
 /*200*/	.long C_LABEL(sys_ssetmask), C_LABEL(sys_sigsuspend), C_LABEL(sys_newlstat)
 	.long C_LABEL(sys_uselib), C_LABEL(old_readdir), C_LABEL(sys_nis_syscall)
 	.long C_LABEL(sys_socketcall), C_LABEL(sys_syslog), C_LABEL(sys_olduname)
@@ -176,12 +176,12 @@
 	.long C_LABEL(sys_fsync), C_LABEL(sys_setpriority), C_LABEL(sys_socket)
 	.long C_LABEL(sys_connect), C_LABEL(sunos_accept)
 /*100*/	.long C_LABEL(sys_getpriority), C_LABEL(sunos_send), C_LABEL(sunos_recv)
-	.long C_LABEL(sunos_nosys), C_LABEL(sys_bind), C_LABEL(sys_setsockopt)
+	.long C_LABEL(sunos_nosys), C_LABEL(sys_bind), C_LABEL(sunos_setsockopt)
 	.long C_LABEL(sys_listen), C_LABEL(sunos_nosys), C_LABEL(sunos_sigaction)
 	.long C_LABEL(sunos_sigblock), C_LABEL(sunos_sigsetmask), C_LABEL(sys_sigpause)
 	.long C_LABEL(sys_sigstack), C_LABEL(sys_recvmsg), C_LABEL(sys_sendmsg)
 	.long C_LABEL(sunos_nosys), C_LABEL(sys_gettimeofday), C_LABEL(sys_getrusage)
-	.long C_LABEL(sys_getsockopt), C_LABEL(sunos_nosys), C_LABEL(sunos_readv)
+	.long C_LABEL(sunos_getsockopt), C_LABEL(sunos_nosys), C_LABEL(sunos_readv)
 	.long C_LABEL(sunos_writev), C_LABEL(sys_settimeofday), C_LABEL(sys_fchown)
 	.long C_LABEL(sys_fchmod), C_LABEL(sys_recvfrom), C_LABEL(sys_setreuid)
 	.long C_LABEL(sys_setregid), C_LABEL(sys_rename), C_LABEL(sys_truncate)
@@ -229,6 +229,8 @@
 /*250*/	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
 	.long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys)
 
+#if 0
+/* Not used yet - {net, open}bsd is a TODO */
 	/* {net, open}bsd system call table. */
 
 	.align	4
@@ -368,7 +370,10 @@
 	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
 	.long C_LABEL(sunos_nosys)/*NOTHING*/, C_LABEL(sunos_nosys)/*NOTHING*/
 	.long C_LABEL(sunos_nosys)/*MINHERIT*/, C_LABEL(sunos_nosys)/*RFORK*/
+#endif
 
+#if 0
+/* Not needed - iBCS has its own */
 	/* One thing left, Solaris syscall table, TODO */
 	.globl	C_LABEL(solaris_sys_table)
 C_LABEL(solaris_sys_table):
@@ -476,3 +481,4 @@
 /*250*/	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
 	.long C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall), C_LABEL(sys_nis_syscall)
 /*255*/	.long C_LABEL(sys_nis_syscall)
+#endif
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/time.c linux/arch/sparc/kernel/time.c
--- v2.1.15/linux/arch/sparc/kernel/time.c	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/time.c	Fri Dec 13 11:37:31 1996
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.19 1996/10/31 06:28:26 davem Exp $
+/* $Id: time.c,v 1.20 1996/11/13 05:09:40 davem Exp $
  * linux/arch/sparc/kernel/time.c
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -15,6 +15,7 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/timex.h>
+#include <linux/init.h>
 
 #include <asm/oplib.h>
 #include <asm/segment.h>
@@ -155,7 +156,7 @@
 }
 
 /* Probe for the real time clock chip. */
-static void clock_probe(void)
+__initfunc(static void clock_probe(void))
 {
 	struct linux_prom_registers clk_reg[2];
 	char model[128];
@@ -236,7 +237,7 @@
 		kick_start_clock();
 }
 
-void time_init(void)
+__initfunc(void time_init(void))
 {
 	unsigned int year, mon, day, hour, min, sec;
 	struct mostek48t02 *mregs;
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/traps.c linux/arch/sparc/kernel/traps.c
--- v2.1.15/linux/arch/sparc/kernel/traps.c	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/traps.c	Fri Dec 13 11:37:31 1996
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.47 1996/10/27 08:36:17 davem Exp $
+/* $Id: traps.c,v 1.48 1996/11/13 05:09:42 davem Exp $
  * arch/sparc/kernel/traps.c
  *
  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -125,6 +125,11 @@
 	printk("Ill instr. at pc=%08lx instruction is %08lx\n",
 	       regs->pc, *(unsigned long *)regs->pc);
 #endif
+	if (sparc_cpu_model == sun4c || sparc_cpu_model == sun4) {
+		extern int do_user_muldiv (struct pt_regs *, unsigned long);
+		if (!do_user_muldiv (regs, pc))
+			return;
+	}
 	current->tss.sig_address = pc;
 	current->tss.sig_desc = SUBSIG_ILLINST;
 	send_sig(SIGILL, current, 1);
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/unaligned.c linux/arch/sparc/kernel/unaligned.c
--- v2.1.15/linux/arch/sparc/kernel/unaligned.c	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/unaligned.c	Fri Dec 13 11:37:31 1996
@@ -1,10 +1,12 @@
-/* $Id: unaligned.c,v 1.10 1996/11/10 21:25:47 davem Exp $
+/* $Id: unaligned.c,v 1.13 1996/11/26 14:01:57 jj Exp $
  * unaligned.c: Unaligned load/store trap handling with special
  *              cases for the kernel to do them more quickly.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -64,22 +66,16 @@
 	}
 }
 
-/* 1 = signed, 0 = unsigned */
+/* 0x400000 = signed, 0 = unsigned */
 static inline int decode_signedness(unsigned int insn)
 {
-	return (insn >> 22) & 1;
+	return (insn & 0x400000);
 }
 
 static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2,
 				       unsigned int rd)
 {
-	int yep;
-
-	if(rs2 >= 16 || rs1 >= 16 || rd >= 16)
-		yep = 1;
-	else
-		yep = 0;
-	if(yep) {
+	if(rs2 >= 16 || rs1 >= 16 || rd >= 16) {
 		/* Wheee... */
 		__asm__ __volatile__("save %sp, -0x40, %sp\n\t"
 				     "save %sp, -0x40, %sp\n\t"
@@ -93,11 +89,6 @@
 	}
 }
 
-static inline int sign_extend_halfword(int hword)
-{
-	return hword << 16 >> 16;
-}
-
 static inline int sign_extend_imm13(int imm)
 {
 	return imm << 19 >> 19;
@@ -131,123 +122,168 @@
 	unsigned int rs1 = (insn >> 14) & 0x1f;
 	unsigned int rs2 = insn & 0x1f;
 	unsigned int rd = (insn >> 25) & 0x1f;
-	unsigned int imm13 = (insn & 0x1fff);
 
 	if(insn & 0x2000) {
 		maybe_flush_windows(rs1, 0, rd);
-		return (fetch_reg(rs1, regs) + sign_extend_imm13(imm13));
+		return (fetch_reg(rs1, regs) + sign_extend_imm13(insn));
 	} else {
 		maybe_flush_windows(rs1, rs2, rd);
 		return (fetch_reg(rs1, regs) + fetch_reg(rs2, regs));
 	}
 }
 
-static inline void do_integer_load(unsigned long *dest_reg, int size,
-				   unsigned long *saddr, int is_signed)
-{
-	unsigned char bytes[4];
-
-	switch(size) {
-	case 2:
-		bytes[0] = *((unsigned char *)saddr + 1);
-		bytes[1] = *((unsigned char *)saddr + 0);
-		*dest_reg = (bytes[0] | (bytes[1] << 8));
-		if(is_signed)
-			*dest_reg = sign_extend_halfword(*dest_reg);
-		break;
-
-	case 4:
-		bytes[0] = *((unsigned char *)saddr + 3);
-		bytes[1] = *((unsigned char *)saddr + 2);
-		bytes[2] = *((unsigned char *)saddr + 1);
-		bytes[3] = *((unsigned char *)saddr + 0);
-		*dest_reg = (bytes[0] | (bytes[1] << 8) |
-			     (bytes[2] << 16) | (bytes[3] << 24));
-		break;
-
-	case 8:
-		bytes[0] = *((unsigned char *)saddr + 3);
-		bytes[1] = *((unsigned char *)saddr + 2);
-		bytes[2] = *((unsigned char *)saddr + 1);
-		bytes[3] = *((unsigned char *)saddr + 0);
-		*dest_reg++ = (bytes[0] | (bytes[1] << 8) |
-			     (bytes[2] << 16) | (bytes[3] << 24));
-		saddr++;
-		bytes[0] = *((unsigned char *)saddr + 3);
-		bytes[1] = *((unsigned char *)saddr + 2);
-		bytes[2] = *((unsigned char *)saddr + 1);
-		bytes[3] = *((unsigned char *)saddr + 0);
-		*dest_reg = (bytes[0] | (bytes[1] << 8) |
-			     (bytes[2] << 16) | (bytes[3] << 24));
-		break;
-
-	default:
-		panic("Impossible unaligned load.");
-	};
-}
-
-static inline void store_common(unsigned long *src_val,
-				int size, unsigned long *dst_addr)
-{
-	unsigned char *daddr = (unsigned char *) dst_addr;
-	switch(size) {
-	case 2:
-		daddr[0] = ((*src_val) >> 8) & 0xff;
-		daddr[1] = (*src_val & 0xff);
-		break;
-
-	case 4:
-		daddr[0] = ((*src_val) >> 24) & 0xff;
-		daddr[1] = ((*src_val) >> 16) & 0xff;
-		daddr[2] = ((*src_val) >> 8) & 0xff;
-		daddr[3] = (*src_val & 0xff);
-		break;
-
-	case 8:
-		daddr[0] = ((*src_val) >> 24) & 0xff;
-		daddr[1] = ((*src_val) >> 16) & 0xff;
-		daddr[2] = ((*src_val) >> 8) & 0xff;
-		daddr[3] = (*src_val & 0xff);
-		daddr += 4;
-		src_val++;
-		daddr[0] = ((*src_val) >> 24) & 0xff;
-		daddr[1] = ((*src_val) >> 16) & 0xff;
-		daddr[2] = ((*src_val) >> 8) & 0xff;
-		daddr[3] = (*src_val & 0xff);
-		break;
-
-	default:
-		panic("Impossible unaligned store.");
-	}
-}
-
-static inline void do_integer_store(int reg_num, int size,
-				    unsigned long *dst_addr,
-				    struct pt_regs *regs)
+/* This is just to make gcc think panic does return... */
+static void unaligned_panic(char *str)
 {
-	unsigned long *src_val;
-	static unsigned long zero[2] = { 0, 0 };
-
-	if(reg_num)
-		src_val = fetch_reg_addr(reg_num, regs);
-	else
-		src_val = &zero[0];
-	store_common(src_val, size, dst_addr);
+	panic(str);
 }
 
-static inline void do_atomic(unsigned long *srcdest_reg, unsigned long *mem)
-{
-	unsigned long flags, tmp;
-
-#ifdef __SMP__
-	/* XXX Need to capture/release other cpu's around this. */
-#endif
-	save_and_cli(flags);
-	tmp = *srcdest_reg;
-	do_integer_load(srcdest_reg, 4, mem, 0);
-	store_common(&tmp, 4, mem);
-	restore_flags(flags);
-}
+#define do_integer_load(dest_reg, size, saddr, is_signed, errh) ({		\
+__asm__ __volatile__ (								\
+	"cmp	%1, 8\n\t"							\
+	"be	9f\n\t"								\
+	" cmp	%1, 4\n\t"							\
+	"be	6f\n"								\
+"4:\t"	" ldub	[%2], %%l1\n"							\
+"5:\t"	"ldub	[%2 + 1], %%l2\n\t"						\
+	"sll	%%l1, 8, %%l1\n\t"						\
+	"tst	%3\n\t"								\
+	"be	3f\n\t"								\
+	" add	%%l1, %%l2, %%l1\n\t"						\
+	"sll	%%l1, 16, %%l1\n\t"						\
+	"sra	%%l1, 16, %%l1\n"						\
+"3:\t"	"b	0f\n\t"								\
+	" st	%%l1, [%0]\n"							\
+"6:\t"	"ldub	[%2 + 1], %%l2\n\t"						\
+	"sll	%%l1, 24, %%l1\n"						\
+"7:\t"	"ldub	[%2 + 2], %%g7\n\t"						\
+	"sll	%%l2, 16, %%l2\n"						\
+"8:\t"	"ldub	[%2 + 3], %%g1\n\t"						\
+	"sll	%%g7, 8, %%g7\n\t"						\
+	"or	%%l1, %%l2, %%l1\n\t"						\
+	"or	%%g7, %%g1, %%g7\n\t"						\
+	"or	%%l1, %%g7, %%l1\n\t"						\
+	"b	0f\n\t"								\
+	" st	%%l1, [%0]\n"							\
+"9:\t"	"ldub	[%2], %%l1\n"							\
+"10:\t"	"ldub	[%2 + 1], %%l2\n\t"						\
+	"sll	%%l1, 24, %%l1\n"						\
+"11:\t"	"ldub	[%2 + 2], %%g7\n\t"						\
+	"sll	%%l2, 16, %%l2\n"						\
+"12:\t"	"ldub	[%2 + 3], %%g1\n\t"						\
+	"sll	%%g7, 8, %%g7\n\t"						\
+	"or	%%l1, %%l2, %%l1\n\t"						\
+	"or	%%g7, %%g1, %%g7\n\t"						\
+	"or	%%l1, %%g7, %%g7\n"						\
+"13:\t"	"ldub	[%2 + 4], %%l1\n\t"						\
+	"st	%%g7, [%0]\n"							\
+"14:\t"	"ldub	[%2 + 5], %%l2\n\t"						\
+	"sll	%%l1, 24, %%l1\n"						\
+"15:\t"	"ldub	[%2 + 6], %%g7\n\t"						\
+	"sll	%%l2, 16, %%l2\n"						\
+"16:\t"	"ldub	[%2 + 7], %%g1\n\t"						\
+	"sll	%%g7, 8, %%g7\n\t"						\
+	"or	%%l1, %%l2, %%l1\n\t"						\
+	"or	%%g7, %%g1, %%g7\n\t"						\
+	"or	%%l1, %%g7, %%g7\n\t"						\
+	"st	%%g7, [%0 + 4]\n"						\
+"0:\n\n\t"									\
+	".section __ex_table\n\t"						\
+	".word	4b, " #errh "\n\t"						\
+	".word	5b, " #errh "\n\t"						\
+	".word	6b, " #errh "\n\t"						\
+	".word	7b, " #errh "\n\t"						\
+	".word	8b, " #errh "\n\t"						\
+	".word	9b, " #errh "\n\t"						\
+	".word	10b, " #errh "\n\t"						\
+	".word	11b, " #errh "\n\t"						\
+	".word	12b, " #errh "\n\t"						\
+	".word	13b, " #errh "\n\t"						\
+	".word	14b, " #errh "\n\t"						\
+	".word	15b, " #errh "\n\t"						\
+	".word	16b, " #errh "\n\n\t"						\
+	".text\n\t"								\
+	: : "r" (dest_reg), "r" (size), "r" (saddr), "r" (is_signed)		\
+	: "l1", "l2", "g7", "g1");						\
+})
+	
+#define store_common(dst_addr, size, src_val, errh) ({				\
+__asm__ __volatile__ (								\
+	"ld	[%2], %%l1\n"							\
+	"cmp	%1, 2\n\t"							\
+	"be	2f\n\t"								\
+	" cmp	%1, 4\n\t"							\
+	"be	1f\n\t"								\
+	" srl	%%l1, 24, %%l2\n\t"						\
+	"srl	%%l1, 16, %%g7\n"						\
+"4:\t"	"stb	%%l2, [%0]\n\t"							\
+	"srl	%%l1, 8, %%l2\n"						\
+"5:\t"	"stb	%%g7, [%0 + 1]\n\t"						\
+	"ld	[%2 + 4], %%g7\n"						\
+"6:\t"	"stb	%%l2, [%0 + 2]\n\t"						\
+	"srl	%%g7, 24, %%l2\n"						\
+"7:\t"	"stb	%%l1, [%0 + 3]\n\t"						\
+	"srl	%%g7, 16, %%l1\n"						\
+"8:\t"	"stb	%%l2, [%0 + 4]\n\t"						\
+	"srl	%%g7, 8, %%l2\n"						\
+"9:\t"	"stb	%%l1, [%0 + 5]\n"						\
+"10:\t"	"stb	%%l2, [%0 + 6]\n\t"						\
+	"b	0f\n"								\
+"11:\t"	" stb	%%g7, [%0 + 7]\n"						\
+"1:\t"	"srl	%%l1, 16, %%g7\n"						\
+"12:\t"	"stb	%%l2, [%0]\n\t"							\
+	"srl	%%l1, 8, %%l2\n"						\
+"13:\t"	"stb	%%g7, [%0 + 1]\n"						\
+"14:\t"	"stb	%%l2, [%0 + 2]\n\t"						\
+	"b	0f\n"								\
+"15:\t"	" stb	%%l1, [%0 + 3]\n"						\
+"2:\t"	"srl	%%l1, 8, %%l2\n"						\
+"16:\t"	"stb	%%l2, [%0]\n"							\
+"17:\t"	"stb	%%l1, [%0 + 1]\n"						\
+"0:\n\n\t"									\
+	".section __ex_table\n\t"						\
+	".word	4b, " #errh "\n\t"						\
+	".word	5b, " #errh "\n\t"						\
+	".word	6b, " #errh "\n\t"						\
+	".word	7b, " #errh "\n\t"						\
+	".word	8b, " #errh "\n\t"						\
+	".word	9b, " #errh "\n\t"						\
+	".word	10b, " #errh "\n\t"						\
+	".word	11b, " #errh "\n\t"						\
+	".word	12b, " #errh "\n\t"						\
+	".word	13b, " #errh "\n\t"						\
+	".word	14b, " #errh "\n\t"						\
+	".word	15b, " #errh "\n\t"						\
+	".word	16b, " #errh "\n\t"						\
+	".word	17b, " #errh "\n\n\t"						\
+	".text\n\t"								\
+	: : "r" (dst_addr), "r" (size), "r" (src_val)				\
+	: "l1", "l2", "g7", "g1");						\
+})
+
+#define do_integer_store(reg_num, size, dst_addr, regs, errh) ({		\
+	unsigned long *src_val;							\
+	static unsigned long zero[2] = { 0, };					\
+										\
+	if (reg_num) src_val = fetch_reg_addr(reg_num, regs);			\
+	else {									\
+		src_val = &zero[0];						\
+		if (size == 8)							\
+			zero[1] = fetch_reg(1, regs);				\
+	}									\
+	store_common(dst_addr, size, src_val, errh);				\
+})
+
+/* XXX Need to capture/release other cpu's for SMP around this. */
+#define do_atomic(srcdest_reg, mem, errh) ({					\
+	unsigned long flags, tmp;						\
+										\
+	save_and_cli(flags);							\
+	tmp = *srcdest_reg;							\
+	do_integer_load(srcdest_reg, 4, mem, 0, errh);				\
+	store_common(mem, 4, &tmp, errh);					\
+	restore_flags(flags);							\
+})
 
 static inline void advance(struct pt_regs *regs)
 {
@@ -265,6 +301,32 @@
 	return !floating_point_load_or_store_p(insn);
 }
 
+void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn) __asm__ ("kernel_mna_trap_fault");
+
+void kernel_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
+{
+	unsigned long g2 = regs->u_regs [UREG_G2];
+	unsigned long fixup = search_exception_table (regs->pc, &g2);
+	
+	if (!fixup) {
+		unsigned long address = compute_effective_address(regs, insn);
+        	if(address < PAGE_SIZE) {
+                	printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference in mna handler");
+        	} else
+                	printk(KERN_ALERT "Unable to handle kernel paging request in mna handler");
+	        printk(KERN_ALERT " at virtual address %08lx\n",address);
+        	printk(KERN_ALERT "current->mm->context = %08lx\n",
+	               (unsigned long) current->mm->context);
+	        printk(KERN_ALERT "current->mm->pgd = %08lx\n",
+        	       (unsigned long) current->mm->pgd);
+	        die_if_kernel("Oops", regs);
+		/* Not reached */
+	}
+	regs->pc = fixup;
+	regs->npc = regs->pc + 4;
+	regs->u_regs [UREG_G2] = g2;
+}
+
 asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
 {
 	enum direction dir = decode_direction(insn);
@@ -273,8 +335,17 @@
 	if(!ok_for_kernel(insn) || dir == both) {
 		printk("Unsupported unaligned load/store trap for kernel at <%08lx>.\n",
 		       regs->pc);
-		panic("Wheee. Kernel does fpu/atomic unaligned load/store.");
-		/* Not reached... */
+		unaligned_panic("Wheee. Kernel does fpu/atomic unaligned load/store.");
+		
+		__asm__ __volatile__ ("\n"
+"kernel_unaligned_trap_fault:\n\t"
+		"mov	%0, %%o0\n\t"
+		"call	kernel_mna_trap_fault\n\t"
+		" mov	%1, %%o1\n\t"
+		: : "r" (regs), "r" (insn)
+		: "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7");
+		
+		return;
 	} else {
 		unsigned long addr = compute_effective_address(regs, insn);
 
@@ -286,17 +357,20 @@
 		case load:
 			do_integer_load(fetch_reg_addr(((insn>>25)&0x1f), regs),
 					size, (unsigned long *) addr,
-					decode_signedness(insn));
+					decode_signedness(insn),
+					kernel_unaligned_trap_fault);
 			break;
 
 		case store:
 			do_integer_store(((insn>>25)&0x1f), size,
-					 (unsigned long *) addr, regs);
+					 (unsigned long *) addr, regs,
+					 kernel_unaligned_trap_fault);
 			break;
-		case both:
 #if 0 /* unsupported */
+		case both:
 			do_atomic(fetch_reg_addr(((insn>>25)&0x1f), regs),
-				  (unsigned long *) addr);
+				  (unsigned long *) addr, 
+				  kernel_unaligned_trap_fault);
 			break;
 #endif
 		default:
@@ -344,6 +418,15 @@
 #undef WINREG_ADDR
 }
 
+void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn) __asm__ ("user_mna_trap_fault");
+
+void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn)
+{
+	current->tss.sig_address = regs->pc;
+	current->tss.sig_desc = SUBSIG_PRIVINST;
+	send_sig(SIGBUS, current, 1);
+}
+
 asmlinkage void user_unaligned_trap(struct pt_regs *regs, unsigned int insn)
 {
 	enum direction dir;
@@ -368,21 +451,34 @@
 		case load:
 			do_integer_load(fetch_reg_addr(((insn>>25)&0x1f), regs),
 					size, (unsigned long *) addr,
-					decode_signedness(insn));
+					decode_signedness(insn),
+					user_unaligned_trap_fault);
 			break;
 
 		case store:
 			do_integer_store(((insn>>25)&0x1f), size,
-					 (unsigned long *) addr, regs);
+					 (unsigned long *) addr, regs,
+					 user_unaligned_trap_fault);
 			break;
 
 		case both:
 			do_atomic(fetch_reg_addr(((insn>>25)&0x1f), regs),
-				  (unsigned long *) addr);
+				  (unsigned long *) addr,
+				  user_unaligned_trap_fault);
 			break;
 
 		default:
-			panic("Impossible user unaligned trap.");
+			unaligned_panic("Impossible user unaligned trap.");
+
+			__asm__ __volatile__ ("\n"
+"user_unaligned_trap_fault:\n\t"
+			"mov	%0, %%o0\n\t"
+			"call	user_mna_trap_fault\n\t"
+			" mov	%1, %%o1\n\t"
+			: : "r" (regs), "r" (insn)
+			: "o0", "o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g4", "g5", "g7");
+		
+			return;
 		}
 		advance(regs);
 		return;
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/wof.S linux/arch/sparc/kernel/wof.S
--- v2.1.15/linux/arch/sparc/kernel/wof.S	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/wof.S	Fri Dec 13 11:37:31 1996
@@ -1,4 +1,4 @@
-/* $Id: wof.S,v 1.29 1996/10/11 01:00:04 davem Exp $
+/* $Id: wof.S,v 1.30 1996/12/10 06:06:19 davem Exp $
  * wof.S: Sparc window overflow handler.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -205,6 +205,7 @@
 	 * c-code to gun down the process.
 	 */
 	rd	%psr, %glob_tmp
+	WRITE_PAUSE
 	andcc	%glob_tmp, PSR_PS, %g0
 	bne	spwin_bad_ustack_from_kernel
 	 nop
@@ -314,8 +315,10 @@
 	be	1f
 	 sra	%sp, 29, %glob_tmp
 
+	rd	%psr, %glob_tmp
+	WRITE_PAUSE
 	b	spwin_user_stack_is_bolixed + 0x4
-	 rd	%psr, %glob_tmp
+	 nop
 
 1:
 	add	%glob_tmp, 0x1, %glob_tmp
@@ -323,8 +326,10 @@
 	be	1f
 	 and	%sp, 0xfff, %glob_tmp		! delay slot
 
+	rd	%psr, %glob_tmp
+	WRITE_PAUSE
 	b	spwin_user_stack_is_bolixed + 0x4
-	 rd	%psr, %glob_tmp
+	 nop
 
 	/* See if our dump area will be on more than one
 	 * page.
@@ -342,8 +347,10 @@
 	be	1f
 	 add	%sp, 0x38, %glob_tmp	/* Is second page in vma hole? */
 
+	rd	%psr, %glob_tmp
+	WRITE_PAUSE
 	b	spwin_user_stack_is_bolixed + 0x4
-	 rd	%psr, %glob_tmp
+	 nop
 
 1:
 	sra	%glob_tmp, 29, %glob_tmp
@@ -352,8 +359,10 @@
 	be	1f
 	 add	%sp, 0x38, %glob_tmp
 
+	rd	%psr, %glob_tmp
+	WRITE_PAUSE
 	b	spwin_user_stack_is_bolixed + 0x4
-	 rd	%psr, %glob_tmp
+	 nop
 
 1:
 	lda	[%glob_tmp] ASI_PTE, %glob_tmp
@@ -364,8 +373,10 @@
 	be	spwin_good_ustack			! success
 	 nop
 
+	rd	%psr, %glob_tmp
+	WRITE_PAUSE
 	b	spwin_user_stack_is_bolixed + 0x4
-	 rd	%psr, %glob_tmp
+	 nop
 
 	/* This is a generic SRMMU routine.  As far as I know this
 	 * works for all current v8/srmmu implementations, we'll
@@ -417,5 +428,7 @@
 	be,a	spwin_finish_up + 0x4			! cool beans, success
 	 restore %g0, %g0, %g0
 
+	rd	%psr, %glob_tmp
+	WRITE_PAUSE
 	b	spwin_user_stack_is_bolixed + 0x4	! we faulted, ugh
-	 rd	%psr, %glob_tmp
+	 nop
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/kernel/wuf.S linux/arch/sparc/kernel/wuf.S
--- v2.1.15/linux/arch/sparc/kernel/wuf.S	Tue Nov 12 15:56:03 1996
+++ linux/arch/sparc/kernel/wuf.S	Fri Dec 13 11:37:31 1996
@@ -1,4 +1,4 @@
-/* $Id: wuf.S,v 1.27 1996/10/11 01:00:06 davem Exp $
+/* $Id: wuf.S,v 1.28 1996/12/10 06:06:20 davem Exp $
  * wuf.S: Window underflow trap handler for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller
@@ -338,14 +338,21 @@
 	mov	AC_M_SFSR, %twin_tmp2
 	lda	[%twin_tmp2] ASI_M_MMUREGS, %twin_tmp2	! read fault status
 	andcc	%twin_tmp2, 0x2, %g0			! did fault occur?
-	be,a	fwin_user_finish_up + 0x4
-	 wr	%t_psr, 0x0, %psr
+
+	bne	1f					! yep, cleanup
+	 nop
+
+	wr	%t_psr, 0x0, %psr
+	WRITE_PAUSE
+	b	fwin_user_finish_up + 0x4
+	 nop
 
 	/* Did I ever tell you about my window lobotomy?
 	 * anyways... fwin_user_stack_is_bolixed expects
 	 * to be in window 'W' so make it happy or else
 	 * we watchdog badly.
 	 */
+1:
 	restore	%g0, %g0, %g0
 	b	fwin_user_stack_is_bolixed	! oh well
 	 restore	%g0, %g0, %g0
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/lib/Makefile linux/arch/sparc/lib/Makefile
--- v2.1.15/linux/arch/sparc/lib/Makefile	Tue Nov 12 15:56:04 1996
+++ linux/arch/sparc/lib/Makefile	Fri Dec 13 11:37:31 1996
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.12 1996/10/27 08:36:26 davem Exp $
+# $Id: Makefile,v 1.15 1996/11/22 11:57:00 ecd Exp $
 # Makefile for Sparc library files..
 #
 
@@ -6,7 +6,8 @@
 
 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
+	strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \
+	copy_user.o clear_user.o
 
 lib.a: $(OBJS)
 	$(AR) rcs lib.a $(OBJS)
@@ -30,6 +31,15 @@
 strncpy_from_user.o: strncpy_from_user.S
 	$(CC) -D__ASSEMBLY__ -ansi -c -o strncpy_from_user.o strncpy_from_user.S
 
+strlen_user.o: strlen_user.S
+	$(CC) -D__ASSEMBLY__ -ansi -c -o strlen_user.o strlen_user.S
+
+copy_user.o: copy_user.S
+	$(CC) -D__ASSEMBLY__ -ansi -c -o copy_user.o copy_user.S
+
+clear_user.o: clear_user.S
+	$(CC) -D__ASSEMBLY__ -ansi -c -o clear_user.o clear_user.S
+
 blockops.o: blockops.S
 	$(CC) -ansi -c -o blockops.o blockops.S
 
@@ -38,6 +48,12 @@
 
 strlen.o: strlen.S
 	$(CC) -ansi -c -o strlen.o strlen.S
+
+divdi3.o: divdi3.S
+	$(CC) -ansi -c -o divdi3.o divdi3.S
+
+udivdi3.o: udivdi3.S
+	$(CC) -ansi -c -o udivdi3.o udivdi3.S
 
 mul.o: mul.S
 	$(CC) -c -o mul.o mul.S
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/lib/clear_user.S linux/arch/sparc/lib/clear_user.S
--- v2.1.15/linux/arch/sparc/lib/clear_user.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/lib/clear_user.S	Fri Dec 13 11:37:31 1996
@@ -0,0 +1,185 @@
+/* linux/arch/sparc/lib/clear_user.S: Sparc optimized clear_user code
+ *
+ * Zero %o1 bytes at user %o0, handling exceptions as we go.
+ * Returns 0 if successfull, # of bytes still not cleared otherwise
+ *
+ * Copyright (C) 1991,1996 Free Software Foundation
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <asm/cprefix.h>
+#include <asm/ptrace.h>
+
+#define EX(x,y,a,b,z) 				\
+98: 	x,y;					\
+	.section .fixup,z##alloc,z##execinstr;	\
+	.align	4;				\
+99:	retl;					\
+	 a, b, %o0;				\
+	.section __ex_table,z##alloc;		\
+	.align	4;				\
+	.word	98b, 99b;			\
+	.text;					\
+	.align	4
+
+#define EXT(start,end,handler,z) 		\
+	.section __ex_table,z##alloc;		\
+	.align	4;				\
+	.word	start, 0, end, handler;		\
+	.text;					\
+	.align	4
+
+/* Please don't change these macros, unless you change the login
+ * in the .fixup section below as well */
+/* Store 64 bytes at (BASE + OFFSET) using value SOURCE. */
+#define ZERO_BIG_BLOCK(base, offset, source)    \
+	std	source, [base + offset + 0x00]; \
+	std	source, [base + offset + 0x08]; \
+	std	source, [base + offset + 0x10]; \
+	std	source, [base + offset + 0x18]; \
+	std	source, [base + offset + 0x20]; \
+	std	source, [base + offset + 0x28]; \
+	std	source, [base + offset + 0x30]; \
+	std	source, [base + offset + 0x38];
+
+#define ZERO_LAST_BLOCKS(base, offset, source)	\
+	std	source, [base - offset - 0x38]; \
+	std	source, [base - offset - 0x30]; \
+	std	source, [base - offset - 0x28]; \
+	std	source, [base - offset - 0x20]; \
+	std	source, [base - offset - 0x18]; \
+	std	source, [base - offset - 0x10]; \
+	std	source, [base - offset - 0x08]; \
+	std	source, [base - offset - 0x00];
+
+	.text
+	.align 4
+
+	.globl	C_LABEL(__clear_user)
+3:
+	cmp	%o2, 3
+	be	2f
+	 EX(stb	%g0, [%o0], sub %o1, 0,#)
+
+	cmp	%o2, 2
+	be	2f
+	 EX(stb	%g0, [%o0 + 0x01], sub %o1, 1,#)
+
+	EX(stb	%g0, [%o0 + 0x02], sub %o1, 2,#)
+2:
+	sub	%o2, 4, %o2
+	add	%o1, %o2, %o1
+	b	4f
+	 sub	%o0, %o2, %o0
+
+C_LABEL(__clear_user):
+	cmp	%o1, 7
+	bleu	7f
+	 andcc	%o0, 3, %o2
+	bne	3b
+4:
+	 andcc	%o0, 4, %g0
+
+	be	2f
+	 mov	%g0, %g1
+
+	EX(st	%g0, [%o0], sub %o1, 0,#)
+	sub	%o1, 4, %o1
+	add	%o0, 4, %o0
+2:
+	andcc	%o1, 0xffffff80, %o3	! Now everything is 8 aligned and o1 is len to run
+	be	9f
+	 andcc	%o1, 0x78, %o2
+10:
+	ZERO_BIG_BLOCK(%o0, 0x00, %g0)
+	subcc	%o3, 128, %o3
+	ZERO_BIG_BLOCK(%o0, 0x40, %g0)
+11:
+	EXT(10b, 11b, 20f,#)
+	bne	10b
+	 add	%o0, 128, %o0
+
+	orcc	%o2, %g0, %g0
+9:
+	be	13f
+	 andcc	%o1, 7, %o1
+
+	srl	%o2, 1, %o3
+	set	13f, %o4
+	sub	%o4, %o3, %o4
+	jmp	%o4
+	 add	%o0, %o2, %o0
+
+12:
+	ZERO_LAST_BLOCKS(%o0, 0x48, %g0)
+	ZERO_LAST_BLOCKS(%o0, 0x08, %g0)
+13:
+	EXT(12b, 13b, 21f,#)
+	be	8f
+	 andcc	%o1, 4, %g0
+
+	be	1f
+	 andcc	%o1, 2, %g0
+
+	EX(st	%g0, [%o0], and %o1, 7,#)
+	add	%o0, 4, %o0
+1:
+	be	1f
+	 andcc	%o1, 1, %g0
+
+	EX(sth	%g0, [%o0], and %o1, 3,#)
+	add	%o0, 2, %o0
+1:
+	bne,a	8f
+	 EX(stb	%g0, [%o0], add %g0, 1,#)
+8:
+	retl
+	 clr	%o0
+7:
+	be	13b
+	 orcc	%o1, 0, %g0
+
+	andcc	%o1, 4, %g0
+	be	1f
+	 andcc	%o1, 2, %g0
+
+	EX(stb	%g0, [%o0 + 0], sub %o1, 0,#)
+	EX(stb	%g0, [%o0 + 1], sub %o1, 1,#)
+	EX(stb	%g0, [%o0 + 2], sub %o1, 2,#)
+	EX(stb	%g0, [%o0 + 3], sub %o1, 3,#)
+	add	%o0, 4, %o0
+1:
+	be	1f
+	 andcc	%o1, 1, %o2
+
+	EX(stb	%g0, [%o0 + 0], add %o2, 2,#)
+	EX(stb	%g0, [%o0 + 1], add %o2, 1,#)
+	add	%o0, 2, %o0
+1:
+	bne,a	8b
+	 EX(stb	%g0, [%o0], add %g0, 1,#)
+
+	retl
+	 clr	%o0
+
+	.section .fixup,#alloc,#execinstr
+	.align	4
+20:
+	cmp	%g2, 8
+	bleu	1f
+	 and	%o1, 0x7f, %o1
+	sub	%g2, 9, %g2
+	add	%o3, 64, %o3
+1:
+	sll	%g2, 3, %g2
+	add	%o3, %o1, %o0
+	retl
+	 sub	%o0, %g2, %o0
+21:
+	mov	8, %o0
+	and	%o1, 7, %o1
+	sub	%o0, %g2, %o0
+	sll	%o0, 3, %o0
+	retl
+	 add	%o0, %o1, %o0
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/lib/copy_user.S linux/arch/sparc/lib/copy_user.S
--- v2.1.15/linux/arch/sparc/lib/copy_user.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/lib/copy_user.S	Fri Dec 13 11:37:31 1996
@@ -0,0 +1,453 @@
+/* copy_user.S: Sparc optimized copy_from_user and copy_to_user code.
+ *
+ *  Copyright(C) 1995 Linus Torvalds
+ *  Copyright(C) 1996 David S. Miller
+ *  Copyright(C) 1996 Eddie C. Dost
+ *  Copyright(C) 1996 Jakub Jelinek
+ *
+ * derived from:
+ *	e-mail between David and Eddie.
+ *
+ * Returns 0 if successful, otherwise count of bytes not copied yet
+ */
+
+#include <asm/cprefix.h>
+#include <asm/ptrace.h>
+
+#define EX(x,y,a,b,z) 				\
+98: 	x,y;					\
+	.section .fixup,z##alloc,z##execinstr;	\
+	.align	4;				\
+99:	retl;					\
+	 a, b, %o0;				\
+	.section __ex_table,z##alloc;		\
+	.align	4;				\
+	.word	98b, 99b;			\
+	.text;					\
+	.align	4
+
+#define EX2(x,y,c,d,e,a,b,z) 			\
+98: 	x,y;					\
+	.section .fixup,z##alloc,z##execinstr;	\
+	.align	4;				\
+99:	c, d, e;				\
+	retl;					\
+	 a, b, %o0;				\
+	.section __ex_table,z##alloc;		\
+	.align	4;				\
+	.word	98b, 99b;			\
+	.text;					\
+	.align	4
+
+#define EXO2(x,y,z) 				\
+98: 	x,##y;					\
+	.section __ex_table,z##alloc;		\
+	.align	4;				\
+	.word	98b, 97f;			\
+	.text;					\
+	.align	4
+
+#define EXT(start,end,handler,z) 		\
+	.section __ex_table,z##alloc;		\
+	.align	4;				\
+	.word	start, 0, end, handler;		\
+	.text;					\
+	.align	4
+
+/* Please do not change following macros unless you change logic used
+ * in .fixup at the end of this file as well
+ */
+
+/* Both these macros have to start with exactly the same insn */
+#define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
+	ldd	[%src + offset + 0x00], %t0; \
+	ldd	[%src + offset + 0x08], %t2; \
+	ldd	[%src + offset + 0x10], %t4; \
+	ldd	[%src + offset + 0x18], %t6; \
+	st	%t0, [%dst + offset + 0x00]; \
+	st	%t1, [%dst + offset + 0x04]; \
+	st	%t2, [%dst + offset + 0x08]; \
+	st	%t3, [%dst + offset + 0x0c]; \
+	st	%t4, [%dst + offset + 0x10]; \
+	st	%t5, [%dst + offset + 0x14]; \
+	st	%t6, [%dst + offset + 0x18]; \
+	st	%t7, [%dst + offset + 0x1c];
+
+#define MOVE_BIGALIGNCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
+	ldd	[%src + offset + 0x00], %t0; \
+	ldd	[%src + offset + 0x08], %t2; \
+	ldd	[%src + offset + 0x10], %t4; \
+	ldd	[%src + offset + 0x18], %t6; \
+	std	%t0, [%dst + offset + 0x00]; \
+	std	%t2, [%dst + offset + 0x08]; \
+	std	%t4, [%dst + offset + 0x10]; \
+	std	%t6, [%dst + offset + 0x18];
+
+#define MOVE_LASTCHUNK(src, dst, offset, t0, t1, t2, t3) \
+	ldd	[%src - offset - 0x10], %t0; \
+	ldd	[%src - offset - 0x08], %t2; \
+	st	%t0, [%dst - offset - 0x10]; \
+	st	%t1, [%dst - offset - 0x0c]; \
+	st	%t2, [%dst - offset - 0x08]; \
+	st	%t3, [%dst - offset - 0x04];
+
+#define MOVE_HALFCHUNK(src, dst, offset, t0, t1, t2, t3) \
+	lduh	[%src + offset + 0x00], %t0; \
+	lduh	[%src + offset + 0x02], %t1; \
+	lduh	[%src + offset + 0x04], %t2; \
+	lduh	[%src + offset + 0x06], %t3; \
+	sth	%t0, [%dst + offset + 0x00]; \
+	sth	%t1, [%dst + offset + 0x02]; \
+	sth	%t2, [%dst + offset + 0x04]; \
+	sth	%t3, [%dst + offset + 0x06];
+
+#define MOVE_SHORTCHUNK(src, dst, offset, t0, t1) \
+	ldub	[%src - offset - 0x02], %t0; \
+	ldub	[%src - offset - 0x01], %t1; \
+	stb	%t0, [%dst - offset - 0x02]; \
+	stb	%t1, [%dst - offset - 0x01];
+
+	.text
+	.align	4
+
+	.globl	C_LABEL(__copy_user)
+dword_align:
+	andcc	%o1, 1, %g0
+	be	4f
+	 andcc	%o1, 2, %g0
+
+	EXO2(ldub [%o1], %g2,#)
+	add	%o1, 1, %o1
+	EXO2(stb %g2, [%o0],#)
+	sub	%o2, 1, %o2
+	bne	3f
+	 add	%o0, 1, %o0
+
+	EXO2(lduh [%o1], %g2,#)
+	add	%o1, 2, %o1
+	EXO2(sth %g2, [%o0],#)
+	sub	%o2, 2, %o2
+	b	3f
+	 add	%o0, 2, %o0
+4:
+	EXO2(lduh [%o1], %g2,#)
+	add	%o1, 2, %o1
+	EXO2(sth %g2, [%o0],#)
+	sub	%o2, 2, %o2
+	b	3f
+	 add	%o0, 2, %o0
+
+C_LABEL(__copy_user):	/* %o0=dst %o1=src %o2=len */
+	xor	%o0, %o1, %o4
+1:
+	andcc	%o4, 3, %o5
+2:
+	bne	cannot_optimize
+	 cmp	%o2, 15
+
+	bleu	short_aligned_end
+	 andcc	%o1, 3, %g0
+
+	bne	dword_align
+3:
+	 andcc	%o1, 4, %g0
+
+	be	2f
+	 mov	%o2, %g1
+
+	EXO2(ld [%o1], %o4,#)
+	sub	%g1, 4, %g1
+	EXO2(st %o4, [%o0],#)
+	add	%o1, 4, %o1
+	add	%o0, 4, %o0
+2:
+	andcc	%g1, 0xffffff80, %g7
+	be	3f
+	 andcc	%o0, 4, %g0
+
+	be	ldd_std + 4
+5:
+	MOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
+	MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
+	MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
+	MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
+80:
+	EXT(5b, 80b, 50f,#)
+	subcc	%g7, 128, %g7
+	add	%o1, 128, %o1
+	bne	5b
+	 add	%o0, 128, %o0
+3:
+	andcc	%g1, 0x70, %g7
+	be	copy_user_table_end
+	 andcc	%g1, 8, %g0
+
+	sethi	%hi(copy_user_table_end), %o5
+	srl	%g7, 1, %o4
+	add	%g7, %o4, %o4
+	add	%o1, %g7, %o1
+	sub	%o5, %o4, %o5
+	jmpl	%o5 + %lo(copy_user_table_end), %g0
+	 add	%o0, %g7, %o0
+
+copy_user_table:
+	MOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
+	MOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
+	MOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
+	MOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5)
+	MOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5)
+	MOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
+	MOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
+copy_user_table_end:
+	EXT(copy_user_table, copy_user_table_end, 51f,#)
+	be	copy_user_last7
+	 andcc	%g1, 4, %g0
+
+	EX(ldd	[%o1], %g2, and %g1, 0xf,#)
+	add	%o0, 8, %o0
+	add	%o1, 8, %o1
+	EX(st	%g2, [%o0 - 0x08], and %g1, 0xf,#)
+	EX2(st	%g3, [%o0 - 0x04], and %g1, 0xf, %g1, sub %g1, 4,#)
+copy_user_last7:
+	be	1f
+	 andcc	%g1, 2, %g0
+
+	EX(ld	[%o1], %g2, and %g1, 7,#)
+	add	%o1, 4, %o1
+	EX(st	%g2, [%o0], and %g1, 7,#)
+	add	%o0, 4, %o0
+1:
+	be	1f
+	 andcc	%g1, 1, %g0
+
+	EX(lduh	[%o1], %g2, and %g1, 3,#)
+	add	%o1, 2, %o1
+	EX(sth	%g2, [%o0], and %g1, 3,#)
+	add	%o0, 2, %o0
+1:
+	be	1f
+	 nop
+
+	EX(ldub	[%o1], %g2, add %g0, 1,#)
+	EX(stb	%g2, [%o0], add %g0, 1,#)
+1:
+	retl
+ 	 clr	%o0
+
+ldd_std:
+	MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
+	MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
+	MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
+	MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
+81:
+	EXT(ldd_std, 81b, 52f,#)
+	subcc	%g7, 128, %g7
+	add	%o1, 128, %o1
+	bne	ldd_std
+	 add	%o0, 128, %o0
+
+	andcc	%g1, 0x70, %g7
+	be	copy_user_table_end
+	 andcc	%g1, 8, %g0
+
+	sethi	%hi(copy_user_table_end), %o5
+	srl	%g7, 1, %o4
+	add	%g7, %o4, %o4
+	add	%o1, %g7, %o1
+	sub	%o5, %o4, %o5
+	jmpl	%o5 + %lo(copy_user_table_end), %g0
+	 add	%o0, %g7, %o0
+
+cannot_optimize:
+	bleu	short_end
+	 cmp	%o5, 2
+
+	bne	byte_chunk
+	 and	%o2, 0xfffffff0, %o3
+	 
+	andcc	%o1, 1, %g0
+	be	10f
+	 nop
+
+	EXO2(ldub [%o1], %g2,#)
+	add	%o1, 1, %o1
+	EXO2(stb %g2, [%o0],#)
+	sub	%o2, 1, %o2
+	andcc	%o2, 0xfffffff0, %o3
+	be	short_end
+	 add	%o0, 1, %o0
+10:
+	MOVE_HALFCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
+	MOVE_HALFCHUNK(o1, o0, 0x08, g2, g3, g4, g5)
+82:
+	EXT(10b, 82b, 53f,#)
+	subcc	%o3, 0x10, %o3
+	add	%o1, 0x10, %o1
+	bne	10b
+	 add	%o0, 0x10, %o0
+	b	2f
+	 and	%o2, 0xe, %o3
+	
+byte_chunk:
+	MOVE_SHORTCHUNK(o1, o0, -0x02, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x04, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x06, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x08, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x0a, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x0c, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x0e, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, -0x10, g2, g3)
+83:
+	EXT(byte_chunk, 83b, 54f,#)
+	subcc	%o3, 0x10, %o3
+	add	%o1, 0x10, %o1
+	bne	byte_chunk
+	 add	%o0, 0x10, %o0
+
+short_end:
+	and	%o2, 0xe, %o3
+2:
+	sethi	%hi(short_table_end), %o5
+	sll	%o3, 3, %o4
+	add	%o0, %o3, %o0
+	sub	%o5, %o4, %o5
+	add	%o1, %o3, %o1
+	jmpl	%o5 + %lo(short_table_end), %g0
+	 andcc	%o2, 1, %g0
+84:
+	MOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3)
+	MOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3)
+short_table_end:
+	EXT(84b, short_table_end, 55f,#)
+	be	1f
+	 nop
+	EX(ldub	[%o1], %g2, add %g0, 1,#)
+	EX(stb	%g2, [%o0], add %g0, 1,#)
+1:
+	retl
+ 	 clr	%o0
+
+short_aligned_end:
+	bne	short_end
+	 andcc	%o2, 8, %g0
+
+	be	1f
+	 andcc	%o2, 4, %g0
+
+	EXO2(ld	[%o1 + 0x00], %g2,#)
+	EX(ld	[%o1 + 0x04], %g3, sub %o2, 4,#)
+	add	%o1, 8, %o1
+	EXO2(st	%g2, [%o0 + 0x00],#)
+	EX(st	%g3, [%o0 + 0x04], sub %o2, 4,#)
+	add	%o0, 8, %o0
+1:
+	b	copy_user_last7
+	 mov	%o2, %g1
+
+	.section .fixup,#alloc,#execinstr
+	.align	4
+97:
+	retl
+	 mov	%o2, %o0
+/* exception routine sets %g2 to (broken_insn - first_insn)>>2 */
+50:
+/* This magic counts how many bytes are left when crash in MOVE_BIGCHUNK
+ * happens. This is derived from the amount ldd reads, st stores, etc.
+ * x = g2 % 12;
+ * o0 = g1 + g7 - ((g2 / 12) * 32 + (x < 4) ? x * 8 : (x - 4) * 4)
+ */
+	cmp	%g2, 12
+	bcs	1f
+	 cmp	%g2, 24
+	bcs	2f
+	 cmp	%g2, 36
+	bcs	3f
+	 nop
+	sub	%g2, 12, %g2
+	sub	%g7, 32, %g7
+3:
+	sub	%g2, 12, %g2
+	sub	%g7, 32, %g7
+2:
+	sub	%g2, 12, %g2
+	sub	%g7, 32, %g7
+1:
+	cmp	%g2, 4
+	bcs,a	1f
+	 sll	%g2, 3, %g2
+	sub	%g2, 4, %g2
+	sll	%g2, 2, %g2
+1:
+	and	%g1, 0x7f, %o0
+	add	%o0, %g7, %o0
+	retl
+	 sub	%o0, %g2, %o0
+51:
+/* i = 41 - g2; j = i % 6;
+ * o0 = (g1 & 15) + (i / 6) * 16 + (j < 4) ? (j + 1) * 4 : (j - 3) * 8;	
+ */
+	neg	%g2
+	and	%g1, 0xf, %g1
+	add	%g2, 41, %g2
+1:
+	cmp	%g2, 6
+	bcs,a	2f
+	 cmp	%g2, 4
+	add	%g1, 16, %g1
+	b	1b
+	 sub	%g2, 6, %g2
+2:
+	bcs,a	3f
+	 inc	%g2
+	sub	%g2, 3, %g2
+	b	2f
+	 sll	%g2, 3, %g2
+3:
+	sll	%g2, 2, %g2
+2:
+	retl
+	 add	%g1, %g2, %o0
+52:
+/* o0 = g1 + g7 - (g2 / 8) * 32 + (x & 3) * 8 */
+	and	%g2, 0xfffffff8, %g4
+	and	%g2, 3, %g2
+	sll	%g4, 2, %g4
+	sll	%g2, 3, %g2
+	add	%g2, %g4, %g2
+	b,a	1b
+53:
+/* o0 = o3 + (o2 & 15) - (g2 & 8) - (g2 & 3) * 2 */
+	and	%g2, 3, %g4
+	and	%g2, 0xfffffff8, %g2
+	sll	%g4, 1, %g4
+	add	%g2, %g4, %g2
+	and	%o2, 0xf, %o0
+	add	%o0, %o3, %o0
+	retl
+	 sub	%o0, %g2, %o0
+54:
+/* o0 = o3 + (o2 & 15) - (g2 / 4) * 2 - (g2 & 1) */
+	srl	%g2, 2, %o4
+	and	%g2, 1, %o1
+	sll	%o4, 1, %o4
+	and	%o2, 0xf, %o2
+	sub	%o3, %o1, %o3
+	sub	%o2, %o4, %o2
+	retl
+	 add	%o2, %o3, %o0
+55:
+/* o0 = (o2 & 1) + (27 - g2)/4 * 2 + ((27 - g2) & 1) */
+	neg	%g2
+	and	%o2, 1, %o2
+	add	%g2, 27, %g2
+	srl	%g2, 2, %o1
+	and	%g2, 1, %g2
+	sll	%o1, 1, %o1
+	add	%o2, %g2, %o0
+	retl
+	 add	%o0, %o1, %o0
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/lib/divdi3.S linux/arch/sparc/lib/divdi3.S
--- v2.1.15/linux/arch/sparc/lib/divdi3.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/lib/divdi3.S	Fri Dec 13 11:37:31 1996
@@ -0,0 +1,295 @@
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+	.data
+	.align 8
+	.globl	__clz_tab
+__clz_tab:
+	.byte	0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5
+	.byte	6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6
+	.byte	7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
+	.byte	7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
+	.byte	8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
+	.byte	8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
+	.byte	8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
+	.byte	8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
+	.size	 __clz_tab,256
+	.global .udiv
+
+	.text
+	.align 4
+	.globl __divdi3
+__divdi3:
+	save %sp,-104,%sp
+	cmp %i0,0
+	bge .LL40
+	mov 0,%l4
+	mov -1,%l4
+	sub %g0,%i1,%o0
+	mov %o0,%o5
+	subcc %g0,%o0,%g0
+	sub %g0,%i0,%o0
+	subx %o0,0,%o4
+	mov %o4,%i0
+	mov %o5,%i1
+.LL40:
+	cmp %i2,0
+	bge .LL84
+	mov %i3,%o4
+	xnor %g0,%l4,%l4
+	sub %g0,%i3,%o0
+	mov %o0,%o3
+	subcc %g0,%o0,%g0
+	sub %g0,%i2,%o0
+	subx %o0,0,%o2
+	mov %o2,%i2
+	mov %o3,%i3
+	mov %i3,%o4
+.LL84:
+	cmp %i2,0
+	bne .LL45
+	mov %i1,%i3
+	cmp %o4,%i0
+	bleu .LL46
+	mov %i3,%o1
+	mov	32,%g1
+	subcc	%i0,%o4,%g0
+1:	bcs	5f
+	 addxcc %o1,%o1,%o1	! shift n1n0 and a q-bit in lsb
+	sub	%i0,%o4,%i0	! this kills msb of n
+	addx	%i0,%i0,%i0	! so this cannot give carry
+	subcc	%g1,1,%g1
+2:	bne	1b
+	 subcc	%i0,%o4,%g0
+	bcs	3f
+	 addxcc %o1,%o1,%o1	! shift n1n0 and a q-bit in lsb
+	b	3f
+	 sub	%i0,%o4,%i0	! this kills msb of n
+4:	sub	%i0,%o4,%i0
+5:	addxcc	%i0,%i0,%i0
+	bcc	2b
+	 subcc	%g1,1,%g1
+! Got carry from n.  Subtract next step to cancel this carry.
+	bne	4b
+	 addcc	%o1,%o1,%o1	! shift n1n0 and a 0-bit in lsb
+	sub	%i0,%o4,%i0
+3:	xnor	%o1,0,%o1
+	b .LL50
+	mov 0,%o2
+.LL46:
+	cmp %o4,0
+	bne .LL85
+	mov %i0,%o2
+	mov 1,%o0
+	call .udiv,0
+	mov 0,%o1
+	mov %o0,%o4
+	mov %i0,%o2
+.LL85:
+	mov 0,%g3
+	mov	32,%g1
+	subcc	%g3,%o4,%g0
+1:	bcs	5f
+	 addxcc %o2,%o2,%o2	! shift n1n0 and a q-bit in lsb
+	sub	%g3,%o4,%g3	! this kills msb of n
+	addx	%g3,%g3,%g3	! so this cannot give carry
+	subcc	%g1,1,%g1
+2:	bne	1b
+	 subcc	%g3,%o4,%g0
+	bcs	3f
+	 addxcc %o2,%o2,%o2	! shift n1n0 and a q-bit in lsb
+	b	3f
+	 sub	%g3,%o4,%g3	! this kills msb of n
+4:	sub	%g3,%o4,%g3
+5:	addxcc	%g3,%g3,%g3
+	bcc	2b
+	 subcc	%g1,1,%g1
+! Got carry from n.  Subtract next step to cancel this carry.
+	bne	4b
+	 addcc	%o2,%o2,%o2	! shift n1n0 and a 0-bit in lsb
+	sub	%g3,%o4,%g3
+3:	xnor	%o2,0,%o2
+	mov %g3,%i0
+	mov %i3,%o1
+	mov	32,%g1
+	subcc	%i0,%o4,%g0
+1:	bcs	5f
+	 addxcc %o1,%o1,%o1	! shift n1n0 and a q-bit in lsb
+	sub	%i0,%o4,%i0	! this kills msb of n
+	addx	%i0,%i0,%i0	! so this cannot give carry
+	subcc	%g1,1,%g1
+2:	bne	1b
+	 subcc	%i0,%o4,%g0
+	bcs	3f
+	 addxcc %o1,%o1,%o1	! shift n1n0 and a q-bit in lsb
+	b	3f
+	 sub	%i0,%o4,%i0	! this kills msb of n
+4:	sub	%i0,%o4,%i0
+5:	addxcc	%i0,%i0,%i0
+	bcc	2b
+	 subcc	%g1,1,%g1
+! Got carry from n.  Subtract next step to cancel this carry.
+	bne	4b
+	 addcc	%o1,%o1,%o1	! shift n1n0 and a 0-bit in lsb
+	sub	%i0,%o4,%i0
+3:	xnor	%o1,0,%o1
+	b .LL86
+	mov %o1,%l1
+.LL45:
+	cmp %i2,%i0
+	bleu .LL51
+	sethi %hi(65535),%o0
+	b .LL78
+	mov 0,%o1
+.LL51:
+	or %o0,%lo(65535),%o0
+	cmp %i2,%o0
+	bgu .LL58
+	mov %i2,%o1
+	cmp %i2,256
+	addx %g0,-1,%o0
+	b .LL64
+	and %o0,8,%o2
+.LL58:
+	sethi %hi(16777215),%o0
+	or %o0,%lo(16777215),%o0
+	cmp %i2,%o0
+	bgu .LL64
+	mov 24,%o2
+	mov 16,%o2
+.LL64:
+	srl %o1,%o2,%o0
+	sethi %hi(__clz_tab),%o1
+	or %o1,%lo(__clz_tab),%o1
+	ldub [%o0+%o1],%o0
+	add %o0,%o2,%o0
+	mov 32,%o1
+	subcc %o1,%o0,%o3
+	bne,a .LL72
+	sub %o1,%o3,%o1
+	cmp %i0,%i2
+	bgu .LL74
+	cmp %i3,%o4
+	blu .LL78
+	mov 0,%o1
+.LL74:
+	b .LL78
+	mov 1,%o1
+.LL72:
+	sll %i2,%o3,%o2
+	srl %o4,%o1,%o0
+	or %o2,%o0,%i2
+	sll %o4,%o3,%o4
+	srl %i0,%o1,%o2
+	sll %i0,%o3,%o0
+	srl %i3,%o1,%o1
+	or %o0,%o1,%i0
+	sll %i3,%o3,%i3
+	mov %i0,%o1
+	mov	32,%g1
+	subcc	%o2,%i2,%g0
+1:	bcs	5f
+	 addxcc %o1,%o1,%o1	! shift n1n0 and a q-bit in lsb
+	sub	%o2,%i2,%o2	! this kills msb of n
+	addx	%o2,%o2,%o2	! so this cannot give carry
+	subcc	%g1,1,%g1
+2:	bne	1b
+	 subcc	%o2,%i2,%g0
+	bcs	3f
+	 addxcc %o1,%o1,%o1	! shift n1n0 and a q-bit in lsb
+	b	3f
+	 sub	%o2,%i2,%o2	! this kills msb of n
+4:	sub	%o2,%i2,%o2
+5:	addxcc	%o2,%o2,%o2
+	bcc	2b
+	 subcc	%g1,1,%g1
+! Got carry from n.  Subtract next step to cancel this carry.
+	bne	4b
+	 addcc	%o1,%o1,%o1	! shift n1n0 and a 0-bit in lsb
+	sub	%o2,%i2,%o2
+3:	xnor	%o1,0,%o1
+	mov %o2,%i0
+	wr	%g0,%o1,%y	! SPARC has 0-3 delay insn after a wr
+	sra	%o4,31,%g2	! Do not move this insn
+	and	%o1,%g2,%g2	! Do not move this insn
+	andcc	%g0,0,%g1	! Do not move this insn
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,%o4,%g1
+	mulscc	%g1,0,%g1
+	add	%g1,%g2,%o0
+	rd	%y,%o2
+	cmp %o0,%i0
+	bgu,a .LL78
+	add %o1,-1,%o1
+	bne,a .LL50
+	mov 0,%o2
+	cmp %o2,%i3
+	bleu .LL50
+	mov 0,%o2
+	add %o1,-1,%o1
+.LL78:
+	mov 0,%o2
+.LL50:
+	mov %o1,%l1
+.LL86:
+	mov %o2,%l0
+	mov %l0,%i0
+	mov %l1,%i1
+	cmp %l4,0
+	be .LL81
+	sub %g0,%i1,%o0
+	mov %o0,%l3
+	subcc %g0,%o0,%g0
+	sub %g0,%i0,%o0
+	subx %o0,0,%l2
+	mov %l2,%i0
+	mov %l3,%i1
+.LL81:
+	ret
+	restore
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/lib/memcpy.S linux/arch/sparc/lib/memcpy.S
--- v2.1.15/linux/arch/sparc/lib/memcpy.S	Tue Nov 12 15:56:04 1996
+++ linux/arch/sparc/lib/memcpy.S	Fri Dec 13 11:37:31 1996
@@ -226,35 +226,6 @@
 	retl
  	 nop
 
-	/* Placed here for cache reasons. */
-	.globl	C_LABEL(__copy_to_user), C_LABEL(__copy_from_user)
-C_LABEL(__copy_to_user):
-	b	copy_user_common
-	 st	%o0, [%g6 + THREAD_EX_ADDR]
-
-C_LABEL(__copy_from_user):
-	st	%o1, [%g6 + THREAD_EX_ADDR]
-
-copy_user_common:
-	ld	[%g6 + THREAD_EX_COUNT], %g1
-	set	copy_user_failure, %g2
-	add	%g1, 1, %g1
-	st	%o7, [%g6 + THREAD_EX_PC]
-	st	%g1, [%g6 + THREAD_EX_COUNT]
-	call	C_LABEL(__memcpy)
-	 st	%g2, [%g6 + THREAD_EX_EXPC]
-
-copy_user_success:
-	ldd	[%g6 + THREAD_EX_COUNT], %g2
-	mov	0, %o0
-	sub	%g2, 1, %g1
-	jmpl	%g3 + 0x8, %g0
-	 st	%g1, [%g6 + THREAD_EX_COUNT]
-
-copy_user_failure:
-	jmpl	%g3 + 0x8, %g0
-	 mov	%g2, %o0
-
 ldd_std:
 	MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
 	MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/lib/memset.S linux/arch/sparc/lib/memset.S
--- v2.1.15/linux/arch/sparc/lib/memset.S	Tue Nov 12 15:56:04 1996
+++ linux/arch/sparc/lib/memset.S	Fri Dec 13 11:37:31 1996
@@ -68,28 +68,6 @@
 	 sub	%o0, %o2, %o0
 #endif /* HANDLE_UNALIGNED */
 
-	.globl	C_LABEL(__clear_user)
-C_LABEL(__clear_user):
-	st	%o0, [%g6 + THREAD_EX_ADDR]
-	ld	[%g6 + THREAD_EX_COUNT], %g1
-	set	clear_user_failure, %g2
-	add	%g1, 1, %g1
-	st	%o7, [%g6 + THREAD_EX_PC]
-	st	%g1, [%g6 + THREAD_EX_COUNT]
-	call	C_LABEL(__bzero)
-	 st	%g2, [%g6 + THREAD_EX_EXPC]
-
-clear_user_success:
-	ldd	[%g6 + THREAD_EX_COUNT], %g2
-	mov	0, %o0
-	sub	%g2, 1, %g1
-	jmpl	%g3 + 0x8, %g0
-	 st	%g1, [%g6 + THREAD_EX_COUNT]
-
-clear_user_failure:
-	jmpl	%g3 + 0x8, %g0
-	 mov	%g2, %o0
-
 C_LABEL(__bzero):
 	mov	%g0, %g3
 1:
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/lib/memset.c linux/arch/sparc/lib/memset.c
--- v2.1.15/linux/arch/sparc/lib/memset.c	Sun Apr 21 12:30:31 1996
+++ linux/arch/sparc/lib/memset.c	Thu Jan  1 02:00:00 1970
@@ -1,71 +0,0 @@
-/* linux/arch/sparc/lib/memset.c
- *
- * This is from GNU libc.
- */
-
-#include <linux/types.h>
-
-#define op_t unsigned long int
-#define OPSIZ (sizeof(op_t))
-
-typedef unsigned char byte;
-
-void *memset(void *dstpp, char c, size_t len)
-{
-	long int dstp = (long int) dstpp;
-
-	if (len >= 8) {
-			size_t xlen;
-			op_t cccc;
-
-			cccc = (unsigned char) c;
-			cccc |= cccc << 8;
-			cccc |= cccc << 16;
-
-			/* There are at least some bytes to set.
-			   No need to test for LEN == 0 in this alignment loop.  */
-			while (dstp % OPSIZ != 0) {
-				((byte *) dstp)[0] = c;
-				dstp += 1;
-				len -= 1;
-			}
-
-			/* Write 8 `op_t' per iteration until less
-			 * than 8 `op_t' remain.
-			 */
-			xlen = len / (OPSIZ * 8);
-			while (xlen > 0) {
-				((op_t *) dstp)[0] = cccc;
-				((op_t *) dstp)[1] = cccc;
-				((op_t *) dstp)[2] = cccc;
-				((op_t *) dstp)[3] = cccc;
-				((op_t *) dstp)[4] = cccc;
-				((op_t *) dstp)[5] = cccc;
-				((op_t *) dstp)[6] = cccc;
-				((op_t *) dstp)[7] = cccc;
-				dstp += 8 * OPSIZ;
-				xlen -= 1;
-			}
-			len %= OPSIZ * 8;
-
-			/* Write 1 `op_t' per iteration until less than
-			 * OPSIZ bytes remain.
-			 */
-			xlen = len / OPSIZ;
-			while (xlen > 0) {
-				((op_t *) dstp)[0] = cccc;
-				dstp += OPSIZ;
-				xlen -= 1;
-			}
-			len %= OPSIZ;
-	}
-
-	/* Write the last few bytes.  */
-	while (len > 0) {
-		((byte *) dstp)[0] = c;
-		dstp += 1;
-		len -= 1;
-	}
-
-	return dstpp;
-}
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/lib/strlen.S linux/arch/sparc/lib/strlen.S
--- v2.1.15/linux/arch/sparc/lib/strlen.S	Tue Nov 12 15:56:04 1996
+++ linux/arch/sparc/lib/strlen.S	Fri Dec 13 11:37:31 1996
@@ -1,7 +1,8 @@
-/* strlen.S: Sparc optimized strlen().
- *
- * This was hand optimized by davem@caip.rutgers.edu from
- * the C-code in GNU-libc.
+/* strlen.S: Sparc optimized strlen code
+ * Hand optimized from GNU libc's strlen
+ * Copyright (C) 1991,1996 Free Software Foundation
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 #include <asm/cprefix.h>
@@ -9,80 +10,74 @@
 #define LO_MAGIC 0x01010101
 #define HI_MAGIC 0x80808080
 
+0:
+	ldub	[%o0], %o5
+	cmp	%o5, 0
+	be	1f
+	 add	%o0, 1, %o0
+	andcc	%o0, 3, %g0
+	be	4f
+	 or	%o4, %lo(HI_MAGIC), %o3
+	ldub	[%o0], %o5
+	cmp	%o5, 0
+	be	2f
+	 add	%o0, 1, %o0
+	andcc	%o0, 3, %g0
+	be	5f
+	 sethi	%hi(LO_MAGIC), %o4
+	ldub	[%o0], %o5
+	cmp	%o5, 0
+	be	3f
+	 add	%o0, 1, %o0
+	b	8f
+	 or	%o4, %lo(LO_MAGIC), %o2
+1:
+	retl
+	 mov	0, %o0
+2:
+	retl
+	 mov	1, %o0
+3:
+	retl
+	 mov	2, %o0
+
 	.align 4
 	.global C_LABEL(strlen)
 C_LABEL(strlen):
 	mov	%o0, %o1
-	andcc	%o0, 3, %g0		! and with %o0 so no dependency problems
-	be	scan_words
-	 sethi	%hi(HI_MAGIC), %g2	! common case and most Sparcs predict taken
-
-	ldsb	[%o0], %g2
-still_not_word_aligned:
-	cmp	%g2, 0
-	bne,a	1f
-	 add	%o0, 1, %o0
-
-	/* Ok, so there are tons of quick interlocks above for the
-	 * < 4 length string unaligned... not too common so I'm not
-	 * very concerned.
-	 */
-	retl
-	 sub	%o0, %o1, %o0
-
-1:
 	andcc	%o0, 3, %g0
-	bne,a	still_not_word_aligned
-	 ldsb	[%o0], %g2
-
-	/* HyperSparc executes each sethi/or pair in 1 cycle. */
-	sethi	%hi(HI_MAGIC), %g2
-scan_words:
-	or	%g2, %lo(HI_MAGIC), %o3
-	sethi	%hi(LO_MAGIC), %g3
-	or	%g3, %lo(LO_MAGIC), %o2
-next_word:
-	ld	[%o0], %g2		! no dependencies
-next_word_preloaded:
-	sub	%g2, %o2, %g2		! lots of locks here
-	andcc	%g2, %o3, %g0		! and I dont like it...
-	be	next_word
+	bne	0b
+	 sethi	%hi(HI_MAGIC), %o4
+	or	%o4, %lo(HI_MAGIC), %o3
+4:
+	sethi	%hi(LO_MAGIC), %o4
+5:
+	or	%o4, %lo(LO_MAGIC), %o2
+8:
+	ld	[%o0], %o5
+2:
+	sub	%o5, %o2, %o4
+	andcc	%o4, %o3, %g0
+	be	8b
 	 add	%o0, 4, %o0
 
 	/* Check every byte. */
-byte_zero:
-	ldsb	[%o0 - 0x4], %g2
-	cmp	%g2, 0
-	bne	byte_one
-	 add	%o0, -4, %g3
-
-	retl
-	 sub	%g3, %o1, %o0
-
-byte_one:
-	ldsb	[%o0 - 0x3], %g2
-	cmp	%g2, 0
-	bne,a	byte_two_and_three
-	 ldsb	[%o0 - 0x2], %g2
-
-	sub	%g3, %o1, %o0
-	retl
-	 add	%o0, 1, %o0
-
-byte_two_and_three:
-	cmp	%g2, 0
-	be,a	found_it
-	 sub	%g3, %o1, %o0
-
-	ldsb	[%o0 - 0x1], %g2
-	cmp	%g2, 0
-	bne,a	next_word_preloaded
-	 ld	[%o0], %g2
-
-	sub	%g3, %o1, %o0
-	retl
-	 add	%o0, 3, %o0
-
-found_it:
+	srl	%o5, 24, %g5
+	andcc	%g5, 0xff, %g0
+	be	1f
+	 add	%o0, -4, %o4
+	srl	%o5, 16, %g5
+	andcc	%g5, 0xff, %g0
+	be	1f
+	 add	%o4, 1, %o4
+	srl	%o5, 8, %g5
+	andcc	%g5, 0xff, %g0
+	be	1f
+	 add	%o4, 1, %o4
+	andcc	%o5, 0xff, %g0
+	bne,a	2b
+	 ld	[%o0], %o5
+	add	%o4, 1, %o4
+1:
 	retl
-	 add	%o0, 2, %o0
+	 sub	%o4, %o1, %o0
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/lib/strlen_user.S linux/arch/sparc/lib/strlen_user.S
--- v2.1.15/linux/arch/sparc/lib/strlen_user.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/lib/strlen_user.S	Fri Dec 13 11:37:31 1996
@@ -0,0 +1,104 @@
+/* strlen_user.S: Sparc optimized strlen_user code
+ *
+ * Return length of string in userspace including terminating 0
+ * or 0 for error
+ *
+ * Copyright (C) 1991,1996 Free Software Foundation
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <asm/cprefix.h>
+
+#define LO_MAGIC 0x01010101
+#define HI_MAGIC 0x80808080
+
+10:
+	ldub	[%o0], %o5
+	cmp	%o5, 0
+	be	1f
+	 add	%o0, 1, %o0
+	andcc	%o0, 3, %g0
+	be	4f
+	 or	%o4, %lo(HI_MAGIC), %o3
+11:
+	ldub	[%o0], %o5
+	cmp	%o5, 0
+	be	2f
+	 add	%o0, 1, %o0
+	andcc	%o0, 3, %g0
+	be	5f
+	 sethi	%hi(LO_MAGIC), %o4
+12:
+	ldub	[%o0], %o5
+	cmp	%o5, 0
+	be	3f
+	 add	%o0, 1, %o0
+	b	13f
+	 or	%o4, %lo(LO_MAGIC), %o2
+1:
+	retl
+	 mov	1, %o0
+2:
+	retl
+	 mov	2, %o0
+3:
+	retl
+	 mov	3, %o0
+
+	.align 4
+	.global C_LABEL(__strlen_user)
+C_LABEL(__strlen_user):
+	mov	%o0, %o1
+	andcc	%o0, 3, %g0
+	bne	10b
+	 sethi	%hi(HI_MAGIC), %o4
+	or	%o4, %lo(HI_MAGIC), %o3
+4:
+	sethi	%hi(LO_MAGIC), %o4
+5:
+	or	%o4, %lo(LO_MAGIC), %o2
+13:
+	ld	[%o0], %o5
+2:
+	sub	%o5, %o2, %o4
+	andcc	%o4, %o3, %g0
+	be	13b
+	 add	%o0, 4, %o0
+
+	/* Check every byte. */
+	srl	%o5, 24, %g5
+	andcc	%g5, 0xff, %g0
+	be	1f
+	 add	%o0, -3, %o4
+	srl	%o5, 16, %g5
+	andcc	%g5, 0xff, %g0
+	be	1f
+	 add	%o4, 1, %o4
+	srl	%o5, 8, %g5
+	andcc	%g5, 0xff, %g0
+	be	1f
+	 add	%o4, 1, %o4
+	andcc	%o5, 0xff, %g0
+	bne,a	2b
+14:
+	 ld	[%o0], %o5
+	add	%o4, 1, %o4
+1:
+	retl
+	 sub	%o4, %o1, %o0
+
+	.section .fixup,#alloc,#execinstr
+	.align	4
+9:
+	retl
+	 clr	%o0
+
+	.section __ex_table,#alloc
+	.align	4
+
+	.word	10b, 9b
+	.word	11b, 9b
+	.word	12b, 9b
+	.word	13b, 9b
+	.word	14b, 9b
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/lib/strncpy_from_user.S linux/arch/sparc/lib/strncpy_from_user.S
--- v2.1.15/linux/arch/sparc/lib/strncpy_from_user.S	Tue Nov 12 15:56:04 1996
+++ linux/arch/sparc/lib/strncpy_from_user.S	Fri Dec 13 11:37:31 1996
@@ -5,6 +5,7 @@
 
 #include <asm/cprefix.h>
 #include <asm/ptrace.h>
+#include <asm/errno.h>
 
 	.text
 	.align	4
@@ -19,19 +20,12 @@
 	.globl	C_LABEL(__strncpy_from_user)
 C_LABEL(__strncpy_from_user):
 	/* %o0=dest, %o1=src, %o2=count */
-	ld	[%g6 + THREAD_EX_COUNT], %g1
-	set	strncpy_user_failure, %g2
-	add	%g1, 1, %g3
-	st	%o7, [%g6 + THREAD_EX_PC]
-	st	%g3, [%g6 + THREAD_EX_COUNT]
-	st	%g2, [%g6 + THREAD_EX_EXPC]
-
 	mov	%o2, %o3
 1:
 	subcc	%o2, 1, %o2
 	bneg	2f
 	 nop
-
+10:
 	ldub	[%o1], %o4
 	add	%o0, 1, %o0
 	cmp	%o4, 0
@@ -40,10 +34,15 @@
 	 stb	%o4, [%o0 - 1]
 2:
 	add	%o2, 1, %o0
-	st	%g1, [%g6 + THREAD_EX_COUNT]
 	retl
 	 sub	%o3, %o0, %o0
 
-strncpy_user_failure:
-	jmpl	%g3 + 0x8, %g0
-	 mov	%g1, %o0
+	.section .fixup,#alloc,#execinstr
+	.align	4
+4:
+	retl
+	 mov	-EFAULT, %o0
+
+	.section __ex_table,#alloc
+	.align	4
+	.word	10b, 4b
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/lib/udivdi3.S linux/arch/sparc/lib/udivdi3.S
--- v2.1.15/linux/arch/sparc/lib/udivdi3.S	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/lib/udivdi3.S	Fri Dec 13 11:37:31 1996
@@ -0,0 +1,258 @@
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+	.text
+	.align 4
+	.globl __udivdi3
+__udivdi3:
+	save %sp,-104,%sp
+	mov %i3,%o3
+	cmp %i2,0
+	bne .LL40
+	mov %i1,%i3
+	cmp %o3,%i0
+	bleu .LL41
+	mov %i3,%o1
+	! Inlined udiv_qrnnd
+	mov	32,%g1
+	subcc	%i0,%o3,%g0
+1:	bcs	5f
+	 addxcc %o1,%o1,%o1	! shift n1n0 and a q-bit in lsb
+	sub	%i0,%o3,%i0	! this kills msb of n
+	addx	%i0,%i0,%i0	! so this cannot give carry
+	subcc	%g1,1,%g1
+2:	bne	1b
+	 subcc	%i0,%o3,%g0
+	bcs	3f
+	 addxcc %o1,%o1,%o1	! shift n1n0 and a q-bit in lsb
+	b	3f
+	 sub	%i0,%o3,%i0	! this kills msb of n
+4:	sub	%i0,%o3,%i0
+5:	addxcc	%i0,%i0,%i0
+	bcc	2b
+	 subcc	%g1,1,%g1
+! Got carry from n.  Subtract next step to cancel this carry.
+	bne	4b
+	 addcc	%o1,%o1,%o1	! shift n1n0 and a 0-bit in lsb
+	sub	%i0,%o3,%i0
+3:	xnor	%o1,0,%o1
+	! End of inline udiv_qrnnd
+	b .LL45
+	mov 0,%o2
+.LL41:
+	cmp %o3,0
+	bne .LL77
+	mov %i0,%o2
+	mov 1,%o0
+	call .udiv,0
+	mov 0,%o1
+	mov %o0,%o3
+	mov %i0,%o2
+.LL77:
+	mov 0,%o4
+	! Inlined udiv_qrnnd
+	mov	32,%g1
+	subcc	%o4,%o3,%g0
+1:	bcs	5f
+	 addxcc %o2,%o2,%o2	! shift n1n0 and a q-bit in lsb
+	sub	%o4,%o3,%o4	! this kills msb of n
+	addx	%o4,%o4,%o4	! so this cannot give carry
+	subcc	%g1,1,%g1
+2:	bne	1b
+	 subcc	%o4,%o3,%g0
+	bcs	3f
+	 addxcc %o2,%o2,%o2	! shift n1n0 and a q-bit in lsb
+	b	3f
+	 sub	%o4,%o3,%o4	! this kills msb of n
+4:	sub	%o4,%o3,%o4
+5:	addxcc	%o4,%o4,%o4
+	bcc	2b
+	 subcc	%g1,1,%g1
+! Got carry from n.  Subtract next step to cancel this carry.
+	bne	4b
+	 addcc	%o2,%o2,%o2	! shift n1n0 and a 0-bit in lsb
+	sub	%o4,%o3,%o4
+3:	xnor	%o2,0,%o2
+	! End of inline udiv_qrnnd
+	mov %o4,%i0
+	mov %i3,%o1
+	! Inlined udiv_qrnnd
+	mov	32,%g1
+	subcc	%i0,%o3,%g0
+1:	bcs	5f
+	 addxcc %o1,%o1,%o1	! shift n1n0 and a q-bit in lsb
+	sub	%i0,%o3,%i0	! this kills msb of n
+	addx	%i0,%i0,%i0	! so this cannot give carry
+	subcc	%g1,1,%g1
+2:	bne	1b
+	 subcc	%i0,%o3,%g0
+	bcs	3f
+	 addxcc %o1,%o1,%o1	! shift n1n0 and a q-bit in lsb
+	b	3f
+	 sub	%i0,%o3,%i0	! this kills msb of n
+4:	sub	%i0,%o3,%i0
+5:	addxcc	%i0,%i0,%i0
+	bcc	2b
+	 subcc	%g1,1,%g1
+! Got carry from n.  Subtract next step to cancel this carry.
+	bne	4b
+	 addcc	%o1,%o1,%o1	! shift n1n0 and a 0-bit in lsb
+	sub	%i0,%o3,%i0
+3:	xnor	%o1,0,%o1
+	! End of inline udiv_qrnnd
+	b .LL78
+	mov %o1,%l1
+.LL40:
+	cmp %i2,%i0
+	bleu .LL46
+	sethi %hi(65535),%o0
+	b .LL73
+	mov 0,%o1
+.LL46:
+	or %o0,%lo(65535),%o0
+	cmp %i2,%o0
+	bgu .LL53
+	mov %i2,%o1
+	cmp %i2,256
+	addx %g0,-1,%o0
+	b .LL59
+	and %o0,8,%o2
+.LL53:
+	sethi %hi(16777215),%o0
+	or %o0,%lo(16777215),%o0
+	cmp %o1,%o0
+	bgu .LL59
+	mov 24,%o2
+	mov 16,%o2
+.LL59:
+	srl %o1,%o2,%o1
+	sethi %hi(__clz_tab),%o0
+	or %o0,%lo(__clz_tab),%o0
+	ldub [%o1+%o0],%o0
+	add %o0,%o2,%o0
+	mov 32,%o1
+	subcc %o1,%o0,%o2
+	bne,a .LL67
+	mov 32,%o0
+	cmp %i0,%i2
+	bgu .LL69
+	cmp %i3,%o3
+	blu .LL73
+	mov 0,%o1
+.LL69:
+	b .LL73
+	mov 1,%o1
+.LL67:
+	sub %o0,%o2,%o0
+	sll %i2,%o2,%i2
+	srl %o3,%o0,%o1
+	or %i2,%o1,%i2
+	sll %o3,%o2,%o3
+	srl %i0,%o0,%o1
+	sll %i0,%o2,%i0
+	srl %i3,%o0,%o0
+	or %i0,%o0,%i0
+	sll %i3,%o2,%i3
+	mov %i0,%o5
+	mov %o1,%o4
+	! Inlined udiv_qrnnd
+	mov	32,%g1
+	subcc	%o4,%i2,%g0
+1:	bcs	5f
+	 addxcc %o5,%o5,%o5	! shift n1n0 and a q-bit in lsb
+	sub	%o4,%i2,%o4	! this kills msb of n
+	addx	%o4,%o4,%o4	! so this cannot give carry
+	subcc	%g1,1,%g1
+2:	bne	1b
+	 subcc	%o4,%i2,%g0
+	bcs	3f
+	 addxcc %o5,%o5,%o5	! shift n1n0 and a q-bit in lsb
+	b	3f
+	 sub	%o4,%i2,%o4	! this kills msb of n
+4:	sub	%o4,%i2,%o4
+5:	addxcc	%o4,%o4,%o4
+	bcc	2b
+	 subcc	%g1,1,%g1
+! Got carry from n.  Subtract next step to cancel this carry.
+	bne	4b
+	 addcc	%o5,%o5,%o5	! shift n1n0 and a 0-bit in lsb
+	sub	%o4,%i2,%o4
+3:	xnor	%o5,0,%o5
+	! End of inline udiv_qrnnd
+	mov %o4,%i0
+	mov %o5,%o1
+	! Inlined umul_ppmm
+	wr	%g0,%o1,%y	! SPARC has 0-3 delay insn after a wr
+	sra	%o3,31,%g2	! Do not move this insn
+	and	%o1,%g2,%g2	! Do not move this insn
+	andcc	%g0,0,%g1	! Do not move this insn
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,%o3,%g1
+	mulscc	%g1,0,%g1
+	add	%g1,%g2,%o0
+	rd	%y,%o2
+	cmp %o0,%i0
+	bgu,a .LL73
+	add %o1,-1,%o1
+	bne,a .LL45
+	mov 0,%o2
+	cmp %o2,%i3
+	bleu .LL45
+	mov 0,%o2
+	add %o1,-1,%o1
+.LL73:
+	mov 0,%o2
+.LL45:
+	mov %o1,%l1
+.LL78:
+	mov %o2,%l0
+	mov %l0,%i0
+	mov %l1,%i1
+	ret
+	restore
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/mm/Makefile linux/arch/sparc/mm/Makefile
--- v2.1.15/linux/arch/sparc/mm/Makefile	Tue Nov 12 15:56:04 1996
+++ linux/arch/sparc/mm/Makefile	Fri Dec 13 11:37:31 1996
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.21 1996/04/26 10:45:53 tridge Exp $
+# $Id: Makefile,v 1.22 1996/11/22 11:57:03 ecd Exp $
 # Makefile for the linux Sparc-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -8,6 +8,7 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 O_TARGET := mm.o
-O_OBJS   := fault.o init.o sun4c.o srmmu.o loadmmu.o generic.o asyncd.o
+O_OBJS   := fault.o init.o sun4c.o srmmu.o loadmmu.o generic.o asyncd.o \
+	    extable.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/mm/extable.c linux/arch/sparc/mm/extable.c
--- v2.1.15/linux/arch/sparc/mm/extable.c	Thu Jan  1 02:00:00 1970
+++ linux/arch/sparc/mm/extable.c	Fri Dec 13 11:37:31 1996
@@ -0,0 +1,70 @@
+/*
+ * linux/arch/sparc/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 unsigned long
+search_one_table(const struct exception_table_entry *start,
+		 const struct exception_table_entry *last,
+		 unsigned long value, unsigned long *g2)
+{
+	const struct exception_table_entry *first = start;
+	const struct exception_table_entry *mid;
+	long diff = 0;
+        while (first <= last) {
+		mid = (last - first) / 2 + first;
+		diff = mid->insn - value;
+                if (diff == 0) {
+                	if (!mid->fixup) {
+                		*g2 = 0;
+                		return (mid + 1)->fixup;
+                	} else
+	                        return mid->fixup;
+                } else if (diff < 0)
+                        first = mid+1;
+                else
+                        last = mid-1;
+        }
+        if (last->insn < value && !last->fixup && (last + 1)->insn > value) {
+        	*g2 = (value - last->insn)/4;
+        	return (last + 1)->fixup;
+        }
+        if (first > start && (first-1)->insn < value && !(first-1)->fixup && first->insn < value) {
+        	*g2 = (value - (first-1)->insn)/4;
+        	return first->fixup;
+        }
+        return 0;
+}
+
+unsigned long
+search_exception_table(unsigned long addr, unsigned long *g2)
+{
+	unsigned long ret;
+#ifdef CONFIG_MODULES
+	struct module *mp;
+#endif
+
+	/* Search the kernel's table first.  */
+	ret = search_one_table(__start___ex_table,
+			       __stop___ex_table-1, addr, g2);
+	if (ret)
+		return ret;
+
+#ifdef CONFIG_MODULES
+	for (mp = module_list; mp != NULL; mp = mp->next) {
+		if (mp->exceptinfo.start != NULL) {
+			ret = search_one_table(mp->exceptinfo.start,
+				mp->exceptinfo.stop-1, addr, g2);
+			if (ret)
+				return ret;
+		}
+	}
+#endif
+	return 0;
+}
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
--- v2.1.15/linux/arch/sparc/mm/fault.c	Tue Nov 12 15:56:04 1996
+++ linux/arch/sparc/mm/fault.c	Fri Dec 13 11:37:31 1996
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.77 1996/10/28 00:56:02 davem Exp $
+/* $Id: fault.c,v 1.84 1996/12/10 06:06:23 davem Exp $
  * fault.c:  Page fault handlers for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -26,6 +26,7 @@
 #include <asm/smp.h>
 #include <asm/traps.h>
 #include <asm/kdebug.h>
+#include <asm/uaccess.h>
 
 #define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0]))
 
@@ -70,8 +71,10 @@
 		bytes = mlist->num_bytes;
 		tally += bytes;
 		if (i >= SPARC_PHYS_BANKS-1) {
-			printk ("The machine has more banks that this kernel can support\n"
-				"Increase the SPARC_PHYS_BANKS setting (currently %d)\n",
+			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;
@@ -134,6 +137,8 @@
 	struct vm_area_struct *vma;
 	struct task_struct *tsk = current;
 	struct mm_struct *mm = tsk->mm;
+	unsigned int fixup;
+	unsigned long g2;
 	int from_user = !(regs->psr & PSR_PS);
 #if 0
 	static unsigned long last_one;
@@ -162,15 +167,12 @@
 #endif
 	}
 #endif
-	/* Now actually handle the fault.  Do kernel faults special,
-	 * because on the sun4c we could have faulted trying to read
-	 * the vma area of the task and without the following code
-	 * we'd fault recursively until all our stack is gone. ;-(
+
+	/* The kernel referencing a bad kernel pointer can lock up
+	 * a sun4c machine completely, so we must attempt recovery.
 	 */
-	if(!from_user && address >= PAGE_OFFSET) {
-		quick_kernel_fault(address);
-		return;
-	}
+	if(!from_user && address >= PAGE_OFFSET)
+		goto bad_area;
 
 	vma = find_vma(mm, address);
 	if(!vma)
@@ -203,6 +205,18 @@
 	 */
 bad_area:
 	up(&mm->mmap_sem);
+	/* Is this in ex_table? */
+	
+	g2 = regs->u_regs[UREG_G2];
+	if (!from_user && (fixup = search_exception_table (regs->pc, &g2))) {
+		printk("Exception: PC<%08lx> faddr<%08lx>\n", regs->pc, address);
+		printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n",
+			regs->pc, fixup, g2);
+		regs->pc = fixup;
+		regs->npc = regs->pc + 4;
+		regs->u_regs[UREG_G2] = g2;
+		return;
+	}
 	/* Did we have an exception handler installed? */
 	if(current->tss.ex.count == 1) {
 		if(from_user) {
@@ -235,10 +249,12 @@
 		return;
 	}
 	if((unsigned long) address < PAGE_SIZE) {
-		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
-	} else
-		printk(KERN_ALERT "Unable to handle kernel paging request");
-	printk(KERN_ALERT " at virtual address %08lx\n",address);
+		printk(KERN_ALERT "Unable to handle kernel NULL "
+		       "pointer dereference");
+	} else {
+		printk(KERN_ALERT "Unable to handle kernel paging request "
+		       "at virtual address %08lx\n", address);
+	}
 	printk(KERN_ALERT "tsk->mm->context = %08lx\n",
 	       (unsigned long) tsk->mm->context);
 	printk(KERN_ALERT "tsk->mm->pgd = %08lx\n",
@@ -249,27 +265,62 @@
 asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write,
 			       unsigned long address)
 {
-	extern void sun4c_update_mmu_cache(struct vm_area_struct *,unsigned long,pte_t);
+	extern void sun4c_update_mmu_cache(struct vm_area_struct *,
+					   unsigned long,pte_t);
 	extern pgd_t *sun4c_pgd_offset(struct mm_struct *,unsigned long);
 	extern pte_t *sun4c_pte_offset(pmd_t *,unsigned long);
 	struct task_struct *tsk = current;
 	struct mm_struct *mm = tsk->mm;
-	pgd_t *pgd;
-	pte_t *pte;
+	pgd_t *pgdp;
+	pte_t *ptep;
 
-	if(text_fault)
+	if (text_fault)
 		address = regs->pc;
 
-	pgd = sun4c_pgd_offset(mm, address);
-	pte = sun4c_pte_offset((pmd_t *) pgd, address);
+	pgdp = sun4c_pgd_offset(mm, address);
+	ptep = sun4c_pte_offset((pmd_t *) pgdp, address);
+
+	if (pgd_val(*pgdp)) {
+	    if (write) {
+		if ((pte_val(*ptep) & (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT))
+				   == (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT)) {
+
+			pte_val(*ptep) |= (_SUN4C_PAGE_ACCESSED |
+					   _SUN4C_PAGE_MODIFIED |
+					   _SUN4C_PAGE_VALID |
+					   _SUN4C_PAGE_DIRTY);
+
+			if (sun4c_get_segmap(address) != invalid_segment) {
+				sun4c_put_pte(address, pte_val(*ptep));
+				return;
+			}
+		}
+	    } else {
+		if ((pte_val(*ptep) & (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT))
+				   == (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT)) {
+
+			pte_val(*ptep) |= (_SUN4C_PAGE_ACCESSED |
+					   _SUN4C_PAGE_VALID);
+
+			if (sun4c_get_segmap(address) != invalid_segment) {
+				sun4c_put_pte(address, pte_val(*ptep));
+				return;
+			}
+		}
+	    }
+	}
 
 	/* This conditional is 'interesting'. */
-	if(pgd_val(*pgd) && !(write && !(pte_val(*pte) & _SUN4C_PAGE_WRITE))
-	   && (pte_val(*pte) & _SUN4C_PAGE_VALID))
-		/* XXX Very bad, can't do this optimization when VMA arg is actually
-		 * XXX used by update_mmu_cache()!
+	if (pgd_val(*pgdp) && !(write && !(pte_val(*ptep) & _SUN4C_PAGE_WRITE))
+	    && (pte_val(*ptep) & _SUN4C_PAGE_VALID))
+		/* Note: It is safe to not grab the MMAP semaphore here because
+		 *       we know that update_mmu_cache() will not sleep for
+		 *       any reason (at least not in the current implementation)
+		 *       and therefore there is no danger of another thread getting
+		 *       on the CPU and doing a shrink_mmap() on this vma.
 		 */
-		sun4c_update_mmu_cache((struct vm_area_struct *) 0, address, *pte);
+		sun4c_update_mmu_cache (find_vma(current->mm, address), address,
+					*ptep);
 	else
 		do_sparc_fault(regs, text_fault, write, address);
 }
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/mm/init.c linux/arch/sparc/mm/init.c
--- v2.1.15/linux/arch/sparc/mm/init.c	Tue Nov 12 15:56:04 1996
+++ linux/arch/sparc/mm/init.c	Fri Dec 13 11:37:31 1996
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.42 1996/10/27 08:36:44 davem Exp $
+/*  $Id: init.c,v 1.45 1996/12/11 10:23:06 davem Exp $
  *  linux/arch/sparc/mm/init.c
  *
  *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -20,6 +20,7 @@
 #ifdef CONFIG_BLK_DEV_INITRD
 #include <linux/blk.h>
 #endif
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/segment.h>
@@ -88,7 +89,7 @@
 
 extern pgprot_t protection_map[16];
 
-unsigned long sparc_context_init(unsigned long start_mem, int numctx)
+__initfunc(unsigned long sparc_context_init(unsigned long start_mem, int numctx))
 {
 	int ctx;
 
@@ -117,7 +118,8 @@
 extern unsigned long srmmu_paging_init(unsigned long, unsigned long);
 extern unsigned long device_scan(unsigned long);
 
-unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(unsigned long 
+paging_init(unsigned long start_mem, unsigned long end_mem))
 {
 	switch(sparc_cpu_model) {
 	case sun4c:
@@ -166,7 +168,7 @@
 
 int physmem_mapped_contig = 1;
 
-static void taint_real_pages(unsigned long start_mem, unsigned long end_mem)
+__initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long end_mem))
 {
 	unsigned long addr, tmp2 = 0;
 
@@ -194,7 +196,7 @@
 	}
 }
 
-void mem_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
 {
 	int codepages = 0;
 	int datapages = 0;
@@ -209,6 +211,7 @@
 	high_memory = (void *) end_mem;
 
 	start_mem = PAGE_ALIGN(start_mem);
+	num_physpages = (start_mem - KERNBASE) >> PAGE_SHIFT;
 
 	addr = KERNBASE;
 	while(addr < start_mem) {
@@ -231,6 +234,7 @@
 			continue;
 		}
 		mem_map[MAP_NR(addr)].count = 1;
+		num_physpages++;
 #ifdef CONFIG_BLK_DEV_INITRD
 		if (!initrd_start ||
 		    (addr < initrd_start || addr >= initrd_end))
@@ -250,6 +254,32 @@
 		min_free_pages = 16;
 	free_pages_low = min_free_pages + (min_free_pages >> 1);
 	free_pages_high = min_free_pages + min_free_pages;
+}
+
+void free_initmem (void)
+{
+	extern int text_init_begin, text_init_end, data_init_begin, data_init_end;
+	unsigned long addr, addrend;
+	int savec, saved;
+	
+	addr = PAGE_ALIGN((unsigned long)(&text_init_begin));
+	addrend = ((unsigned long)(&text_init_end)) & PAGE_MASK;
+	for (savec = addrend - addr; addr < addrend; addr += PAGE_SIZE) {
+		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
+		mem_map[MAP_NR(addr)].count = 1;
+		free_page(addr);
+	}
+	if (savec < 0) savec = 0;
+	addr = PAGE_ALIGN((unsigned long)(&data_init_begin));
+	addrend = ((unsigned long)(&data_init_end)) & PAGE_MASK;
+	for (saved = addrend - addr; addr < addrend; addr += PAGE_SIZE) {
+		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
+		mem_map[MAP_NR(addr)].count = 1;
+		free_page(addr);
+	}
+	if (saved < 0) saved = 0;
+	printk ("Freeing unused kernel memory: %dk code, %dk data\n",
+        	savec >> 10, saved >> 10);
 }
 
 void si_meminfo(struct sysinfo *val)
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/mm/loadmmu.c linux/arch/sparc/mm/loadmmu.c
--- v2.1.15/linux/arch/sparc/mm/loadmmu.c	Tue Nov 12 15:56:04 1996
+++ linux/arch/sparc/mm/loadmmu.c	Fri Dec 13 11:37:31 1996
@@ -1,4 +1,4 @@
-/* $Id: loadmmu.c,v 1.36 1996/10/27 08:36:46 davem Exp $
+/* $Id: loadmmu.c,v 1.42 1996/12/03 08:44:47 jj Exp $
  * loadmmu.c:  This code loads up all the mm function pointers once the
  *             machine type has been determined.  It also sets the static
  *             mmu values such as PAGE_NONE, etc.
@@ -8,12 +8,15 @@
 
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/a.out.h>
 
 unsigned long page_offset = 0xf0000000;
+unsigned long stack_top = 0xf0000000 - PAGE_SIZE;
 
 struct ctx_list *ctx_list_pool;
 struct ctx_list ctx_free;
@@ -58,6 +61,7 @@
 			      unsigned long end);
 void (*local_flush_tlb_page)(struct vm_area_struct *, unsigned long address);
 void (*local_flush_page_to_ram)(unsigned long address);
+void (*local_flush_sig_insns)(struct mm_struct *mm, unsigned long insn_addr);
 #endif
 
 void (*flush_cache_all)(void);
@@ -74,6 +78,8 @@
 
 void (*flush_page_to_ram)(unsigned long page);
 
+void (*flush_sig_insns)(struct mm_struct *mm, unsigned long insn_addr);
+
 void (*set_pte)(pte_t *pteptr, pte_t pteval);
 
 unsigned int pmd_shift, pmd_size, pmd_mask;
@@ -128,6 +134,7 @@
 void (*pgd_free)(pgd_t *);
 
 pgd_t * (*pgd_alloc)(void);
+void (*pgd_flush)(pgd_t *);
 
 int (*pte_write)(pte_t);
 int (*pte_dirty)(pte_t);
@@ -145,8 +152,7 @@
 extern void ld_mmu_sun4c(void);
 extern void ld_mmu_srmmu(void);
 
-void
-load_mmu(void)
+__initfunc(void load_mmu(void))
 {
 	switch(sparc_cpu_model) {
 	case sun4c:
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v2.1.15/linux/arch/sparc/mm/srmmu.c	Tue Nov 12 15:56:04 1996
+++ linux/arch/sparc/mm/srmmu.c	Fri Dec 13 11:37:31 1996
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.103 1996/10/31 06:28:35 davem Exp $
+/* $Id: srmmu.c,v 1.116 1996/12/12 11:57:59 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -10,6 +10,8 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -25,6 +27,7 @@
 #include <asm/iommu.h>
 #include <asm/asi.h>
 #include <asm/msi.h>
+#include <asm/a.out.h>
 
 /* Now the cpu specific definitions. */
 #include <asm/viking.h>
@@ -51,6 +54,7 @@
 
 /* #define USE_CHUNK_ALLOC 1 */
 
+static unsigned long (*mmu_getpage)(void);
 static void (*ctxd_set)(ctxd_t *ctxp, pgd_t *pgdp);
 static void (*pmd_set)(pmd_t *pmdp, pte_t *ptep);
 
@@ -327,7 +331,7 @@
 	flush_tlb_page_for_cbit(addr);
 }
 
-static inline unsigned long srmmu_getpage(void)
+static unsigned long srmmu_getpage(void)
 {
 	unsigned long page = get_free_page(GFP_KERNEL);
 
@@ -585,9 +589,9 @@
 #else
 
 /* The easy versions. */
-#define NEW_PGD() (pgd_t *) srmmu_getpage()
-#define NEW_PMD() (pmd_t *) srmmu_getpage()
-#define NEW_PTE() (pte_t *) srmmu_getpage()
+#define NEW_PGD() (pgd_t *) mmu_getpage()
+#define NEW_PMD() (pmd_t *) mmu_getpage()
+#define NEW_PTE() (pte_t *) mmu_getpage()
 #define FREE_PGD(chunk) srmmu_putpage((unsigned long)(chunk))
 #define FREE_PMD(chunk) srmmu_putpage((unsigned long)(chunk))
 #define FREE_PTE(chunk) srmmu_putpage((unsigned long)(chunk))
@@ -723,6 +727,10 @@
 	return NEW_PGD();
 }
 
+static void srmmu_pgd_flush(pgd_t *pgdp)
+{
+}
+
 static void srmmu_set_pte_cacheable(pte_t *ptep, pte_t pteval)
 {
 	srmmu_set_entry(ptep, pte_val(pteval));
@@ -730,11 +738,14 @@
 
 static void srmmu_set_pte_nocache_hyper(pte_t *ptep, pte_t pteval)
 {
+	volatile unsigned long clear;
 	unsigned long flags;
 
 	save_and_cli(flags);
 	srmmu_set_entry(ptep, pte_val(pteval));
-	hyper_flush_cache_page(((unsigned long)ptep) & PAGE_MASK);
+	if(srmmu_hwprobe(((unsigned long)ptep)&PAGE_MASK))
+		hyper_flush_cache_page(((unsigned long)ptep) & PAGE_MASK);
+	clear = srmmu_get_fstatus();
 	restore_flags(flags);
 }
 
@@ -768,12 +779,11 @@
 
 static void srmmu_set_pte_nocache_nomxccvik(pte_t *ptep, pte_t pteval)
 {
-	unsigned long paddr = srmmu_v2p(((unsigned long)ptep));
 	unsigned long vaddr;
 	int set;
 	int i;
 
-	set = (paddr >> 5) & 0x7f;
+	set = ((unsigned long)ptep >> 5) & 0x7f;
 	vaddr = (KERNBASE + PAGE_SIZE) | (set << 5);
 	srmmu_set_entry(ptep, pteval);
 	for (i = 0; i < 8; i++) {
@@ -789,6 +799,8 @@
 	       smp_processor_id(), address);
 	while (1) ;
 #else
+	extern void die_if_kernel(char *str, struct pt_regs *regs);
+
 	printk("Kernel faults at addr=0x%08lx\n", address);
 	printk("PTE=%08lx\n", srmmu_hwprobe((address & PAGE_MASK)));
 	die_if_kernel("SRMMU bolixed...", current->tss.kregs);
@@ -922,7 +934,12 @@
 
 unsigned long srmmu_alloc_kernel_stack(struct task_struct *tsk)
 {
-	return __get_free_pages(GFP_KERNEL, 1, 0);
+	unsigned long kstk = __get_free_pages(GFP_KERNEL, 1, 0);
+
+	if(!kstk)
+		kstk = (unsigned long) vmalloc(PAGE_SIZE << 1);
+
+	return kstk;
 }
 
 static void srmmu_free_task_struct(struct task_struct *tsk)
@@ -932,7 +949,10 @@
 
 static void srmmu_free_kernel_stack(unsigned long stack)
 {
-	free_pages(stack, 1);
+	if(stack < VMALLOC_START)
+		free_pages(stack, 1);
+	else
+		vfree((char *)stack);
 }
 
 /* Tsunami flushes.  It's page level tlb invalidation is not very
@@ -1003,6 +1023,15 @@
 	tsunami_flush_dcache();
 }
 
+/* Tsunami has harvard style split I/D caches which do not snoop each other,
+ * so we have to flush on-stack sig insns.  Only the icache need be flushed
+ * since the Tsunami has a write-through data cache.
+ */
+static void tsunami_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
+{
+	tsunami_flush_icache();
+}
+
 static void tsunami_flush_tlb_all(void)
 {
 	module_stats.invall++;
@@ -1122,6 +1151,15 @@
 	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_cache_page_to_uncache(unsigned long page)
 {
 	swift_flush_dcache();
@@ -1204,6 +1242,13 @@
 {
 }
 
+/* All vikings have an icache which snoops the processor bus and is fully
+ * coherent with the dcache, so no flush is necessary at all.
+ */
+static void viking_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
+{
+}
+
 static void viking_mxcc_flush_page(unsigned long page)
 {
 	unsigned long ppage = srmmu_v2p(page & PAGE_MASK);
@@ -1293,6 +1338,19 @@
 {
 }
 
+static unsigned long viking_no_mxcc_getpage(void)
+{
+	unsigned long page = get_free_page(GFP_KERNEL);
+
+	viking_no_mxcc_flush_page(page);
+	return page;
+}
+
+static void viking_no_mxcc_pgd_flush(pgd_t *pgdp)
+{
+	viking_no_mxcc_flush_page((unsigned long)pgdp);
+}
+
 static void viking_flush_tlb_all(void)
 {
 	module_stats.invall++;
@@ -1329,13 +1387,13 @@
 		flush_user_windows();
 		octx = srmmu_get_context();
 		srmmu_set_context(mm->context);
-		if((start - end) < SRMMU_PMD_SIZE) {
+		if((end - start) < SRMMU_PMD_SIZE) {
 			start &= PAGE_MASK;
 			while(start < end) {
 				srmmu_flush_tlb_page(start);
 				start += PAGE_SIZE;
 			}
-		} else if((start - end) < SRMMU_PGDIR_SIZE) {
+		} else if((end - start) < SRMMU_PGDIR_SIZE) {
 			start &= SRMMU_PMD_MASK;
 			while(start < end) {
 				srmmu_flush_tlb_segment(start);
@@ -1552,6 +1610,14 @@
 {
 }
 
+/* Cypress has unified L2 VIPT, from which both instructions and data
+ * are stored.  It does not have an onboard icache of any sort, therefore
+ * no flush is necessary.
+ */
+static void cypress_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
+{
+}
+
 static void cypress_flush_page_to_uncache(unsigned long page)
 {
 	register unsigned long a, b, c, d, e, f, g;
@@ -1579,6 +1645,63 @@
 	} while(line != page);
 }
 
+static unsigned long cypress_getpage(void)
+{
+	register unsigned long a, b, c, d, e, f, g;
+	unsigned long page = get_free_page(GFP_KERNEL);
+	unsigned long line;
+
+	a = 0x20; b = 0x40; c = 0x60; d = 0x80; e = 0xa0; f = 0xc0; g = 0xe0;
+	page &= PAGE_MASK;
+	line = (page + PAGE_SIZE) - 0x100;
+	goto inside;
+	do {
+		line -= 0x100;
+	inside:
+		__asm__ __volatile__("sta %%g0, [%0] %1\n\t"
+				     "sta %%g0, [%0 + %2] %1\n\t"
+				     "sta %%g0, [%0 + %3] %1\n\t"
+				     "sta %%g0, [%0 + %4] %1\n\t"
+				     "sta %%g0, [%0 + %5] %1\n\t"
+				     "sta %%g0, [%0 + %6] %1\n\t"
+				     "sta %%g0, [%0 + %7] %1\n\t"
+				     "sta %%g0, [%0 + %8] %1\n\t" : :
+				     "r" (line),
+				     "i" (ASI_M_FLUSH_PAGE),
+				     "r" (a), "r" (b), "r" (c), "r" (d),
+				     "r" (e), "r" (f), "r" (g));
+	} while(line != page);
+	return page;
+}
+
+static void cypress_pgd_flush(pgd_t *pgdp)
+{
+	register unsigned long a, b, c, d, e, f, g;
+	unsigned long page = ((unsigned long) pgdp) & PAGE_MASK;
+	unsigned long line;
+
+	a = 0x20; b = 0x40; c = 0x60; d = 0x80; e = 0xa0; f = 0xc0; g = 0xe0;
+	page &= PAGE_MASK;
+	line = (page + PAGE_SIZE) - 0x100;
+	goto inside;
+	do {
+		line -= 0x100;
+	inside:
+		__asm__ __volatile__("sta %%g0, [%0] %1\n\t"
+				     "sta %%g0, [%0 + %2] %1\n\t"
+				     "sta %%g0, [%0 + %3] %1\n\t"
+				     "sta %%g0, [%0 + %4] %1\n\t"
+				     "sta %%g0, [%0 + %5] %1\n\t"
+				     "sta %%g0, [%0 + %6] %1\n\t"
+				     "sta %%g0, [%0 + %7] %1\n\t"
+				     "sta %%g0, [%0 + %8] %1\n\t" : :
+				     "r" (line),
+				     "i" (ASI_M_FLUSH_PAGE),
+				     "r" (a), "r" (b), "r" (c), "r" (d),
+				     "r" (e), "r" (f), "r" (g));
+	} while(line != page);
+}
+
 static void cypress_flush_tlb_all(void)
 {
 	module_stats.invall++;
@@ -1613,13 +1736,13 @@
 		flush_user_windows();
 		octx = srmmu_get_context();
 		srmmu_set_context(mm->context);
-		if((start - end) < SRMMU_PMD_SIZE) {
+		if((end - start) < SRMMU_PMD_SIZE) {
 			start &= PAGE_MASK;
 			while(start < end) {
 				srmmu_flush_tlb_page(start);
 				start += PAGE_SIZE;
 			}
-		} else if((start - end) < SRMMU_PGDIR_SIZE) {
+		} else if((end - start) < SRMMU_PGDIR_SIZE) {
 			start &= SRMMU_PMD_MASK;
 			while(start < end) {
 				srmmu_flush_tlb_segment(start);
@@ -1751,6 +1874,14 @@
 {
 }
 
+/* HyperSparc has unified I/D L2 cache, however it posseses a small on-chip
+ * ICACHE which must be flushed for the new style signals.
+ */
+static void hypersparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
+{
+	hyper_flush_whole_icache();
+}
+
 static void hypersparc_flush_cache_page_to_uncache(unsigned long page)
 {
 	volatile unsigned long clear;
@@ -1760,6 +1891,34 @@
 	clear = srmmu_get_fstatus();
 }
 
+static unsigned long hypersparc_getpage(void)
+{
+	volatile unsigned long clear;
+	unsigned long page = get_free_page(GFP_KERNEL);
+	unsigned long flags;
+
+	save_and_cli(flags);
+	if(srmmu_hwprobe(page))
+		hyper_flush_cache_page(page);
+	clear = srmmu_get_fstatus();
+	restore_flags(flags);
+
+	return page;
+}
+
+static void hypersparc_pgd_flush(pgd_t *pgdp)
+{
+	volatile unsigned long clear;
+	unsigned long page = ((unsigned long) pgdp) & PAGE_MASK;
+	unsigned long flags;
+
+	save_and_cli(flags);
+	if(srmmu_hwprobe(page))
+		hyper_flush_cache_page(page);
+	clear = srmmu_get_fstatus();
+	restore_flags(flags);
+}
+
 static void hypersparc_flush_tlb_all(void)
 {
 	module_stats.invall++;
@@ -1796,13 +1955,13 @@
 
 		octx = srmmu_get_context();
 		srmmu_set_context(mm->context);
-		if((start - end) < SRMMU_PMD_SIZE) {
+		if((end - start) < SRMMU_PMD_SIZE) {
 			start &= PAGE_MASK;
 			while(start < end) {
 				srmmu_flush_tlb_page(start);
 				start += PAGE_SIZE;
 			}
-		} else if((start - end) < SRMMU_PGDIR_SIZE) {
+		} else if((end - start) < SRMMU_PGDIR_SIZE) {
 			start &= SRMMU_PMD_MASK;
 			while(start < end) {
 				srmmu_flush_tlb_segment(start);
@@ -1955,6 +2114,8 @@
 
 	/* Initialize new table. */
 	flush_cache_all();
+	memset(iommu->page_table, 0, ptsize);
+	srmmu_map_dvma_pages_for_iommu(iommu, memory_end);
 	if(viking_mxcc_present) {
 		unsigned long start = (unsigned long) iommu->page_table;
 		unsigned long end = (start + ptsize);
@@ -1970,8 +2131,6 @@
 			start += PAGE_SIZE;
 		}
 	}
-	memset(iommu->page_table, 0, ptsize);
-	srmmu_map_dvma_pages_for_iommu(iommu, memory_end);
 	flush_tlb_all();
 	iommu->regs->base = srmmu_v2p((unsigned long) iommu->page_table) >> 4;
 	iommu_invalidate(iommu->regs);
@@ -1997,6 +2156,7 @@
 
 	/* Initialize new table. */
 	flush_cache_all();
+	memset(iommu, 0, 16 * PAGE_SIZE);
 	if(viking_mxcc_present) {
 		unsigned long start = (unsigned long) iommu;
 		unsigned long end = (start + 16 * PAGE_SIZE);
@@ -2012,7 +2172,6 @@
 			start += PAGE_SIZE;
 		}
 	}
-	memset(iommu, 0, 16 * PAGE_SIZE);
 	flush_tlb_all();
 
 	sbus->iommu = (struct iommu_struct *)iommu;
@@ -2568,6 +2727,7 @@
 	}
 	MKTRACE(("success\n"));
 	init_task.mm->mmap->vm_start = page_offset = low_base;
+	stack_top = page_offset - PAGE_SIZE;
 	return; /* SUCCESS! */
 }
 
@@ -2747,46 +2907,65 @@
 static void srmmu_vac_update_mmu_cache(struct vm_area_struct * vma,
 				       unsigned long address, pte_t pte)
 {
-#if 0
-	struct inode *inode;
-	struct vm_area_struct *vmaring;
 	unsigned long offset, vaddr;
 	unsigned long start;
 	pgd_t *pgdp;
 	pmd_t *pmdp;
 	pte_t *ptep;
 
-	if (!(vma->vm_flags & VM_WRITE) ||
-	    !(vma->vm_flags & VM_SHARED))
-		return;
-
-	inode = vma->vm_inode;
-	if (!inode)
-		return;
+	if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) {
+		struct vm_area_struct *vmaring;
+		struct inode *inode;
+		unsigned long flags;
+		int alias_found = 0;
 
-	offset = (address & PAGE_MASK) - vma->vm_start;
-	vmaring = inode->i_mmap; 
-	do {
-		vaddr = vmaring->vm_start + offset;
+		save_and_cli(flags);
 
-		if ((vaddr ^ address) & vac_badbits) {
-			start = vma->vm_start;
-			while (start < vma->vm_end) {
-				pgdp = srmmu_pgd_offset(vma->vm_mm, start);
-				pmdp = srmmu_pmd_offset(pgdp, start);
-				ptep = srmmu_pte_offset(pmdp, start);
-
-				flush_cache_page_to_uncache(start);
-				set_pte(ptep, __pte((pte_val(*ptep) &
-					      ~SRMMU_CACHE)));
-				flush_tlb_page_for_cbit(start);
+		inode = vma->vm_inode;
+		if (!inode)
+			goto done;
+		offset = (address & PAGE_MASK) - vma->vm_start;
+		vmaring = inode->i_mmap; 
+		do {
+			vaddr = vmaring->vm_start + offset;
 
-				start += PAGE_SIZE;
+			if ((vaddr ^ address) & vac_badbits) {
+				alias_found++;
+				start = vmaring->vm_start;
+				while (start < vmaring->vm_end) {
+					pgdp = srmmu_pgd_offset(vmaring->vm_mm, start);
+					if(!pgdp) goto next;
+					pmdp = srmmu_pmd_offset(pgdp, start);
+					if(!pmdp) goto next;
+					ptep = srmmu_pte_offset(pmdp, start);
+					if(!ptep) goto next;
+
+					if((pte_val(*ptep) & SRMMU_ET_MASK) == SRMMU_VALID) {
+#if 1
+						printk("Fixing USER/USER alias [%d:%08lx]\n",
+						       vmaring->vm_mm->context, start);
+#endif
+						flush_cache_page(vmaring, start);
+						set_pte(ptep, __pte((pte_val(*ptep) &
+								     ~SRMMU_CACHE)));
+						flush_tlb_page(vmaring, start);
+					}
+				next:
+					start += PAGE_SIZE;
+				}
 			}
-			return;
+		} while ((vmaring = vmaring->vm_next_share) != inode->i_mmap);
+
+		if(alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
+			pgdp = srmmu_pgd_offset(vma->vm_mm, address);
+			ptep = srmmu_pte_offset((pmd_t *) pgdp, address);
+			flush_cache_page(vma, address);
+			pte_val(*ptep) = (pte_val(*ptep) | _SUN4C_PAGE_NOCACHE);
+			flush_tlb_page(vma, address);
 		}
-	} while ((vmaring = vmaring->vm_next_share) != inode->i_mmap);
-#endif
+	done:
+		restore_flags(flags);
+	}
 }
 
 static void hypersparc_exit_hook(void)
@@ -2819,40 +2998,64 @@
 }
 
 /* Init various srmmu chip types. */
-static void srmmu_is_bad(void)
+__initfunc(static void srmmu_is_bad(void))
 {
 	prom_printf("Could not determine SRMMU chip type.\n");
 	prom_halt();
 }
 
-static void init_vac_layout(void)
+__initfunc(static void init_vac_layout(void))
 {
 	int nd, cache_lines;
 	char node_str[128];
+#ifdef __SMP__
+	int cpu = 0;
+	unsigned long max_size = 0;
+	unsigned long min_line_size = 0x10000000;
+#endif
 
 	nd = prom_getchild(prom_root_node);
 	while((nd = prom_getsibling(nd)) != 0) {
 		prom_getstring(nd, "device_type", node_str, sizeof(node_str));
-		if(!strcmp(node_str, "cpu"))
+		if(!strcmp(node_str, "cpu")) {
+			vac_line_size = prom_getint(nd, "cache-line-size");
+			if (vac_line_size == -1) {
+				prom_printf("can't determine cache-line-size, "
+					    "halting.\n");
+				prom_halt();
+			}
+			cache_lines = prom_getint(nd, "cache-nlines");
+			if (cache_lines == -1) {
+				prom_printf("can't determine cache-nlines, halting.\n");
+				prom_halt();
+			}
+
+			vac_cache_size = cache_lines * vac_line_size;
+			vac_badbits = (vac_cache_size - 1) & PAGE_MASK;
+#ifdef __SMP__
+			if(vac_cache_size > max_size)
+				max_size = vac_cache_size;
+			if(vac_line_size < min_line_size)
+				min_line_size = vac_line_size;
+			cpu++;
+			if(cpu == smp_num_cpus)
+				break;
+#else
 			break;
+#endif
+		}
 	}
 	if(nd == 0) {
 		prom_printf("No CPU nodes found, halting.\n");
 		prom_halt();
 	}
-
-	vac_line_size = prom_getint(nd, "cache-line-size");
-	if (vac_line_size == -1) {
-		prom_printf("can't determine cache-line-size, halting.\n");
-		prom_halt();
-	}
-	cache_lines = prom_getint(nd, "cache-nlines");
-	if (cache_lines == -1) {
-		prom_printf("can't determine cache-nlines, halting.\n");
-		prom_halt();
-	}
-	vac_cache_size = cache_lines * vac_line_size;
+#ifdef __SMP__
+	vac_cache_size = max_size;
+	vac_line_size = min_line_size;
 	vac_badbits = (vac_cache_size - 1) & PAGE_MASK;
+#endif
+	printk("SRMMU: Using VAC size of %d bytes, line size %d bytes.\n",
+	       (int)vac_cache_size, (int)vac_line_size);
 }
 
 static void poke_hypersparc(void)
@@ -2875,13 +3078,14 @@
 	clear = srmmu_get_fstatus();
 }
 
-static void init_hypersparc(void)
+__initfunc(static void init_hypersparc(void))
 {
 	srmmu_name = "ROSS HyperSparc";
 
 	init_vac_layout();
 
 	set_pte = srmmu_set_pte_nocache_hyper;
+	mmu_getpage = hypersparc_getpage;
 	flush_cache_all = hypersparc_flush_cache_all;
 	flush_cache_mm = hypersparc_flush_cache_mm;
 	flush_cache_range = hypersparc_flush_cache_range;
@@ -2893,9 +3097,11 @@
 	flush_tlb_page = hypersparc_flush_tlb_page;
 
 	flush_page_to_ram = hypersparc_flush_page_to_ram;
+	flush_sig_insns = hypersparc_flush_sig_insns;
 	flush_page_for_dma = hypersparc_flush_page_for_dma;
 	flush_cache_page_to_uncache = hypersparc_flush_cache_page_to_uncache;
 	flush_tlb_page_for_cbit = hypersparc_flush_tlb_page_for_cbit;
+	pgd_flush = hypersparc_pgd_flush;
 
 	ctxd_set = hypersparc_ctxd_set;
 	switch_to_context = hypersparc_switch_to_context;
@@ -2930,11 +3136,12 @@
 	srmmu_set_mmureg(mreg);
 }
 
-static void init_cypress_common(void)
+__initfunc(static void init_cypress_common(void))
 {
 	init_vac_layout();
 
 	set_pte = srmmu_set_pte_nocache_cypress;
+	mmu_getpage = cypress_getpage;
 	flush_cache_all = cypress_flush_cache_all;
 	flush_cache_mm = cypress_flush_cache_mm;
 	flush_cache_range = cypress_flush_cache_range;
@@ -2946,22 +3153,24 @@
 	flush_tlb_range = cypress_flush_tlb_range;
 
 	flush_page_to_ram = cypress_flush_page_to_ram;
+	flush_sig_insns = cypress_flush_sig_insns;
 	flush_page_for_dma = cypress_flush_page_for_dma;
 	flush_cache_page_to_uncache = cypress_flush_page_to_uncache;
 	flush_tlb_page_for_cbit = cypress_flush_tlb_page_for_cbit;
+	pgd_flush = cypress_pgd_flush;
 
 	update_mmu_cache = srmmu_vac_update_mmu_cache;
 	poke_srmmu = poke_cypress;
 }
 
-static void init_cypress_604(void)
+__initfunc(static void init_cypress_604(void))
 {
 	srmmu_name = "ROSS Cypress-604(UP)";
 	srmmu_modtype = Cypress;
 	init_cypress_common();
 }
 
-static void init_cypress_605(unsigned long mrev)
+__initfunc(static void init_cypress_605(unsigned long mrev))
 {
 	srmmu_name = "ROSS Cypress-605(MP)";
 	if(mrev == 0xe) {
@@ -2999,7 +3208,7 @@
 }
 
 #define SWIFT_MASKID_ADDR  0x10003018
-static void init_swift(void)
+__initfunc(static void init_swift(void))
 {
 	unsigned long swift_rev;
 
@@ -3057,6 +3266,7 @@
 	flush_tlb_range = swift_flush_tlb_range;
 
 	flush_page_to_ram = swift_flush_page_to_ram;
+	flush_sig_insns = swift_flush_sig_insns;
 	flush_page_for_dma = swift_flush_page_for_dma;
 	flush_cache_page_to_uncache = swift_flush_cache_page_to_uncache;
 	flush_tlb_page_for_cbit = swift_flush_tlb_page_for_cbit;
@@ -3081,7 +3291,7 @@
 	srmmu_set_mmureg(mreg);
 }
 
-static void init_tsunami(void)
+__initfunc(static void init_tsunami(void))
 {
 	/* Tsunami's pretty sane, Sun and TI actually got it
 	 * somewhat right this time.  Fujitsu should have
@@ -3102,6 +3312,7 @@
 	flush_tlb_range = tsunami_flush_tlb_range;
 
 	flush_page_to_ram = tsunami_flush_page_to_ram;
+	flush_sig_insns = tsunami_flush_sig_insns;
 	flush_page_for_dma = tsunami_flush_page_for_dma;
 	flush_cache_page_to_uncache = tsunami_flush_cache_page_to_uncache;
 	flush_tlb_page_for_cbit = tsunami_flush_tlb_page_for_cbit;
@@ -3154,11 +3365,11 @@
 #endif
 	srmmu_set_mmureg(mreg);
 
-
 #ifdef __SMP__
 	/* Avoid unnecessary cross calls. */
 	flush_cache_all = local_flush_cache_all;
 	flush_page_to_ram = local_flush_page_to_ram;
+	flush_sig_insns = local_flush_sig_insns;
 	flush_page_for_dma = local_flush_page_for_dma;
 	if (viking_mxcc_present) {
 		flush_cache_page_to_uncache = local_flush_cache_page_to_uncache;
@@ -3166,7 +3377,7 @@
 #endif
 }
 
-static void init_viking(void)
+__initfunc(static void init_viking(void))
 {
 	unsigned long mreg = srmmu_get_mmureg();
 
@@ -3177,7 +3388,6 @@
 
 		srmmu_name = "TI Viking";
 		viking_mxcc_present = 0;
-		set_pte = srmmu_set_pte_nocache_nomxccvik;
 
 		bpreg = viking_get_bpreg();
 		bpreg &= ~(VIKING_ACTION_MIX);
@@ -3185,6 +3395,10 @@
 
 		msi_set_sync();
 
+		mmu_getpage = viking_no_mxcc_getpage;
+		set_pte = srmmu_set_pte_nocache_nomxccvik;
+		pgd_flush = viking_no_mxcc_pgd_flush;
+
 		flush_cache_page_to_uncache = viking_no_mxcc_flush_page;
 
 		/* We need this to make sure old viking takes no hits
@@ -3214,13 +3428,14 @@
 	flush_tlb_range = viking_flush_tlb_range;
 
 	flush_page_to_ram = viking_flush_page_to_ram;
+	flush_sig_insns = viking_flush_sig_insns;
 	flush_tlb_page_for_cbit = viking_flush_tlb_page_for_cbit;
 
 	poke_srmmu = poke_viking;
 }
 
 /* Probe for the srmmu chip version. */
-static void get_srmmu_type(void)
+__initfunc(static void get_srmmu_type(void))
 {
 	unsigned long mreg, psr;
 	unsigned long mod_typ, mod_rev, psr_typ, psr_vers;
@@ -3245,6 +3460,8 @@
 			/* Uniprocessor Cypress */
 			init_cypress_604();
 			break;
+		case 10:
+		case 11:
 		case 12:
 			/* _REALLY OLD_ Cypress MP chips... */
 		case 13:
@@ -3254,7 +3471,8 @@
 			init_cypress_605(mod_rev);
 			break;
 		default:
-			srmmu_is_bad();
+			/* Some other Cypress revision, assume a 605. */
+			init_cypress_605(mod_rev);
 			break;
 		};
 		return;
@@ -3302,7 +3520,7 @@
 		*iaddr = SPARC_BRANCH((unsigned long) daddr, (unsigned long) iaddr); \
         } while(0);
 
-static void patch_window_trap_handlers(void)
+__initfunc(static void patch_window_trap_handlers(void))
 {
 	unsigned long *iaddr, *daddr;
 	
@@ -3337,7 +3555,7 @@
 #endif
 
 /* Load up routines and constants for sun4m mmu */
-void ld_mmu_srmmu(void)
+__initfunc(void ld_mmu_srmmu(void))
 {
 	/* First the constants */
 	pmd_shift = SRMMU_PMD_SHIFT;
@@ -3359,6 +3577,7 @@
 	pg_iobits = SRMMU_VALID | SRMMU_WRITE | SRMMU_REF;
 	    
 	/* Functions */
+	mmu_getpage = srmmu_getpage;
 	set_pte = srmmu_set_pte_cacheable;
 	switch_to_context = srmmu_switch_to_context;
 	pmd_align = srmmu_pmd_align;
@@ -3403,6 +3622,7 @@
 	pmd_alloc = srmmu_pmd_alloc;
 	pgd_free = srmmu_pgd_free;
 	pgd_alloc = srmmu_pgd_alloc;
+	pgd_flush = srmmu_pgd_flush;
 
 	pte_write = srmmu_pte_write;
 	pte_dirty = srmmu_pte_dirty;
@@ -3457,6 +3677,7 @@
 	local_flush_tlb_range = flush_tlb_range;
 	local_flush_tlb_page = flush_tlb_page;
 	local_flush_page_to_ram = flush_page_to_ram;
+	local_flush_sig_insns = flush_sig_insns;
 	local_flush_page_for_dma = flush_page_for_dma;
 	local_flush_cache_page_to_uncache = flush_cache_page_to_uncache;
 	local_flush_tlb_page_for_cbit = flush_tlb_page_for_cbit;
@@ -3470,6 +3691,7 @@
 	flush_tlb_range = smp_flush_tlb_range;
 	flush_tlb_page = smp_flush_tlb_page;
 	flush_page_to_ram = smp_flush_page_to_ram;
+	flush_sig_insns = smp_flush_sig_insns;
 	flush_page_for_dma = smp_flush_page_for_dma;
 	flush_cache_page_to_uncache = smp_flush_cache_page_to_uncache;
 	flush_tlb_page_for_cbit = smp_flush_tlb_page_for_cbit;
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/mm/sun4c.c linux/arch/sparc/mm/sun4c.c
--- v2.1.15/linux/arch/sparc/mm/sun4c.c	Tue Nov 12 15:56:04 1996
+++ linux/arch/sparc/mm/sun4c.c	Fri Dec 13 11:37:32 1996
@@ -1,4 +1,4 @@
-/* $Id: sun4c.c,v 1.121 1996/11/01 20:36:27 ecd Exp $
+/* $Id: sun4c.c,v 1.132 1996/12/10 06:06:27 davem Exp $
  * sun4c.c: Doing in software what should be done in hardware.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -8,6 +8,7 @@
 
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/init.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -23,19 +24,7 @@
 
 extern int num_segmaps, num_contexts;
 
-/* Small structure for ease of handling in the low level kernel fault
- * handler. This holds all information necessary, like the sun4c_ufree_ring
- * for user segments.
- */
-struct sun4c_segment_info {
-	unsigned long vaddr;
-	unsigned char pseg;
-};
-struct sun4c_segment_info *sun4c_kernel_next;
-
 #define SUN4C_KERNEL_BUCKETS 32
-#define SUN4C_KERNEL_BSIZE (sizeof(struct sun4c_segment_info) \
-			    * SUN4C_KERNEL_BUCKETS)
 
 #ifndef MAX
 #define MAX(a,b) ((a)<(b)?(b):(a))
@@ -45,7 +34,6 @@
 #endif
 
 
-
 #define KGPROF_PROFILING 0
 #if KGPROF_PROFILING
 #define KGPROF_DEPTH 3 /* this needs to match the code below */
@@ -85,6 +73,7 @@
 /* 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 */
@@ -121,39 +110,61 @@
 /* Blow the entire current context out of the virtual cache. */
 static inline void sun4c_flush_context(void)
 {
-	unsigned long vaddr;
+	extern unsigned long bcopy;
+	unsigned long begin, end, flags;
 
 	ctxflushes++;
-	if(sun4c_vacinfo.do_hwflushes) {
-		for(vaddr=0; vaddr < sun4c_vacinfo.num_bytes; vaddr+=PAGE_SIZE)
-			__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
-					     "r" (vaddr), "i" (ASI_HWFLUSHCONTEXT));
+
+	begin = ((unsigned long) &bcopy);
+	end = (begin + sun4c_vacinfo.num_bytes);
+
+	save_and_cli(flags);
+	if(sun4c_vacinfo.linesize == 32) {
+		while(begin < end) {
+			__asm__ __volatile__("
+			ld	[%0 + 0x00], %%g0
+			ld	[%0 + 0x20], %%g0
+			ld	[%0 + 0x40], %%g0
+			ld	[%0 + 0x60], %%g0
+			ld	[%0 + 0x80], %%g0
+			ld	[%0 + 0xa0], %%g0
+			ld	[%0 + 0xc0], %%g0
+			ld	[%0 + 0xe0], %%g0
+			ld	[%0 + 0x100], %%g0
+			ld	[%0 + 0x120], %%g0
+			ld	[%0 + 0x140], %%g0
+			ld	[%0 + 0x160], %%g0
+			ld	[%0 + 0x180], %%g0
+			ld	[%0 + 0x1a0], %%g0
+			ld	[%0 + 0x1c0], %%g0
+			ld	[%0 + 0x1e0], %%g0
+			" : : "r" (begin));
+			begin += 512;
+		}
 	} else {
-		/* AJT: possibly read the tags and avoid flushing the ones that 
-		   are above 0xf0000000 so the kernel isn't flushed all the time */
-		__asm__ __volatile__("add	%1, %1, %%g1\n\t"
-				     "add	%1, %%g1, %%g2\n\t"
-				     "add	%1, %%g2, %%g3\n\t"
-				     "add	%1, %%g3, %%g4\n\t"
-				     "add	%1, %%g4, %%g5\n\t"
-				     "add	%1, %%g5, %%o4\n\t"
-				     "add	%1, %%o4, %%o5\n"
-				     "1:\n\t"
-				     "subcc	%0, %%o5, %0\n\t"
-				     "sta	%%g0, [%0] %2\n\t"
-				     "sta	%%g0, [%0 + %1] %2\n\t"
-				     "sta	%%g0, [%0 + %%g1] %2\n\t"
-				     "sta	%%g0, [%0 + %%g2] %2\n\t"
-				     "sta	%%g0, [%0 + %%g3] %2\n\t"
-				     "sta	%%g0, [%0 + %%g4] %2\n\t"
-				     "sta	%%g0, [%0 + %%g5] %2\n\t"
-				     "bg	1b\n\t"
-				     " sta	%%g0, [%0 + %%o4] %2\n\t" : :
-				     "r" (sun4c_vacinfo.num_bytes),
-				     "r" (sun4c_vacinfo.linesize),
-				     "i" (ASI_FLUSHCTX) :
-				     "g1", "g2", "g3", "g4", "g5", "o4", "o5");
+		while(begin < end) {
+			__asm__ __volatile__("
+			ld	[%0 + 0x00], %%g0
+			ld	[%0 + 0x10], %%g0
+			ld	[%0 + 0x20], %%g0
+			ld	[%0 + 0x30], %%g0
+			ld	[%0 + 0x40], %%g0
+			ld	[%0 + 0x50], %%g0
+			ld	[%0 + 0x60], %%g0
+			ld	[%0 + 0x70], %%g0
+			ld	[%0 + 0x80], %%g0
+			ld	[%0 + 0x90], %%g0
+			ld	[%0 + 0xa0], %%g0
+			ld	[%0 + 0xb0], %%g0
+			ld	[%0 + 0xc0], %%g0
+			ld	[%0 + 0xd0], %%g0
+			ld	[%0 + 0xe0], %%g0
+			ld	[%0 + 0xf0], %%g0
+			" : : "r" (begin));
+			begin += 256;
+		}
 	}
+	restore_flags(flags);
 }
 
 /* Scrape the segment starting at ADDR from the virtual cache. */
@@ -161,6 +172,10 @@
 {
 	segflushes++;
 	addr &= SUN4C_REAL_PGDIR_MASK;
+
+	if(sun4c_get_segmap(addr) == invalid_segment)
+		return;
+
 	if(sun4c_vacinfo.do_hwflushes) {
 		unsigned long end = (addr + sun4c_vacinfo.num_bytes);
 
@@ -168,6 +183,9 @@
 			__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
 					     "r" (addr), "i" (ASI_HWFLUSHSEG));
 	} else {
+		unsigned long nbytes = sun4c_vacinfo.num_bytes;
+		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"
@@ -177,20 +195,20 @@
 				     "add	%2, %%o4, %%o5\n"
 				     "1:\n\t"
 				     "subcc	%1, %%o5, %1\n\t"
-				     "sta	%%g0, [%0] %3\n\t"
-				     "sta	%%g0, [%0 + %2] %3\n\t"
-				     "sta	%%g0, [%0 + %%g1] %3\n\t"
-				     "sta	%%g0, [%0 + %%g2] %3\n\t"
-				     "sta	%%g0, [%0 + %%g3] %3\n\t"
-				     "sta	%%g0, [%0 + %%g4] %3\n\t"
-				     "sta	%%g0, [%0 + %%g5] %3\n\t"
-				     "sta	%%g0, [%0 + %%o4] %3\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" (sun4c_vacinfo.num_bytes),
-				     "r" (sun4c_vacinfo.linesize),
-				     "i" (ASI_FLUSHSEG) :
-				     "g1", "g2", "g3", "g4", "g5", "o4", "o5");
+				     " 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");
 	}
 }
 
@@ -199,11 +217,18 @@
 {
 	addr &= PAGE_MASK;
 
+	if((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) !=
+	   _SUN4C_PAGE_VALID)
+		return;
+
 	pageflushes++;
 	if(sun4c_vacinfo.do_hwflushes) {
 		__asm__ __volatile__("sta %%g0, [%0] %1\n\t" : :
 				     "r" (addr), "i" (ASI_HWFLUSHPAGE));
 	} else {
+		unsigned long left = PAGE_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"
@@ -213,20 +238,20 @@
 				     "add	%2, %%o4, %%o5\n"
 				     "1:\n\t"
 				     "subcc	%1, %%o5, %1\n\t"
-				     "sta	%%g0, [%0] %3\n\t"
-				     "sta	%%g0, [%0 + %2] %3\n\t"
-				     "sta	%%g0, [%0 + %%g1] %3\n\t"
-				     "sta	%%g0, [%0 + %%g2] %3\n\t"
-				     "sta	%%g0, [%0 + %%g3] %3\n\t"
-				     "sta	%%g0, [%0 + %%g4] %3\n\t"
-				     "sta	%%g0, [%0 + %%g5] %3\n\t"
-				     "sta	%%g0, [%0 + %%o4] %3\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" (PAGE_SIZE),
-				     "r" (sun4c_vacinfo.linesize),
-				     "i" (ASI_FLUSHPG) :
-				     "g1", "g2", "g3", "g4", "g5", "o4", "o5");
+				     " add	%0, %%o5, %0\n\t"
+				     : "=&r" (addr), "=&r" (left), "=&r" (lsize)
+				     : "0" (addr), "1" (left), "2" (lsize),
+				       "i" (ASI_FLUSHPG)
+				     : "g1", "g2", "g3", "g4", "g5", "o4", "o5");
 	}
 }
 
@@ -280,10 +305,19 @@
 void sun4c_probe_vac(void)
 {
 	sun4c_disable_vac();
-	sun4c_vacinfo.num_bytes = prom_getintdefault(prom_root_node,
-						     "vac-size", 65536);
-	sun4c_vacinfo.linesize = prom_getintdefault(prom_root_node,
-						    "vac-linesize", 16);
+	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.
+		 */
+		sun4c_vacinfo.num_bytes = 65536;
+		sun4c_vacinfo.linesize = 16;
+	} else {
+		sun4c_vacinfo.num_bytes = prom_getintdefault(prom_root_node,
+							     "vac-size", 65536);
+		sun4c_vacinfo.linesize = prom_getintdefault(prom_root_node,
+							    "vac-linesize", 16);
+	}
 	sun4c_vacinfo.num_lines =
 		(sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize);
 	switch(sun4c_vacinfo.linesize) {
@@ -299,12 +333,11 @@
 		prom_halt();
 	};
 
-	/* Only vac-hwflush (with a dash) is reliable, weitek
-	 * power-up processor claims vac_hwflush (underscore)
-	 * yet crashes if you try to use hardware based flushes.
-	 */
 	sun4c_vacinfo.do_hwflushes = prom_getintdefault(prom_root_node,
 							"vac-hwflush", 0);
+	if(sun4c_vacinfo.do_hwflushes == 0)
+		sun4c_vacinfo.do_hwflushes = prom_getintdefault(prom_root_node,
+								"vac_hwflush", 0);
 
 	if(sun4c_vacinfo.num_bytes != 65536) {
 		prom_printf("WEIRD Sun4C VAC cache size, tell davem");
@@ -320,8 +353,9 @@
 extern unsigned long invalid_segment_patch2, invalid_segment_patch2_ff;
 extern unsigned long num_context_patch1, num_context_patch1_16;
 extern unsigned long num_context_patch2, num_context_patch2_16;
-extern unsigned long sun4c_kernel_buckets_patch;
-extern unsigned long sun4c_kernel_buckets_patch_32;
+extern unsigned long vac_linesize_patch, vac_linesize_patch_32;
+extern unsigned long vac_hwflush_patch1, vac_hwflush_patch1_on;
+extern unsigned long vac_hwflush_patch2, vac_hwflush_patch2_on;
 
 #define PATCH_INSN(src, dst) do {	\
 		daddr = &(dst);		\
@@ -363,25 +397,38 @@
 				    num_contexts);
 			prom_halt();
 	}
-	switch (SUN4C_KERNEL_BUCKETS) {
+	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) {
 		case 16:
 			/* Default, nothing to do. */
 			break;
 		case 32:
-			PATCH_INSN(sun4c_kernel_buckets_patch_32,
-				   sun4c_kernel_buckets_patch);
+			PATCH_INSN(vac_linesize_patch_32, vac_linesize_patch);
 			break;
 		default:
-			prom_printf("Unhandled number of kernel buckets: %d\n",
-				    SUN4C_KERNEL_BUCKETS);
+			prom_printf("Impossible VAC linesize %d, halting...\n",
+				    sun4c_vacinfo.linesize);
 			prom_halt();
+		};
 	}
 }
 
 static void sun4c_probe_mmu(void)
 {
-	num_segmaps = prom_getintdefault(prom_root_node, "mmu-npmg", 128);
-	num_contexts = prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
+	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.
+		 */
+		num_segmaps = 128;
+		num_contexts = 8;
+	} else {
+		num_segmaps = prom_getintdefault(prom_root_node, "mmu-npmg", 128);
+		num_contexts = prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
+	}
 	patch_kernel_fault_handler();
 }
 
@@ -408,7 +455,8 @@
 	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_SUN4C | SM_4C_IPX)) ||
+	   (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);
@@ -432,7 +480,8 @@
 		sun4c_flush_page(page);
 		page -= PAGE_OFFSET;
 		page >>= PAGE_SHIFT;
-		page |= (_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_NOCACHE);
+		page |= (_SUN4C_PAGE_VALID | _SUN4C_PAGE_DIRTY |
+			 _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_PRIV);
 		sun4c_put_pte(addr, page);
 		addr += PAGE_SIZE;
 	}
@@ -440,6 +489,11 @@
 
 
 /* TLB management. */
+
+/* Don't change this struct without changing entry.S. This is used
+ * in the in-window kernel fault handler, and you don't want to mess
+ * with that. (See sun4c_fault in entry.S).
+ */
 struct sun4c_mmu_entry {
 	struct sun4c_mmu_entry *next;
 	struct sun4c_mmu_entry *prev;
@@ -449,7 +503,7 @@
 };
 static struct sun4c_mmu_entry mmu_entry_pool[256];
 
-static void sun4c_init_mmu_entry_pool(void)
+__initfunc(static void sun4c_init_mmu_entry_pool(void))
 {
 	int i;
 
@@ -500,7 +554,7 @@
 	}
 }
 
-static void sun4c_init_lock_area(unsigned long start, unsigned long end)
+__initfunc(static void sun4c_init_lock_area(unsigned long start, unsigned long end))
 {
 	int i, ctx;
 
@@ -516,19 +570,18 @@
 	}
 }
 
+/* Don't change this struct without changing entry.S. This is used
+ * in the in-window kernel fault handler, and you don't want to mess
+ * with that. (See sun4c_fault in entry.S).
+ */
 struct sun4c_mmu_ring {
 	struct sun4c_mmu_entry ringhd;
 	int num_entries;
 };
 static struct sun4c_mmu_ring sun4c_context_ring[16]; /* used user entries */
 static struct sun4c_mmu_ring sun4c_ufree_ring;       /* free user entries */
-
-static inline void sun4c_next_kernel_bucket(struct sun4c_segment_info **next)
-{
-	(*next)++;
-	*next = (struct sun4c_segment_info *)
-			((unsigned long)*next & ~SUN4C_KERNEL_BSIZE);
-}
+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)
 {
@@ -542,11 +595,16 @@
 	sun4c_ufree_ring.ringhd.next = sun4c_ufree_ring.ringhd.prev =
 		&sun4c_ufree_ring.ringhd;
 	sun4c_ufree_ring.num_entries = 0;
-	/* This needs to be aligned to twice it's size for speed. */
-	sun4c_kernel_next = sparc_init_alloc(mempool, 2 * SUN4C_KERNEL_BSIZE);
+	sun4c_kernel_ring.ringhd.next = sun4c_kernel_ring.ringhd.prev =
+		&sun4c_kernel_ring.ringhd;
+	sun4c_kernel_ring.num_entries = 0;
+	sun4c_kfree_ring.ringhd.next = sun4c_kfree_ring.ringhd.prev =
+		&sun4c_kfree_ring.ringhd;
+	sun4c_kfree_ring.num_entries = 0;
 }
 
-static inline void add_ring(struct sun4c_mmu_ring *ring, struct sun4c_mmu_entry *entry)
+static inline void add_ring(struct sun4c_mmu_ring *ring,
+			    struct sun4c_mmu_entry *entry)
 {
 	struct sun4c_mmu_entry *head = &ring->ringhd;
 
@@ -556,7 +614,8 @@
 	ring->num_entries++;
 }
 
-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;
 
@@ -564,13 +623,15 @@
 	ring->num_entries--;
 }
 
-static inline void recycle_ring(struct sun4c_mmu_ring *ring, struct sun4c_mmu_entry *entry)
+static inline void recycle_ring(struct sun4c_mmu_ring *ring,
+			        struct sun4c_mmu_entry *entry)
 {
 	struct sun4c_mmu_entry *head = &ring->ringhd;
 	struct sun4c_mmu_entry *next = entry->next;
 
 	(next->prev = entry->prev)->next = next;
-	entry->prev = head; (entry->next = head->next)->prev = entry;
+	entry->prev = head;
+	(entry->next = head->next)->prev = entry;
 	head->next = entry;
 	/* num_entries stays the same */
 }
@@ -587,7 +648,14 @@
         add_ring(sun4c_context_ring+ctx, entry);
 }
 
-static void sun4c_init_fill_kernel_ring(int howmany)
+static inline void free_kernel_entry(struct sun4c_mmu_entry *entry,
+				     struct sun4c_mmu_ring *ring)
+{
+        remove_ring(ring, entry);
+        add_ring(&sun4c_kfree_ring, entry);
+}
+
+__initfunc(static void sun4c_init_fill_kernel_ring(int howmany))
 {
 	int i;
 
@@ -597,14 +665,12 @@
 				break;
 		mmu_entry_pool[i].locked = 1;
 		sun4c_init_clean_segmap(i);
-		sun4c_kernel_next->vaddr = 0;
-		sun4c_kernel_next->pseg = mmu_entry_pool[i].pseg;
-		sun4c_next_kernel_bucket(&sun4c_kernel_next);
+		add_ring(&sun4c_kfree_ring, &mmu_entry_pool[i]);
 		howmany--;
 	}
 }
 
-static void sun4c_init_fill_user_ring(void)
+__initfunc(static void sun4c_init_fill_user_ring(void))
 {
 	int i;
 
@@ -642,7 +708,6 @@
 
 static inline void sun4c_user_unmap(struct sun4c_mmu_entry *uentry)
 {
-	/* PM: need flush_user_windows() ?? */
 	sun4c_put_segmap(uentry->vaddr, invalid_segment);
 }
 
@@ -661,22 +726,25 @@
 static inline void sun4c_demap_context(struct sun4c_mmu_ring *crp, unsigned char ctx)
 {
 	struct sun4c_mmu_entry *this_entry, *next_entry;
+	unsigned long flags;
 	int savectx = sun4c_get_context();
 
+	save_and_cli(flags);
 	this_entry = crp->ringhd.next;
 	flush_user_windows();
 	sun4c_set_context(ctx);
-	sun4c_flush_context();
 	while(crp->num_entries) {
 		next_entry = this_entry->next;
+		sun4c_flush_segment(this_entry->vaddr);
 		sun4c_user_unmap(this_entry);
 		free_user_entry(ctx, this_entry);
 		this_entry = next_entry;
 	}
 	sun4c_set_context(savectx);
+	restore_flags(flags);
 }
 
-static inline void sun4c_demap_one(struct sun4c_mmu_ring *crp,unsigned char ctx)
+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;
@@ -690,6 +758,51 @@
 	sun4c_set_context(savectx);
 }
 
+static int sun4c_user_taken_entries = 0;
+
+static inline 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) {
+		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);
+	sun4c_kernel_unmap(this_entry);
+	free_kernel_entry(this_entry, &sun4c_kernel_ring);
+	this_entry = sun4c_kfree_ring.ringhd.next;
+
+	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
+	}
+	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.
@@ -704,6 +817,11 @@
 	if(sun4c_ufree_ring.num_entries)
 		return sun4c_ufree_ring.ringhd.next;
 
+	if (sun4c_user_taken_entries) {
+		sun4c_shrink_kernel_ring();
+		return sun4c_ufree_ring.ringhd.next;
+	}
+
 	/* Grab one from the LRU context. */
 	next_one = ctx_used.next;
 	while (sun4c_context_ring[next_one->ctx_number].num_entries == 0)
@@ -712,10 +830,28 @@
 	ctx = next_one->ctx_number;
 	rp = &sun4c_context_ring[ctx];
 
-	sun4c_demap_one(rp,ctx);
+	sun4c_demap_one(rp, ctx);
 	return sun4c_ufree_ring.ringhd.next;
 }
 
+void sun4c_grow_kernel_ring(void)
+{
+	struct sun4c_mmu_entry *entry;
+
+	if (sun4c_ufree_ring.num_entries) {
+		entry = sun4c_ufree_ring.ringhd.next;
+        	remove_ring(&sun4c_ufree_ring, entry);
+		add_ring(&sun4c_kfree_ring, entry);
+		sun4c_user_taken_entries++;
+#if 0
+		printk("grow: 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;
@@ -727,73 +863,11 @@
 	sun4c_user_map(entry);
 }
 
-/* XXX Just like kernel tlb replacement we'd like to have a low level
- * XXX equivalent for user faults which need not go through the mm
- * XXX subsystem just to load a mmu entry.  But this might not be as
- * XXX feasible since we need to go through the kernel page tables
- * XXX for this process, which we currently don't lock into the mmu
- * XXX so we would fault with traps off... must think about this...
- */
-void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
-{
-	unsigned long flags;
-#if 0
-	struct inode *inode;
-	struct vm_area_struct *vmaring;
-	unsigned long offset, vaddr;
-	unsigned long start;
-	pgd_t *pgdp;
-	pmd_t *pmdp;
-	pte_t *ptep;
-#endif
-
-	save_and_cli(flags);
-	address &= PAGE_MASK;
-	if(sun4c_get_segmap(address) == invalid_segment)
-		alloc_user_segment(address, sun4c_get_context());
-	sun4c_put_pte(address, pte_val(pte));
-
-#if 0
-	if (!(vma->vm_flags & VM_WRITE) ||
-	    !(vma->vm_flags & VM_SHARED))
-		goto done;
-
-	inode = vma->vm_inode;
-	if (!inode)
-		goto done;
-
-	offset = (address & PAGE_MASK) - vma->vm_start;
-	vmaring = inode->i_mmap; 
-	do {
-		vaddr = vmaring->vm_start + offset;
-
-		if (S4CVAC_BADALIAS(vaddr, address)) {
-			start = vma->vm_start;
-			while (start < vma->vm_end) {
-				pgdp = pgd_offset(vma->vm_mm, start);
-				pmdp = pmd_offset(pgdp, start);
-				ptep = pte_offset(pmdp, start);
-
-				if (sun4c_get_pte(start) & _SUN4C_PAGE_VALID)
-				sun4c_put_pte(start, sun4c_get_pte(start) |
-						     _SUN4C_PAGE_NOCACHE);
-
-				start += PAGE_SIZE;
-			}
-			goto done;
-		}
-	} while ((vmaring = vmaring->vm_next_share) != inode->i_mmap);
-
-done:
-#endif
-	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)
 {
-        printk("Kernel faults at addr=0x%08lx\n", address);
-        panic("sun4c fault handler bolixed...");
+        printk("Kernel faults at addr 0x%08lx\n", address);
+        panic("sun4c kernel fault handler bolixed...");
 }
 
 /*
@@ -865,26 +939,35 @@
 
 static inline void garbage_collect(int entry)
 {
+	unsigned long flags;
 	int start, end;
 
+	save_and_cli(flags);
+
 	/* 16 buckets per segment... */
 	entry &= ~15;
 	start = entry;
 	for(end = (start + 16); start < end; start++)
 		if(sun4c_bucket[start] != BUCKET_EMPTY)
-			return;
+			goto done;
 	/* Entire segment empty, release it. */
 	free_locked_segment(BUCKET_ADDR(entry));
+done:
+	restore_flags(flags);
 }
 
 static struct task_struct *sun4c_alloc_task_struct(void)
 {
-	unsigned long addr, page;
+	unsigned long addr, page, flags;
 	int entry;
 
+	save_and_cli(flags);
+
 	page = get_free_page(GFP_KERNEL);
-	if(!page)
+	if(!page) {
+		restore_flags(flags);
 		return (struct task_struct *) 0;
+	}
 	/* XXX Bahh, linear search too slow, use hash
 	 * XXX table in final implementation.  Or
 	 * XXX keep track of first free when we free
@@ -895,13 +978,21 @@
 			break;
 	if(entry == NR_TASKS) {
 		free_page(page);
+		restore_flags(flags);
 		return (struct task_struct *) 0;
 	}
+
+	/* Prevent an alias from occurring while the page is ours. */
+	sun4c_flush_page(page);
+
 	addr = BUCKET_ADDR(entry);
 	sun4c_bucket[entry] = (struct task_bucket *) addr;
 	if(sun4c_get_segmap(addr) == invalid_segment)
 		get_locked_segment(addr);
 	sun4c_put_pte(addr, BUCKET_PTE(page));
+
+	restore_flags(flags);
+
 	return (struct task_struct *) addr;
 }
 
@@ -920,7 +1011,12 @@
 		free_page(page[0]);
 		return 0;
 	}
-	saddr += (PAGE_SIZE << 1);
+
+	/* Prevent aliases from occurring while the pages are ours. */
+	sun4c_flush_page(page[0]);
+	sun4c_flush_page(page[1]);
+
+	saddr += PAGE_SIZE << 1;
 	sun4c_put_pte(saddr, BUCKET_PTE(page[0]));
 	sun4c_put_pte(saddr + PAGE_SIZE, BUCKET_PTE(page[1]));
 	return saddr;
@@ -929,7 +1025,9 @@
 static void sun4c_free_kernel_stack(unsigned long stack)
 {
 	unsigned long page[2];
+	unsigned long flags;
 
+	save_and_cli(flags);
 	page[0] = BUCKET_PTE_PAGE(sun4c_get_pte(stack));
 	page[1] = BUCKET_PTE_PAGE(sun4c_get_pte(stack+PAGE_SIZE));
 	sun4c_flush_page(stack);
@@ -938,22 +1036,26 @@
 	sun4c_put_pte(stack + PAGE_SIZE, 0);
 	free_page(page[0]);
 	free_page(page[1]);
+	restore_flags(flags);
 }
 
 static void sun4c_free_task_struct(struct task_struct *tsk)
 {
 	unsigned long tsaddr = (unsigned long) tsk;
 	unsigned long page = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
+	unsigned long flags;
 	int entry = BUCKET_NUM(tsaddr);
 
+	save_and_cli(flags);
 	sun4c_flush_page(tsaddr);
 	sun4c_put_pte(tsaddr, 0);
 	sun4c_bucket[entry] = BUCKET_EMPTY;
 	free_page(page);
 	garbage_collect(entry);
+	restore_flags(flags);
 }
 
-static void sun4c_init_buckets(void)
+__initfunc(static void sun4c_init_buckets(void))
 {
 	int entry;
 
@@ -1017,7 +1119,10 @@
 		pte |= _SUN4C_PAGE_NOCACHE;
 		set_bit(scan, sun4c_iobuffer_map);
 		apage = (scan << PAGE_SHIFT) + sun4c_iobuffer_start;
+
+		/* Flush original mapping so we see the right things later. */
 		sun4c_flush_page(vpage);
+
 		sun4c_put_pte(apage, pte);
 		vpage += PAGE_SIZE;
 	}
@@ -1041,6 +1146,8 @@
 	vpage = (unsigned long)vaddr & PAGE_MASK;
 	npages = (((unsigned long)vaddr & ~PAGE_MASK) +
 		  size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
+
+	save_and_cli(flags);
 	while (npages != 0) {
 		--npages;
 		sun4c_put_pte(vpage, 0);
@@ -1050,7 +1157,6 @@
 	}
 
 	/* garbage collect */
-	save_and_cli(flags);
 	scan = (sun4c_iobuffer_high - sun4c_iobuffer_start) >> PAGE_SHIFT;
 	while (scan >= 0 && !sun4c_iobuffer_map[scan >> 5])
 		scan -= 32;
@@ -1074,8 +1180,10 @@
 	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 bufptr; /* already locked */
+	}
 	return sun4c_lockarea(bufptr, len);
 }
 
@@ -1109,7 +1217,7 @@
 
 struct vm_area_struct sun4c_kstack_vma;
 
-static unsigned long sun4c_init_lock_areas(unsigned long start_mem)
+__initfunc(static unsigned long sun4c_init_lock_areas(unsigned long start_mem))
 {
 	unsigned long sun4c_taskstack_start;
 	unsigned long sun4c_taskstack_end;
@@ -1135,8 +1243,6 @@
 	memset((void *) start_mem, 0, bitmap_size);
 	start_mem += bitmap_size;
 
-	/* Now get us some mmu entries for I/O maps. */
-	/* sun4c_init_lock_area(sun4c_iobuffer_start, sun4c_iobuffer_end); */
 	sun4c_kstack_vma.vm_mm = init_task.mm;
 	sun4c_kstack_vma.vm_start = sun4c_taskstack_start;
 	sun4c_kstack_vma.vm_end = sun4c_taskstack_end;
@@ -1149,80 +1255,99 @@
 /* Cache flushing on the sun4c. */
 static void sun4c_flush_cache_all(void)
 {
-	/* Clear all tags in the sun4c cache.
-	 * The cache is write through so this is safe.
-	 */
+	extern unsigned long bcopy;
+	unsigned long begin, end, flags;
+
+	begin = ((unsigned long) &bcopy);
+	end = (begin + sun4c_vacinfo.num_bytes);
+
+	save_and_cli(flags);
 	flush_user_windows();
-	__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] %3\n\t"
-			     "sta	%%g0, [%0 + %2] %3\n\t"
-			     "sta	%%g0, [%0 + %%g1] %3\n\t"
-			     "sta	%%g0, [%0 + %%g2] %3\n\t"
-			     "sta	%%g0, [%0 + %%g3] %3\n\t"
-			     "sta	%%g0, [%0 + %%g4] %3\n\t"
-			     "sta	%%g0, [%0 + %%g5] %3\n\t"
-			     "sta	%%g0, [%0 + %%o4] %3\n\t"
-			     "bg	1b\n\t"
-			     " add	%0, %%o5, %0\n\t" : :
-			     "r" (AC_CACHETAGS),
-			     "r" (sun4c_vacinfo.num_bytes),
-			     "r" (sun4c_vacinfo.linesize),
-			     "i" (ASI_CONTROL) :
-			     "g1", "g2", "g3", "g4", "g5", "o4", "o5");
+	if(sun4c_vacinfo.linesize == 32) {
+		while(begin < end) {
+			__asm__ __volatile__("
+			ld	[%0 + 0x00], %%g0
+			ld	[%0 + 0x20], %%g0
+			ld	[%0 + 0x40], %%g0
+			ld	[%0 + 0x60], %%g0
+			ld	[%0 + 0x80], %%g0
+			ld	[%0 + 0xa0], %%g0
+			ld	[%0 + 0xc0], %%g0
+			ld	[%0 + 0xe0], %%g0
+			ld	[%0 + 0x100], %%g0
+			ld	[%0 + 0x120], %%g0
+			ld	[%0 + 0x140], %%g0
+			ld	[%0 + 0x160], %%g0
+			ld	[%0 + 0x180], %%g0
+			ld	[%0 + 0x1a0], %%g0
+			ld	[%0 + 0x1c0], %%g0
+			ld	[%0 + 0x1e0], %%g0
+			" : : "r" (begin));
+			begin += 512;
+		}
+	} else {
+		while(begin < end) {
+			__asm__ __volatile__("
+			ld	[%0 + 0x00], %%g0
+			ld	[%0 + 0x10], %%g0
+			ld	[%0 + 0x20], %%g0
+			ld	[%0 + 0x30], %%g0
+			ld	[%0 + 0x40], %%g0
+			ld	[%0 + 0x50], %%g0
+			ld	[%0 + 0x60], %%g0
+			ld	[%0 + 0x70], %%g0
+			ld	[%0 + 0x80], %%g0
+			ld	[%0 + 0x90], %%g0
+			ld	[%0 + 0xa0], %%g0
+			ld	[%0 + 0xb0], %%g0
+			ld	[%0 + 0xc0], %%g0
+			ld	[%0 + 0xd0], %%g0
+			ld	[%0 + 0xe0], %%g0
+			ld	[%0 + 0xf0], %%g0
+			" : : "r" (begin));
+			begin += 256;
+		}
+	}
+	restore_flags(flags);
 }
 
 static void sun4c_flush_cache_mm(struct mm_struct *mm)
 {
-	int octx;
+	unsigned long flags;
+	int octx, new_ctx = mm->context;
 
-#ifndef __SMP__
-	if(mm->context != NO_CONTEXT) {
-#endif
+	if(new_ctx != NO_CONTEXT) {
+		save_and_cli(flags);
 		octx = sun4c_get_context();
 		flush_user_windows();
-		sun4c_set_context(mm->context);
+		sun4c_set_context(new_ctx);
 		sun4c_flush_context();
 		sun4c_set_context(octx);
-#ifndef __SMP__
+		restore_flags(flags);
 	}
-#endif
 }
 
-
 static void sun4c_flush_cache_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-	int size, size2, octx, i;
-	unsigned long start2,end2;
-	struct sun4c_mmu_entry *entry,*entry2;
+	int size, size2, octx, i, new_ctx = mm->context;
+	unsigned long start2, end2, flags;
+	struct sun4c_mmu_entry *entry, *entry2;
 	
-	/* don't flush kernel memory as its always valid in
-	   all contexts */
-	if (start >= PAGE_OFFSET)
-		return;
-
 #if KGPROF_PROFILING
 	kgprof_profile();
 #endif
 
-#ifndef __SMP__
-	if(mm->context != NO_CONTEXT) {
-#endif
+	if(new_ctx != NO_CONTEXT) {
+		save_and_cli(flags);
+
 		size = end - start;
 
 		octx = sun4c_get_context();
 		flush_user_windows();
-		sun4c_set_context(mm->context);
+		sun4c_set_context(new_ctx);
 
-		entry = sun4c_context_ring[mm->context].ringhd.next;
-		i = sun4c_context_ring[mm->context].num_entries;
+		entry = sun4c_context_ring[new_ctx].ringhd.next;
+		i = sun4c_context_ring[new_ctx].num_entries;
 		while (i--) {
 			entry2 = entry->next;
 			if (entry->vaddr < start || entry->vaddr >= end) 
@@ -1241,52 +1366,55 @@
 			} else {
 				start2 &= SUN4C_REAL_PGDIR_MASK;
 				sun4c_flush_segment(start2);
-				/* we are betting that the entry will not be 
-				   needed for a while */
+
+				/* We are betting that the entry will not be 
+				 * needed for a while.
+				 */
 				sun4c_user_unmap(entry);
-				free_user_entry(mm->context, entry);
+				free_user_entry(new_ctx, entry);
 			}
 
 		next_entry:
 			entry = entry2;
 		}
 		sun4c_set_context(octx);
-#ifndef __SMP__
+		restore_flags(flags);
 	}
-#endif
 }
 
 static void sun4c_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
 {
-	int octx;
+	unsigned long flags;
 	struct mm_struct *mm = vma->vm_mm;
-
-	/* don't flush kernel memory as its always valid in
-	   all contexts */
-	if (page >= PAGE_OFFSET)
-		return;
+	int octx, new_ctx = mm->context;
 
 	/* Sun4c has no separate I/D caches so cannot optimize for non
 	 * text page flushes.
 	 */
-#ifndef __SMP__
-	if(mm->context != NO_CONTEXT) {
-#endif
+	if(new_ctx != NO_CONTEXT) {
+		save_and_cli(flags);
 		octx = sun4c_get_context();
 		flush_user_windows();
-		sun4c_set_context(mm->context);
+		sun4c_set_context(new_ctx);
 		sun4c_flush_page(page);
 		sun4c_set_context(octx);
-#ifndef __SMP__
+		restore_flags(flags);
 	}
-#endif
 }
 
-/* Sun4c cache is write-through, so no need to validate main memory
- * during a page copy in kernel space.
+/* Even though sun4c is write through, a virtual cache alias inconsistancy
+ * can still occur with COW page handling so we must flush anyways.
  */
 static void sun4c_flush_page_to_ram(unsigned long page)
 {
+	sun4c_flush_page(page);
+}
+
+/* Sun4c cache is unified, both instructions and data live there, so
+ * no need to flush the on-stack instructions for new signal handlers.
+ */
+static void sun4c_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
+{
 }
 
 /* TLB flushing on the sun4c.  These routines count on the cache
@@ -1296,21 +1424,23 @@
 
 static void sun4c_flush_tlb_all(void)
 {
+	struct sun4c_mmu_entry *this_entry, *next_entry;
 	unsigned long flags;
-	int savectx, ctx, entry;
+	int savectx, ctx;
 
 	save_and_cli(flags);
+	this_entry = sun4c_kernel_ring.ringhd.next;
 	savectx = sun4c_get_context();
-	for (entry = 0; entry < SUN4C_KERNEL_BUCKETS; entry++) {
-		if (sun4c_kernel_next->vaddr) {
-			for(ctx = 0; ctx < num_contexts; ctx++) {
-				sun4c_set_context(ctx);
-				sun4c_put_segmap(sun4c_kernel_next->vaddr,
-						 invalid_segment);
-			}
-			sun4c_kernel_next->vaddr = 0;
+	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++) {
+			sun4c_set_context(ctx);
+			sun4c_put_segmap(this_entry->vaddr, invalid_segment);
 		}
-		sun4c_next_kernel_bucket(&sun4c_kernel_next);
+		free_kernel_entry(this_entry, &sun4c_kernel_ring);
+		this_entry = next_entry;
 	}
 	sun4c_set_context(savectx);
 	restore_flags(flags);
@@ -1320,93 +1450,83 @@
 {
 	struct sun4c_mmu_entry *this_entry, *next_entry;
 	struct sun4c_mmu_ring *crp;
-	int savectx, ctx;
+	unsigned long flags;
+	int savectx, new_ctx = mm->context;
 
-#ifndef __SMP__
-	if(mm->context != NO_CONTEXT) {
-#endif
-		crp = &sun4c_context_ring[mm->context];
+	if(new_ctx != NO_CONTEXT) {
+		save_and_cli(flags);
+		crp = &sun4c_context_ring[new_ctx];
 		savectx = sun4c_get_context();
-		ctx = mm->context;
 		this_entry = crp->ringhd.next;
 		flush_user_windows();
-		sun4c_set_context(mm->context);
-		sun4c_flush_context();
+		sun4c_set_context(new_ctx);
 		while(crp->num_entries) {
 			next_entry = this_entry->next;
+			sun4c_flush_segment(this_entry->vaddr);
 			sun4c_user_unmap(this_entry);
-			free_user_entry(ctx, this_entry);
+			free_user_entry(new_ctx, this_entry);
 			this_entry = next_entry;
 		}
 		sun4c_set_context(savectx);
-#ifndef __SMP__
+		restore_flags(flags);
 	}
-#endif
 }
 
 static void sun4c_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-	struct sun4c_mmu_entry *entry,*entry2;
-	unsigned char savectx;
-	int i;
+	struct sun4c_mmu_entry *entry, *entry2;
+	unsigned long flags;
+	int i, savectx, new_ctx = mm->context;
 
-#ifndef __SMP__
-	if(mm->context == NO_CONTEXT)
+	if(new_ctx == NO_CONTEXT)
 		return;
-#endif
 
 #if KGPROF_PROFILING
 	kgprof_profile();
 #endif
 
+	save_and_cli(flags);
 	savectx = sun4c_get_context();
-	sun4c_set_context(mm->context);
+	flush_user_windows();
+	sun4c_set_context(new_ctx);
 	start &= SUN4C_REAL_PGDIR_MASK;
 
-	entry = sun4c_context_ring[mm->context].ringhd.next;
-	i = sun4c_context_ring[mm->context].num_entries;
+	entry = sun4c_context_ring[new_ctx].ringhd.next;
+	i = sun4c_context_ring[new_ctx].num_entries;
 	while (i--) {
 		entry2 = entry->next;
 		if (entry->vaddr >= start && entry->vaddr < end) {
 			sun4c_flush_segment(entry->vaddr);
 			sun4c_user_unmap(entry);
-			free_user_entry(mm->context, entry);
+			free_user_entry(new_ctx, entry);
 		}
 		entry = entry2;
 	}
 	sun4c_set_context(savectx);
+	restore_flags(flags);
 }
 
-
 static void sun4c_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 {
 	struct mm_struct *mm = vma->vm_mm;
-	int savectx;
+	unsigned long flags;
+	int savectx, new_ctx = mm->context;
 
-#ifndef __SMP__
-	if(mm->context != NO_CONTEXT) {
-#endif
+	if(new_ctx != NO_CONTEXT) {
+		save_and_cli(flags);
 		savectx = sun4c_get_context();
-		sun4c_set_context(mm->context);
+		flush_user_windows();
+		sun4c_set_context(new_ctx);
 		page &= PAGE_MASK;
-		if(sun4c_get_pte(page) & _SUN4C_PAGE_VALID)
-			sun4c_put_pte(page, 0);
+		sun4c_flush_page(page);
+		sun4c_put_pte(page, 0);
 		sun4c_set_context(savectx);
-#ifndef __SMP__
+		restore_flags(flags);
 	}
-#endif
 }
 
-/* Sun4c mmu hardware doesn't update the dirty bit in the pte's
- * for us, so we do it in software.
- */
 static void sun4c_set_pte(pte_t *ptep, pte_t pte)
 {
-
-	if((pte_val(pte) & (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_DIRTY)) ==
-	   _SUN4C_PAGE_WRITE)
-		pte_val(pte) |= _SUN4C_PAGE_DIRTY;
-
 	*ptep = pte;
 }
 
@@ -1416,17 +1536,14 @@
 	unsigned long page_entry;
 
 	page_entry = ((physaddr >> PAGE_SHIFT) & 0xffff);
-	page_entry |= (_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE |
-		       _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_IO);
+	page_entry |= ((pg_iobits | _SUN4C_PAGE_PRIV) & ~(_SUN4C_PAGE_PRESENT));
 	if(rdonly)
-		page_entry &= (~_SUN4C_PAGE_WRITE);
-	sun4c_flush_page(virt_addr);
+		page_entry &= ~_SUN4C_WRITEABLE;
 	sun4c_put_pte(virt_addr, page_entry);
 }
 
 void sun4c_unmapioaddr(unsigned long virt_addr)
 {
-	sun4c_flush_page(virt_addr); /* XXX P3: Is it necessary for I/O page? */
 	sun4c_put_pte(virt_addr, 0);
 }
 
@@ -1474,7 +1591,9 @@
 static void sun4c_switch_to_context(struct task_struct *tsk)
 {
 	struct ctx_list *ctx;
+	unsigned long flags;
 
+	save_and_cli(flags);
 	if(tsk->mm->context == NO_CONTEXT) {
 		sun4c_alloc_context(tsk->mm);
 		goto set_context;
@@ -1487,13 +1606,18 @@
 
 set_context:
 	sun4c_set_context(tsk->mm->context);
+	restore_flags(flags);
 }
 
 static void sun4c_flush_hook(void)
 {
 	if(current->tss.flags & SPARC_FLAG_KTHREAD) {
+		unsigned long flags;
+
+		save_flags(flags);
 		sun4c_alloc_context(current->mm);
 		sun4c_set_context(current->mm->context);
+		restore_flags(flags);
 	}
 }
 
@@ -1503,11 +1627,15 @@
 	struct mm_struct *mm = current->mm;
 
 	if(mm->context != NO_CONTEXT && mm->count == 1) {
+		unsigned long flags;
+
+		save_and_cli(flags);
 		sun4c_demap_context(&sun4c_context_ring[mm->context], mm->context);
 		ctx_old = ctx_list_pool + mm->context;
 		remove_from_ctx_list(ctx_old);
 		add_to_free_ctxlist(ctx_old);
 		mm->context = NO_CONTEXT;
+		restore_flags(flags);
 	}
 }
 
@@ -1531,6 +1659,7 @@
 		"mmuctxs\t\t: %d\n"
 		"mmupsegs\t: %d\n"
 		"kernelpsegs\t: %d\n"
+		"kfreepsegs\t: %d\n"
 		"usedpsegs\t: %d\n"
 		"ufreepsegs\t: %d\n"
 		"context\t\t: %d flushes\n"
@@ -1541,8 +1670,8 @@
 		sun4c_vacinfo.linesize,
 		num_contexts,
 		(invalid_segment + 1),
-		invalid_segment - used_user_entries -
-			sun4c_ufree_ring.num_entries + 1,
+		sun4c_kernel_ring.num_entries,
+		sun4c_kfree_ring.num_entries,
 		used_user_entries,
 		sun4c_ufree_ring.num_entries,
 		ctxflushes, segflushes, pageflushes);
@@ -1590,17 +1719,23 @@
 }
 
 static int sun4c_pte_none(pte_t pte)		{ return !pte_val(pte); }
-static int sun4c_pte_present(pte_t pte)	        { return pte_val(pte) & _SUN4C_PAGE_VALID; }
+static int sun4c_pte_present(pte_t pte)
+{
+	return ((pte_val(pte) & (_SUN4C_PAGE_PRESENT | _SUN4C_PAGE_PRIV)) != 0);
+}
 static void sun4c_pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
 
 static int sun4c_pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
 static int sun4c_pmd_bad(pmd_t pmd)
 {
-	return (pmd_val(pmd) & ~PAGE_MASK) != PGD_TABLE ||
-		MAP_NR(pmd_val(pmd)) > max_mapnr;
+	return (((pmd_val(pmd) & ~PAGE_MASK) != PGD_TABLE) ||
+		(MAP_NR(pmd_val(pmd)) > max_mapnr));
 }
 
-static int sun4c_pmd_present(pmd_t pmd)	        { return pmd_val(pmd) & PGD_PRESENT; }
+static int sun4c_pmd_present(pmd_t pmd)
+{
+	return ((pmd_val(pmd) & PGD_PRESENT) != 0);
+}
 static void sun4c_pmd_clear(pmd_t *pmdp)	{ pmd_val(*pmdp) = 0; }
 
 static int sun4c_pgd_none(pgd_t pgd)		{ return 0; }
@@ -1612,16 +1747,62 @@
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-static int sun4c_pte_write(pte_t pte)		{ return pte_val(pte) & _SUN4C_PAGE_WRITE; }
-static int sun4c_pte_dirty(pte_t pte)		{ return pte_val(pte) & _SUN4C_PAGE_DIRTY; }
-static int sun4c_pte_young(pte_t pte)		{ return pte_val(pte) & _SUN4C_PAGE_REF; }
-
-static pte_t sun4c_pte_wrprotect(pte_t pte)	{ pte_val(pte) &= ~_SUN4C_PAGE_WRITE; return pte; }
-static pte_t sun4c_pte_mkclean(pte_t pte)	{ pte_val(pte) &= ~_SUN4C_PAGE_DIRTY; return pte; }
-static pte_t sun4c_pte_mkold(pte_t pte)	        { pte_val(pte) &= ~_SUN4C_PAGE_REF; return pte; }
-static pte_t sun4c_pte_mkwrite(pte_t pte)	{ pte_val(pte) |= _SUN4C_PAGE_WRITE; return pte; }
-static pte_t sun4c_pte_mkdirty(pte_t pte)	{ pte_val(pte) |= _SUN4C_PAGE_DIRTY; return pte; }
-static pte_t sun4c_pte_mkyoung(pte_t pte)	{ pte_val(pte) |= _SUN4C_PAGE_REF; return pte; }
+static int sun4c_pte_write(pte_t pte)
+{
+	return pte_val(pte) & _SUN4C_PAGE_WRITE;
+}
+
+static int sun4c_pte_dirty(pte_t pte)
+{
+	return pte_val(pte) & _SUN4C_PAGE_MODIFIED;
+}
+
+static int sun4c_pte_young(pte_t pte)
+{
+	return pte_val(pte) & _SUN4C_PAGE_ACCESSED;
+}
+
+static pte_t sun4c_pte_wrprotect(pte_t pte)
+{
+	pte_val(pte) &= ~(_SUN4C_PAGE_WRITE | _SUN4C_PAGE_SILENT_WRITE);
+	return pte;
+}
+
+static pte_t sun4c_pte_mkclean(pte_t pte)
+{
+	pte_val(pte) &= ~(_SUN4C_PAGE_MODIFIED | _SUN4C_PAGE_SILENT_WRITE);
+	return pte;
+}
+
+static pte_t sun4c_pte_mkold(pte_t pte)
+{
+	pte_val(pte) &= ~(_SUN4C_PAGE_ACCESSED | _SUN4C_PAGE_SILENT_READ);
+	return pte;
+}
+
+static pte_t sun4c_pte_mkwrite(pte_t pte)
+{
+	pte_val(pte) |= _SUN4C_PAGE_WRITE;
+	if (pte_val(pte) & _SUN4C_PAGE_MODIFIED)
+		pte_val(pte) |= _SUN4C_PAGE_SILENT_WRITE;
+	return pte;
+}
+
+static pte_t sun4c_pte_mkdirty(pte_t pte)
+{
+	pte_val(pte) |= _SUN4C_PAGE_MODIFIED;
+	if (pte_val(pte) & _SUN4C_PAGE_WRITE)
+		pte_val(pte) |= _SUN4C_PAGE_SILENT_WRITE;
+	return pte;
+}
+
+static pte_t sun4c_pte_mkyoung(pte_t pte)
+{
+	pte_val(pte) |= _SUN4C_PAGE_ACCESSED;
+	if (pte_val(pte) & _SUN4C_PAGE_READ)
+		pte_val(pte) |= _SUN4C_PAGE_SILENT_READ;
+	return pte;
+}
 
 /*
  * Conversion functions: convert a page and protection to a page entry,
@@ -1644,7 +1825,9 @@
 
 static pte_t sun4c_pte_modify(pte_t pte, pgprot_t newprot)
 {
-	return __pte((pte_val(pte) & _SUN4C_PAGE_CHG_MASK) | pgprot_val(newprot));
+	pte_val(pte) = (pte_val(pte) & _SUN4C_PAGE_CHG_MASK) |
+			pgprot_val(newprot);
+	return pte;
 }
 
 static unsigned long sun4c_pte_page(pte_t pte)
@@ -1680,13 +1863,35 @@
 {
 }
 
+/* Please take special note on the foo_kernel() routines below, our
+ * fast in window fault handler wants to get at the pte's for vmalloc
+ * area with traps off, therefore they _MUST_ be locked down to prevent
+ * a watchdog from happening.  The lowest VMALLOC'd thing is the buffer
+ * cache hash table, it is never free'd ever, so the pg0 we use for the
+ * lowest most page of pte's will never be freed and is guarenteed to
+ * be locked down.  Be careful with this code thanks.
+ */
+
 /* Allocate and free page tables. The xxx_kernel() versions are
  * used to allocate a kernel page table - this turns on ASN bits
  * if any, and marks the page tables reserved.
  */
 static void sun4c_pte_free_kernel(pte_t *pte)
 {
-	free_page((unsigned long) pte);
+	unsigned long pg0_addr = (unsigned long) pg0;
+	unsigned long this_addr = (unsigned long) pte;
+	unsigned long page = (unsigned long) pte;
+
+	pg0_addr &= PAGE_MASK;
+	this_addr &= PAGE_MASK;
+
+	/* See above comment. */
+	if(pg0_addr != this_addr) {
+		page = (PAGE_OFFSET + ((sun4c_get_pte(this_addr) & 0xffff)<<PAGE_SHIFT));
+		sun4c_unlockarea((char *)this_addr, PAGE_SIZE);
+	}
+
+	free_page(page);
 }
 
 static pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
@@ -1696,6 +1901,8 @@
 		pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
 		if (sun4c_pmd_none(*pmd)) {
 			if (page) {
+				/* See above comment. */
+				page = (pte_t *) sun4c_lockarea((char *)page, PAGE_SIZE);
 				pmd_val(*pmd) = PGD_TABLE | (unsigned long) page;
 				return page + address;
 			}
@@ -1778,11 +1985,95 @@
 	return (pgd_t *) get_free_page(GFP_KERNEL);
 }
 
+/* There are really two cases of aliases to watch out for, and these
+ * are:
+ *
+ *     1) A user's page which can be aliased with the kernels virtual
+ *        mapping of the physical page.
+ *
+ *     2) Multiple user mappings of the same inode/anonymous object
+ *        such that two copies of the same data for the same phys page
+ *        can live (writable) in the cache at the same time.
+ *
+ * We handle number 1 by flushing the kernel copy of the page always
+ * after COW page operations.
+ *
+ * NOTE: We are a bit slowed down now because the VMA arg is indeed used
+ *       now, so our ref/mod bit tracking quick userfaults eat a few more
+ *       cycles than they used to.
+ */
+void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
+{
+	unsigned long offset, vaddr, start, flags;
+	pgd_t *pgdp;
+	pte_t *ptep;
+
+	save_and_cli(flags);
+	address &= PAGE_MASK;
+	if(sun4c_get_segmap(address) == invalid_segment)
+		alloc_user_segment(address, sun4c_get_context());
+
+	if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) {
+		struct vm_area_struct *vmaring;
+		struct inode *inode;
+		int alias_found = 0;
+
+		/* While on the other hand, this is very uncommon... */
+		inode = vma->vm_inode;
+		if(!inode)
+			goto done;
+
+		offset = (address & PAGE_MASK) - vma->vm_start;
+		vmaring = inode->i_mmap; 
+		do {
+			vaddr = vmaring->vm_start + offset;
+
+			if (S4CVAC_BADALIAS(vaddr, address)) {
+				alias_found++;
+				start = vmaring->vm_start;
+				while(start < vmaring->vm_end) {
+					pgdp = sun4c_pgd_offset(vmaring->vm_mm, start);
+					if(!pgdp) goto next;
+					ptep = sun4c_pte_offset((pmd_t *) pgdp, start);
+					if(!ptep) goto next;
+
+					if(pte_val(*ptep) & _SUN4C_PAGE_PRESENT) {
+#if 1
+						printk("Fixing USER/USER alias [%d:%08lx]\n",
+						       vmaring->vm_mm->context, start);
+#endif
+						sun4c_flush_cache_page(vmaring, start);
+						pte_val(*ptep) = (pte_val(*ptep) |
+								  _SUN4C_PAGE_NOCACHE);
+						sun4c_flush_tlb_page(vmaring, start);
+					}
+				next:
+					start += PAGE_SIZE;
+				}
+			}
+		} while ((vmaring = vmaring->vm_next_share) != inode->i_mmap);
+
+		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);
+			pte_val(*ptep) = (pte_val(*ptep) | _SUN4C_PAGE_NOCACHE);
+			pte = pte_val(*ptep);
+		}
+	}
+done:
+	sun4c_put_pte(address, pte_val(pte));
+	restore_flags(flags);
+}
+
+static void sun4c_pgd_flush(pgd_t *pgdp)
+{
+}
+
 extern unsigned long free_area_init(unsigned long, unsigned long);
 extern unsigned long sparc_context_init(unsigned long, int);
 extern unsigned long end;
 
-unsigned long sun4c_paging_init(unsigned long start_mem, unsigned long end_mem)
+__initfunc(unsigned long sun4c_paging_init(unsigned long start_mem, unsigned long end_mem))
 {
 	int i, cnt;
 	unsigned long kernel_end;
@@ -1811,7 +2102,6 @@
 		PGD_TABLE | (unsigned long) pg0;
 	sun4c_init_ss2_cache_bug();
 	start_mem = PAGE_ALIGN(start_mem);
-	/* start_mem = sun4c_init_alloc_dvma_pages(start_mem); */
 	start_mem = sparc_context_init(start_mem, num_contexts);
 	start_mem = free_area_init(start_mem, end_mem);
 	cnt = 0;
@@ -1823,7 +2113,7 @@
 }
 
 /* Load up routines and constants for sun4c mmu */
-void ld_mmu_sun4c(void)
+__initfunc(void ld_mmu_sun4c(void))
 {
 	printk("Loading sun4c MMU routines\n");
 
@@ -1844,11 +2134,10 @@
 	page_copy = SUN4C_PAGE_COPY;
 	page_readonly = SUN4C_PAGE_READONLY;
 	page_kernel = SUN4C_PAGE_KERNEL;
-	pg_iobits = _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_IO | _SUN4C_PAGE_VALID
-	    | _SUN4C_PAGE_WRITE | _SUN4C_PAGE_DIRTY;
+	pg_iobits = _SUN4C_PAGE_PRESENT | _SUN4C_READABLE | _SUN4C_WRITEABLE |
+		    _SUN4C_PAGE_IO | _SUN4C_PAGE_NOCACHE;
 	
 	/* Functions */
-#ifndef __SMP__
 	flush_cache_all = sun4c_flush_cache_all;
 	flush_cache_mm = sun4c_flush_cache_mm;
 	flush_cache_range = sun4c_flush_cache_range;
@@ -1858,30 +2147,11 @@
 	flush_tlb_mm = sun4c_flush_tlb_mm;
 	flush_tlb_range = sun4c_flush_tlb_range;
 	flush_tlb_page = sun4c_flush_tlb_page;
-#else
-	local_flush_cache_all = sun4c_flush_cache_all;
-	local_flush_cache_mm = sun4c_flush_cache_mm;
-	local_flush_cache_range = sun4c_flush_cache_range;
-	local_flush_cache_page = sun4c_flush_cache_page;
-
-	local_flush_tlb_all = sun4c_flush_tlb_all;
-	local_flush_tlb_mm = sun4c_flush_tlb_mm;
-	local_flush_tlb_range = sun4c_flush_tlb_range;
-	local_flush_tlb_page = sun4c_flush_tlb_page;
-
-	flush_cache_all = smp_flush_cache_all;
-	flush_cache_mm = smp_flush_cache_mm;
-	flush_cache_range = smp_flush_cache_range;
-	flush_cache_page = smp_flush_cache_page;
-
-	flush_tlb_all = smp_flush_tlb_all;
-	flush_tlb_mm = smp_flush_tlb_mm;
-	flush_tlb_range = smp_flush_tlb_range;
-	flush_tlb_page = smp_flush_tlb_page;
-#endif
 
 	flush_page_to_ram = sun4c_flush_page_to_ram;
 
+	flush_sig_insns = sun4c_flush_sig_insns;
+
 	set_pte = sun4c_set_pte;
 	switch_to_context = sun4c_switch_to_context;
 	pmd_align = sun4c_pmd_align;
@@ -1924,6 +2194,7 @@
 	pmd_alloc = sun4c_pmd_alloc;
 	pgd_free = sun4c_pgd_free;
 	pgd_alloc = sun4c_pgd_alloc;
+	pgd_flush = sun4c_pgd_flush;
 
 	pte_write = sun4c_pte_write;
 	pte_dirty = sun4c_pte_dirty;
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/prom/init.c linux/arch/sparc/prom/init.c
--- v2.1.15/linux/arch/sparc/prom/init.c	Sun Apr 21 12:30:32 1996
+++ linux/arch/sparc/prom/init.c	Fri Dec 13 11:37:32 1996
@@ -1,4 +1,4 @@
-/* $Id: init.c,v 1.7 1996/04/04 16:31:00 tridge Exp $
+/* $Id: init.c,v 1.8 1996/11/13 05:10:06 davem Exp $
  * init.c:  Initialize internal variables used by the PROM
  *          library functions.
  *
@@ -7,6 +7,7 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
@@ -29,8 +30,7 @@
 extern void prom_meminit(void);
 extern void prom_ranges_init(void);
 
-void
-prom_init(struct linux_romvec *rp)
+__initfunc(void prom_init(struct linux_romvec *rp))
 {
 	romvec = rp;
 
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/prom/memory.c linux/arch/sparc/prom/memory.c
--- v2.1.15/linux/arch/sparc/prom/memory.c	Tue Nov 12 15:56:04 1996
+++ linux/arch/sparc/prom/memory.c	Fri Dec 13 11:37:32 1996
@@ -1,4 +1,4 @@
-/* $Id: memory.c,v 1.8 1996/07/12 05:14:56 tridge Exp $
+/* $Id: memory.c,v 1.9 1996/11/13 05:10:09 davem Exp $
  * memory.c: Prom routine for acquiring various bits of information
  *           about RAM on the machine, both virtual and physical.
  *
@@ -7,6 +7,7 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
@@ -36,8 +37,8 @@
 /* Internal Prom library routine to sort a linux_mlist_v0 memory
  * list.  Used below in initialization.
  */
-void
-prom_sortmemlist(struct linux_mlist_v0 *thislist)
+__initfunc(static void
+prom_sortmemlist(struct linux_mlist_v0 *thislist))
 {
 	int swapi = 0;
 	int i, mitr, tmpsize;
@@ -66,8 +67,7 @@
 }
 
 /* Initialize the memory lists based upon the prom version. */
-void
-prom_meminit(void)
+__initfunc(void prom_meminit(void))
 {
 	int node = 0;
 	unsigned int iter, num_regs;
diff -u --recursive --new-file v2.1.15/linux/arch/sparc/prom/ranges.c linux/arch/sparc/prom/ranges.c
--- v2.1.15/linux/arch/sparc/prom/ranges.c	Tue Nov 12 15:56:04 1996
+++ linux/arch/sparc/prom/ranges.c	Fri Dec 13 11:37:32 1996
@@ -1,9 +1,10 @@
-/* $Id: ranges.c,v 1.6 1996/11/03 08:12:01 davem Exp $
+/* $Id: ranges.c,v 1.7 1996/11/13 05:10:12 davem Exp $
  * ranges.c: Handle ranges in newer proms for obio/sbus.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <linux/init.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/sbus.h>
@@ -63,8 +64,7 @@
 	prom_adjust_regs(regs, nregs, sbus->sbus_ranges, sbus->num_sbus_ranges);
 }
 
-void
-prom_ranges_init(void)
+__initfunc(void prom_ranges_init(void))
 {
 	int node, obio_node;
 	int success;
@@ -89,8 +89,7 @@
 	return;
 }
 
-void
-prom_sbus_ranges_init(int parentnd, struct linux_sbus *sbus)
+__initfunc(void prom_sbus_ranges_init(int parentnd, struct linux_sbus *sbus))
 {
 	int success;
 	
diff -u --recursive --new-file v2.1.15/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.1.15/linux/drivers/char/Config.in	Thu Dec 12 19:37:01 1996
+++ linux/drivers/char/Config.in	Sat Dec 14 14:19:18 1996
@@ -13,10 +13,10 @@
   tristate '  Stallion EC8/64, ONboard, Brumby support' CONFIG_ISTALLION
 fi
 tristate 'SDL RISCom/8 card support' CONFIG_RISCOM8
-tristate 'Hayes ESP serial port support' CONFIG_ESP
-if [ "$CONFIG_ESP" = "y" -o "$CONFIG_ESP" = "m" ]; then
-  int '  DMA channel' CONFIG_ESP_DMA_CHANNEL 1
-  int '  FIFO trigger level' CONFIG_ESP_TRIGGER_LEVEL 768
+tristate 'Hayes ESP serial port support' CONFIG_ESPSERIAL
+if [ "$CONFIG_ESPSERIAL" = "y" -o "$CONFIG_ESPSERIAL" = "m" ]; then
+  int '  DMA channel' CONFIG_ESPSERIAL_DMA_CHANNEL 1
+  int '  FIFO trigger level' CONFIG_ESPSERIAL_TRIGGER_LEVEL 768
 fi
 tristate 'Parallel printer support' CONFIG_PRINTER
 
diff -u --recursive --new-file v2.1.15/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.1.15/linux/drivers/char/Makefile	Thu Dec 12 19:37:01 1996
+++ linux/drivers/char/Makefile	Sat Dec 14 14:19:18 1996
@@ -78,10 +78,10 @@
   endif
 endif
 
-ifeq ($(CONFIG_ESP),y)
+ifeq ($(CONFIG_ESPSERIAL),y)
 L_OBJS += esp.o
 else
-  ifeq ($(CONFIG_ESP),m)
+  ifeq ($(CONFIG_ESPSERIAL),m)
   M_OBJS += esp.o
   endif
 endif
@@ -227,3 +227,6 @@
 
 uni_hash.tbl: $(FONTMAPFILE) conmakehash
 	./conmakehash $(FONTMAPFILE) > uni_hash.tbl
+
+defkeymap.c: defkeymap.map
+	loadkeys --mktable defkeymap.map > defkeymap.c
diff -u --recursive --new-file v2.1.15/linux/drivers/char/esp.c linux/drivers/char/esp.c
--- v2.1.15/linux/drivers/char/esp.c	Thu Dec 12 19:37:01 1996
+++ linux/drivers/char/esp.c	Wed Dec 18 10:47:20 1996
@@ -79,7 +79,7 @@
 #define WAKEUP_CHARS 1024
 
 static char *serial_name = "ESP driver";
-static char *serial_version = "1.0";
+static char *serial_version = "1.1";
 
 DECLARE_TASK_QUEUE(tq_esp);
 
@@ -118,6 +118,7 @@
 
 static void autoconfig(struct esp_struct * info);
 static void change_speed(struct esp_struct *info);
+static void rs_wait_until_sent(struct tty_struct *, int);
 	
 /*
  * This assumes you have a 1.8432 MHz clock for your UART.
@@ -173,11 +174,13 @@
 }
 
 /*
- * This is used to figure out the divisor speeds and the timeouts
+ * This is used to figure out the divisor speeds
  */
-static int baud_table[] = {
-	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-	9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
+static int quot_table[] = {
+/*      0,    50,    75,  110,  134,  150,  200,  300, 600, 1200, */
+	0, 18432, 12288, 8378, 6878, 6144, 4608, 3072, 1536, 768,
+/*     1800,2400,4800,9600,19200,38400,57600,115200,230400,460800 */
+	512, 384, 192,  96,   48,   24,   16,     8,     4,     2, 0 };
 
 static inline unsigned int serial_in(struct esp_struct *info, int offset)
 {
@@ -279,17 +282,16 @@
 	mark_bh(ESP_BH);
 }
 
-static _INLINE_ void receive_chars_dma(struct esp_struct *info, int *dma_bytes,
-	int *dma_direction, unsigned int *who_dma)
+static _INLINE_ void receive_chars_dma(struct esp_struct *info, int *dma_bytes)
 {
 	unsigned int num_chars;
 
         if (*dma_bytes) {
-		info->stat_flags |= STAT_NEED_DMA;
+		info->stat_flags |= ESP_STAT_NEED_DMA;
         	return;
 	}
 
-	info->stat_flags &= ~(STAT_RX_TIMEOUT | STAT_NEED_DMA);
+	info->stat_flags &= ~(ESP_STAT_RX_TIMEOUT | ESP_STAT_NEED_DMA);
 
 	serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
 	serial_out(info, UART_ESI_CMD1, ESI_GET_RX_AVAIL);
@@ -300,8 +302,7 @@
 		return;
         
         *dma_bytes = num_chars;
-	*dma_direction = DMA_MODE_READ;
-	*who_dma = info->port;
+	info->stat_flags |= ESP_STAT_DMA_RX;
         disable_dma(dma);
         clear_dma_ff(dma);
         set_dma_mode(dma, DMA_MODE_READ);
@@ -362,18 +363,19 @@
 }
 
 static _INLINE_ void receive_chars_dma_done(struct esp_struct *info, 
-	int *dma_bytes, int *dma_direction, unsigned int *who_dma, int status)
+	int *dma_bytes, int status)
 {
 	struct tty_struct *tty = info->tty;
 	int num_bytes, bytes_left, x_bytes;
 	struct tty_flip_buffer *buffer;
 
-	if (!(*dma_bytes) || (*who_dma != info->port))
+	if (!(info->stat_flags & ESP_STAT_DMA_RX))
 		return;
 
 	disable_dma(dma);
 	clear_dma_ff(dma);
 
+	info->stat_flags &= ~ESP_STAT_DMA_RX;
 	num_bytes = *dma_bytes - get_dma_residue(dma);
 
 	buffer = &(tty->flip);
@@ -433,22 +435,21 @@
 
 	if (*dma_bytes != num_bytes) {
 		*dma_bytes = 0;
-		receive_chars_dma(info, dma_bytes, dma_direction, who_dma);
+		receive_chars_dma(info, dma_bytes);
 	} else
 		*dma_bytes = 0;
 }
 
-static _INLINE_ void transmit_chars_dma(struct esp_struct *info, int *dma_bytes,
-	int *dma_direction, unsigned int *who_dma)
+static _INLINE_ void transmit_chars_dma(struct esp_struct *info, int *dma_bytes)
 {
 	int count;
 	
 	if (*dma_bytes) {
-		info->stat_flags |= STAT_NEED_DMA;
+		info->stat_flags |= ESP_STAT_NEED_DMA;
 		return;
 	}
 
-	info->stat_flags &= ~STAT_NEED_DMA;
+	info->stat_flags &= ~ESP_STAT_NEED_DMA;
 
 	if ((info->xmit_cnt <= 0) || info->tty->stopped ||
     		info->tty->hw_stopped) {
@@ -495,8 +496,7 @@
 	}
 
         *dma_bytes = count;
-	*dma_direction = DMA_MODE_WRITE;
-	*who_dma = info->port;
+	info->stat_flags |= ESP_STAT_DMA_TX;
         disable_dma(dma);
         clear_dma_ff(dma);
         set_dma_mode(dma, DMA_MODE_WRITE);
@@ -507,11 +507,11 @@
 }
 
 static _INLINE_ void transmit_chars_dma_done(struct esp_struct *info,
-	int *dma_bytes, int *dma_direction, unsigned int *who_dma)
+	int *dma_bytes)
 {
 	int num_bytes;
 
-	if (!(*dma_bytes) || (*who_dma != info->port))
+	if (!(info->stat_flags & ESP_STAT_DMA_TX))
 		return;
 
 	disable_dma(dma);
@@ -523,7 +523,6 @@
 	{
 		*dma_bytes -= num_bytes;
 		memmove(dma_buffer, dma_buffer + num_bytes, *dma_bytes);
-		*dma_direction = DMA_MODE_WRITE;
         	disable_dma(dma);
         	clear_dma_ff(dma);
         	set_dma_mode(dma, DMA_MODE_WRITE);
@@ -531,8 +530,10 @@
         	set_dma_count(dma, *dma_bytes);
         	enable_dma(dma);
         	serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
-	} else
+	} else {
 		*dma_bytes = 0;
+		info->stat_flags &= ~ESP_STAT_DMA_TX;
+	}
 }
 
 static _INLINE_ void check_modem_status(struct esp_struct *info)
@@ -607,8 +608,6 @@
 	int pre_bytes;
 	int check_dma_only = 0;
 	static int dma_bytes;
-	static int dma_direction;
-	static int who_dma;
 	
 #ifdef SERIAL_DEBUG_INTR
 	printk("rs_interrupt_single(%d)...", irq);
@@ -624,7 +623,7 @@
 
 	do {
 		if (!info->tty || (check_dma_only &&
-			!(info->stat_flags & STAT_NEED_DMA))) {
+			!(info->stat_flags & ESP_STAT_NEED_DMA))) {
 			info = info->next_port;
 			continue;
 		}
@@ -638,7 +637,7 @@
 			err_status |= serial_in(info, UART_ESI_STAT2);
 
 			if (err_status & 0x0100)
-				info->stat_flags |= STAT_RX_TIMEOUT;
+				info->stat_flags |= ESP_STAT_RX_TIMEOUT;
 
 			if (err_status & 0x2000)	/* UART status */
 				check_modem_status(info);
@@ -654,23 +653,19 @@
 		}
 		
 		if ((scratch & 0x88)  || /* DMA completed or timed out */
-			(err_status & 0x1c00) /* receive error */)
-			if (dma_direction == DMA_MODE_READ)
+			(err_status & 0x1c00) /* receive error */) {
 				receive_chars_dma_done(info, &dma_bytes,
-					&dma_direction, &who_dma, err_status);
-			else
-				transmit_chars_dma_done(info, &dma_bytes,
-					&dma_direction, &who_dma);
+					err_status);
+				transmit_chars_dma_done(info, &dma_bytes);
+		}
 
 		if (((scratch & 0x01) ||
-			(info->stat_flags & STAT_RX_TIMEOUT)) &&
+			(info->stat_flags & ESP_STAT_RX_TIMEOUT)) &&
 			(info->IER & UART_IER_RDI))
-			receive_chars_dma(info, &dma_bytes, &dma_direction,
-				&who_dma);
+			receive_chars_dma(info, &dma_bytes);
 
 		if ((scratch & 0x02) && (info->IER & UART_IER_THRI))
-			transmit_chars_dma(info, &dma_bytes, &dma_direction,
-				&who_dma);
+			transmit_chars_dma(info, &dma_bytes);
 
 		info->last_active = jiffies;
 
@@ -815,7 +810,7 @@
 		return 0;
 	}
 
-	if (!info->port || !info->type) {
+	if (!info->port) {
 		if (info->tty)
 			set_bit(TTY_IO_ERROR, &info->tty->flags);
 		restore_flags(flags);
@@ -916,10 +911,8 @@
 	}
 
 	info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
-	info->MCR_noint = UART_MCR_DTR | UART_MCR_RTS;
 #if defined(__alpha__) && !defined(CONFIG_PCI)
 	info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2;
-	info->MCR_noint |= UART_MCR_OUT1 | UART_MCR_OUT2;
 #endif
 
 	serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
@@ -1060,14 +1053,13 @@
 	serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
 	serial_out(info, UART_ESI_CMD2, 0x00);
 
-	if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
 		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
-		info->MCR_noint &= ~(UART_MCR_DTR|UART_MCR_RTS);
-	}
 
+	info->MCR &= ~UART_MCR_OUT2;
 	serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
 	serial_out(info, UART_ESI_CMD2, UART_MCR);
-	serial_out(info, UART_ESI_CMD2, info->MCR_noint);
+	serial_out(info, UART_ESI_CMD2, info->MCR);
 
 	if (info->tty)
 		set_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -1085,8 +1077,9 @@
 	unsigned short port;
 	int	quot = 0;
 	unsigned cflag,cval;
-	int	i;
+	int	i, bits;
 	unsigned char flow1 = 0, flow2 = 0;
+	unsigned long flags;
 
 	if (!info->tty || !info->tty->termios)
 		return;
@@ -1113,53 +1106,36 @@
 		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
 			quot = info->custom_divisor;
 	}
-	if (quot) {
-		info->timeout = ((1024*HZ*15*quot) /
-				 info->baud_base) + 2;
-	} else if (baud_table[i] == 134) {
-		quot = (2*info->baud_base / 269);
-		info->timeout = (1024*HZ*30/269) + 2;
-	} else if (baud_table[i]) {
-		quot = info->baud_base / baud_table[i];
-		info->timeout = (1024*HZ*15/baud_table[i]) + 2;
-	} else {
-		quot = 0;
-		info->timeout = 0;
-	}
-	if (quot) {
-		info->MCR |= UART_MCR_DTR;
-		info->MCR_noint |= UART_MCR_DTR;
-		cli();
-		serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
-		serial_out(info, UART_ESI_CMD2, UART_MCR);
-		serial_out(info, UART_ESI_CMD2, info->MCR);
-		sti();
-	} else {
-		info->MCR &= ~UART_MCR_DTR;
-		info->MCR_noint &= ~UART_MCR_DTR;
-		cli();
-		serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
-		serial_out(info, UART_ESI_CMD2, UART_MCR);
-		serial_out(info, UART_ESI_CMD2, info->MCR);
-		sti();
-		return;
-	}
+
 	/* byte size and parity */
 	switch (cflag & CSIZE) {
-	      case CS5: cval = 0x00; break;
-	      case CS6: cval = 0x01; break;
-	      case CS7: cval = 0x02; break;
-	      case CS8: cval = 0x03; break;
-	      default:  cval = 0x00; break;	/* too keep GCC shut... */
+	      case CS5: cval = 0x00; bits = 7; break;
+	      case CS6: cval = 0x01; bits = 8; break;
+	      case CS7: cval = 0x02; bits = 9; break;
+	      case CS8: cval = 0x03; bits = 10; break;
+	      default:  cval = 0x00; bits = 7; break;
 	}
 	if (cflag & CSTOPB) {
 		cval |= 0x04;
+		bits++;
 	}
-	if (cflag & PARENB)
+	if (cflag & PARENB) {
 		cval |= UART_LCR_PARITY;
+		bits++;
+	}
 	if (!(cflag & PARODD))
 		cval |= UART_LCR_EPAR;
 	
+	if (!quot) {
+		quot = quot_table[i];
+
+		/* default to 9600 bps */
+		if (!quot)
+			quot = BASE_BAUD / 9600;
+	}
+
+	info->timeout = ((1024 * HZ * bits * quot) / BASE_BAUD) + (HZ / 50);
+
 	/* CTS flow control flag and modem status interrupts */
 	/* info->IER &= ~UART_IER_MSI; */
 	if (cflag & CRTSCTS) {
@@ -1213,7 +1189,7 @@
 	if (I_IXOFF(info->tty))
 		flow1 |= 0x81;
 
-	cli();
+	save_flags(flags); cli();
 	/* set baud */
 	serial_out(info, UART_ESI_CMD1, ESI_SET_BAUD);
 	serial_out(info, UART_ESI_CMD2, quot >> 8);
@@ -1260,7 +1236,7 @@
 	serial_out(info, UART_ESI_CMD2, (trigger + 4) / 256);
 	serial_out(info, UART_ESI_CMD2, (trigger + 4) % 256);
 
-	sti();
+	restore_flags(flags);
 }
 
 static void rs_put_char(struct tty_struct *tty, unsigned char ch)
@@ -1459,12 +1435,12 @@
 	if (!retinfo)
 		return -EFAULT;
 	memset(&tmp, 0, sizeof(tmp));
-	tmp.type = info->type;
+	tmp.type = PORT_16550A;
 	tmp.line = info->line;
 	tmp.port = info->port;
 	tmp.irq = info->irq;
 	tmp.flags = info->flags;
-	tmp.baud_base = info->baud_base;
+	tmp.baud_base = BASE_BAUD;
 	tmp.close_delay = info->close_delay;
 	tmp.closing_wait = info->closing_wait;
 	tmp.custom_divisor = info->custom_divisor;
@@ -1479,7 +1455,7 @@
 	struct serial_struct new_serial;
 	struct esp_struct old_info;
 	unsigned int		change_irq;
-	int 			retval = 0;
+	int 			i, retval = 0;
 	struct esp_struct *current_async;
 	unsigned long flags = 0;
 
@@ -1488,10 +1464,10 @@
 	copy_from_user(&new_serial,new_info,sizeof(new_serial));
 	old_info = *info;
 
-	if ((info->type != new_serial.type) ||
+	if ((new_serial.type != PORT_16550A) ||
 		(new_serial.hub6) ||
 		(info->port != new_serial.port) ||
-		(info->baud_base != new_serial.baud_base) ||
+		(new_serial.baud_base != BASE_BAUD) ||
 		(new_serial.irq > 15) ||
 		(new_serial.irq < 1))
 		return -EINVAL;
@@ -1503,7 +1479,6 @@
 
 	if (!suser()) {
 		if (change_irq || 
-		    (new_serial.baud_base != info->baud_base) ||
 		    (new_serial.close_delay != info->close_delay) ||
 		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
 		     (info->flags & ~ASYNC_USR_MASK)))
@@ -1519,24 +1494,31 @@
 
 	if (change_irq) {
 		save_flags(flags); cli();
+		i = 1;
 
-		current_async = info;
-		do {
-			if ((current_async->line >= info->line) &&
-				(current_async->line < (info->line + 8))) {
-				if (current_async == info) {
-					if (current_async->count > 1) {
+		while ((i < 16) && !IRQ_ports[i])
+			i++;
+
+		if (i < 16) {
+			current_async = IRQ_ports[i];
+
+			do {
+				if ((current_async->line >= info->line) &&
+				    (current_async->line < (info->line + 8))) {
+					if (current_async == info) {
+						if (current_async->count > 1) {
+							restore_flags(flags);
+							return -EBUSY;
+						}
+					} else {
 						restore_flags(flags);
 						return -EBUSY;
 					}
-				} else {
-					restore_flags(flags);
-					return -EBUSY;
 				}
-			}
-			
-			current_async = current_async->next_port;
-		} while (current_async != info);
+
+				current_async = current_async->next_port;
+			} while (current_async != IRQ_ports[i]);
+		}
 	}
 
 	/*
@@ -1544,14 +1526,12 @@
 	 * At this point, we start making changes.....
 	 */
 
-	info->baud_base = new_serial.baud_base;
 	info->flags = ((info->flags & ~ASYNC_FLAGS) |
 			(new_serial.flags & ASYNC_FLAGS));
 	info->custom_divisor = new_serial.custom_divisor;
 	info->close_delay = new_serial.close_delay * HZ/100;
 	info->closing_wait = new_serial.closing_wait * HZ/100;
 
-	release_region(info->port,8);
 	if (change_irq) {
 		/*
 		 * We need to shutdown the serial port at the old
@@ -1576,12 +1556,9 @@
 
 		restore_flags(flags);
 	}
-	if(info->type != PORT_UNKNOWN)
-		request_region(info->port,8,"esp(set)");
-
 	
 check_and_exit:
-	if (!info->port || !info->type)
+	if (!info->port)
 		return 0;
 	if (info->flags & ASYNC_INITIALIZED) {
 		if (((old_info.flags & ASYNC_SPD_MASK) !=
@@ -1649,33 +1626,21 @@
 
 	switch (cmd) {
 	case TIOCMBIS: 
-		if (arg & TIOCM_RTS) {
+		if (arg & TIOCM_RTS)
 			info->MCR |= UART_MCR_RTS;
-			info->MCR_noint |= UART_MCR_RTS;
-		}
-		if (arg & TIOCM_DTR) {
+		if (arg & TIOCM_DTR)
 			info->MCR |= UART_MCR_DTR;
-			info->MCR_noint |= UART_MCR_DTR;
-		}
 		break;
 	case TIOCMBIC:
-		if (arg & TIOCM_RTS) {
+		if (arg & TIOCM_RTS)
 			info->MCR &= ~UART_MCR_RTS;
-			info->MCR_noint &= ~UART_MCR_RTS;
-		}
-		if (arg & TIOCM_DTR) {
+		if (arg & TIOCM_DTR)
 			info->MCR &= ~UART_MCR_DTR;
-			info->MCR_noint &= ~UART_MCR_DTR;
-		}
 		break;
 	case TIOCMSET:
 		info->MCR = ((info->MCR & ~(UART_MCR_RTS | UART_MCR_DTR))
 			     | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
 			     | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
-		info->MCR_noint = ((info->MCR_noint
-				    & ~(UART_MCR_RTS | UART_MCR_DTR))
-				   | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
-				   | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
 		break;
 	default:
 		return -EINVAL;
@@ -1688,29 +1653,6 @@
 	return 0;
 }
 
-static int do_autoconfig(struct esp_struct * info)
-{
-	int			retval;
-	
-	if (!suser())
-		return -EPERM;
-	
-	if (info->count > 1)
-		return -EBUSY;
-	
-	shutdown(info);
-
-	cli();
-	autoconfig(info);
-	sti();
-
-	retval = startup(info);
-	if (retval)
-		return retval;
-	return 0;
-}
-
-
 /*
  * This routine sends a break character out the serial port.
  */
@@ -1759,15 +1701,24 @@
 			if (retval)
 				return retval;
 			tty_wait_until_sent(tty, 0);
-			if (!arg)
+			if (current->signal & ~current->blocked)
+				return -EINTR;
+			if (!arg) {
 				send_break(info, HZ/4);	/* 1/4 second */
+				if (current->signal & ~current->blocked)
+					return -EINTR;
+			}
 			return 0;
 		case TCSBRKP:	/* support for POSIX tcsendbreak() */
 			retval = tty_check_change(tty);
 			if (retval)
 				return retval;
 			tty_wait_until_sent(tty, 0);
+			if (current->signal & ~current->blocked)
+				return -EINTR;
 			send_break(info, arg ? arg*(HZ/10) : HZ/4);
+			if (current->signal & ~current->blocked)
+				return -EINTR;
 			return 0;
 		case TIOCGSOFTCAR:
 			return put_user(C_CLOCAL(tty) ? 1 : 0,
@@ -1801,7 +1752,8 @@
 			return set_serial_info(info,
 					       (struct serial_struct *) arg);
 		case TIOCSERCONFIG:
-			return do_autoconfig(info);
+			/* do not reconfigure after initial configuration */
+			return 0;
 
 		case TIOCSERGWILD:
 			return put_user(0L, (unsigned long *) arg);
@@ -1884,6 +1836,32 @@
 
 	change_speed(info);
 
+	/* Handle transition to B0 status */
+	if ((old_termios->c_cflag & CBAUD) &&
+		!(tty->termios->c_cflag & CBAUD)) {
+		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+		cli();
+		serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
+		serial_out(info, UART_ESI_CMD2, UART_MCR);
+		serial_out(info, UART_ESI_CMD2, info->MCR);
+		sti();
+	}
+
+	/* Handle transition away from B0 status */
+	if (!(old_termios->c_cflag & CBAUD) &&
+		(tty->termios->c_cflag & CBAUD)) {
+		info->MCR |= UART_MCR_DTR;
+		if (!tty->hw_stopped ||
+			!(tty->termios->c_cflag & CRTSCTS))
+			info->MCR |= UART_MCR_RTS;
+		cli();
+		serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
+		serial_out(info, UART_ESI_CMD2, UART_MCR);
+		serial_out(info, UART_ESI_CMD2, info->MCR);
+		sti();
+	}
+
+	/* Handle turning of CRTSCTS */
 	if ((old_termios->c_cflag & CRTSCTS) &&
 	    !(tty->termios->c_cflag & CRTSCTS)) {
 		tty->hw_stopped = 0;
@@ -1917,7 +1895,6 @@
 {
 	struct esp_struct * info = (struct esp_struct *)tty->driver_data;
 	unsigned long flags;
-	unsigned long timeout;
 
 	if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
 		return;
@@ -1995,19 +1972,7 @@
 		 * has completely drained; this is especially
 		 * important if there is a transmit FIFO!
 		 */
-		timeout = jiffies+HZ;
-		serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
-		serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
-		while ((serial_in(info, UART_ESI_STAT1) != 0x03) ||
-			(serial_in(info, UART_ESI_STAT2) != 0xff)) {
-			current->state = TASK_INTERRUPTIBLE;
-			current->timeout = jiffies + info->timeout;
-			schedule();
-			if (jiffies > timeout)
-				break;
-			serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
-			serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
-		}
+		rs_wait_until_sent(tty, info->timeout);
 	}
 	shutdown(info);
 	if (tty->driver.flush_buffer)
@@ -2044,6 +2009,46 @@
 	restore_flags(flags);
 }
 
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+	unsigned long orig_jiffies, char_time;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent"))
+		return;
+
+	orig_jiffies = jiffies;
+	char_time = ((info->timeout - HZ / 50) / 1024) / 5;
+
+	if (!char_time)
+		char_time = 1;
+
+	save_flags(flags); cli();
+	serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
+	serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
+
+	while ((serial_in(info, UART_ESI_STAT1) != 0x03) ||
+		(serial_in(info, UART_ESI_STAT2) != 0xff)) {
+		current->state = TASK_INTERRUPTIBLE;
+		current->counter = 0;
+		current->timeout = jiffies + char_time;
+		schedule();
+
+		if (current->signal & ~current->blocked)
+			break;
+
+		if (timeout && ((orig_jiffies + timeout) < jiffies))
+			break;
+
+		serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
+		serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL);
+	}
+	
+	restore_flags(flags);
+	current->state = TASK_RUNNING;
+}
+
 /*
  * esp_hangup() --- called by tty_hangup() when a hangup is signaled.
  */
@@ -2152,7 +2157,8 @@
 	info->blocked_open++;
 	while (1) {
 		cli();
-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE)) {
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+			(tty->termios->c_cflag & CBAUD)) {
 			unsigned int scratch;
 
 			serial_out(info, UART_ESI_CMD1, ESI_READ_UART);
@@ -2342,8 +2348,6 @@
 	unsigned port = info->port;
 	unsigned long flags;
 
-	info->type = PORT_UNKNOWN;
-	
 	if (!port)
 		return;
 
@@ -2360,6 +2364,7 @@
 		status2 = status1 & 0x70;
 		if (status2 != 0x20) {
 			printk(" Old ESP found at %x\n",info->port);
+			info->port = 0;
 		} else {
 			serial_out(info, UART_ESI_CMD1, 0x02);
 			status1 = serial_in(info, UART_ESI_STAT1) & 0x03;
@@ -2369,8 +2374,7 @@
 				else
 					info->irq = 3;
 			}
-			info->type = PORT_16550A;
-			request_region(port,8,"esp(auto)");
+			request_region(port,8,"esp");
 
 			/* put card in enhanced mode */
 			/* this prevents access through */
@@ -2382,6 +2386,8 @@
 			serial_out(info, UART_ESI_CMD2, UART_MCR);
 			serial_out(info, UART_ESI_CMD2, 0x00);
 		}
+	} else {
+		info->port = 0;
 	}
 
 	restore_flags(flags);
@@ -2444,6 +2450,7 @@
 	esp_driver.stop = rs_stop;
 	esp_driver.start = rs_start;
 	esp_driver.hangup = esp_hangup;
+	esp_driver.wait_until_sent = rs_wait_until_sent;
 
 	/*
 	 * The callout device is just like normal device except for
@@ -2470,7 +2477,22 @@
 
 	do {
 		info->port = esp[i] + offset;
-		info->baud_base = BASE_BAUD;
+
+		/* check if i/o region is already in use */
+		if (check_region(info->port, 8)) {
+			/* if it is a primary port, skip secondary ports */
+			if (!offset)
+				i++;
+			else if (offset == 56) {
+				i++;
+				offset = 0;
+			}
+			else
+				offset += 8;
+
+			continue;
+		}
+
 		info->custom_divisor = (divisor[i] >> (offset / 2)) & 0xf;
 		info->flags = STD_COM_FLAGS;
 		if (info->custom_divisor)
@@ -2480,7 +2502,6 @@
 		info->magic = ESP_MAGIC;
 		info->line = (i * 8) + (offset / 8);
 		info->tty = 0;
-		info->type = PORT_UNKNOWN;
 		info->close_delay = 5*HZ/10;
 		info->closing_wait = 30*HZ;
 		info->tqueue.routine = do_softint;
@@ -2494,7 +2515,7 @@
 			info->irq = 9;
 
 		autoconfig(info);
-		if (info->type == PORT_UNKNOWN) {
+		if (!info->port) {
 			i++;
 			offset = 0;
 			continue;
@@ -2559,8 +2580,7 @@
 
 	current_async = IRQ_ports[0];
 	while (current_async != 0) {
-		if (current_async->type != PORT_UNKNOWN)
-			release_region(current_async->port, 8);
+		release_region(current_async->port, 8);
 		current_async = current_async->next_port;
 	}
 
diff -u --recursive --new-file v2.1.15/linux/drivers/char/esp.h linux/drivers/char/esp.h
--- v2.1.15/linux/drivers/char/esp.h	Thu Dec 12 19:37:01 1996
+++ linux/drivers/char/esp.h	Wed Dec 18 10:47:20 1996
@@ -45,8 +45,10 @@
 #define ESI_SET_PRESCALAR	0x23
 #define ESI_NO_COMMAND		0xff
 
-#define STAT_RX_TIMEOUT		0x01
-#define STAT_NEED_DMA		0x02
+#define ESP_STAT_RX_TIMEOUT	0x01
+#define ESP_STAT_NEED_DMA	0x02
+#define ESP_STAT_DMA_RX		0x04
+#define ESP_STAT_DMA_TX		0x08
 
 #define ESP_EVENT_WRITE_WAKEUP	0
 #define ESP_MAGIC		0x53ee
@@ -54,11 +56,9 @@
 
 struct esp_struct {
 	int			magic;
-	int			baud_base;
 	int			port;
 	int			irq;
 	int			flags; 		/* defined in tty.h */
-	int			type; 		/* UART type */
 	struct tty_struct 	*tty;
 	int			read_status_mask;
 	int			ignore_status_mask;
@@ -70,7 +70,6 @@
 	unsigned short		closing_wait2;
 	int			IER; 	/* Interrupt Enable Register */
 	int			MCR; 	/* Modem control register */
-	int			MCR_noint; /* MCR with interrupts off */
 	unsigned long		event;
 	unsigned long		last_active;
 	int			line;
diff -u --recursive --new-file v2.1.15/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.1.15/linux/drivers/char/serial.c	Thu Dec 12 19:37:01 1996
+++ linux/drivers/char/serial.c	Wed Dec 18 11:45:43 1996
@@ -2365,6 +2365,9 @@
 	if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent"))
 		return;
 
+	if (info->state->type == PORT_UNKNOWN)
+		return;
+
 	orig_jiffies = jiffies;
 	/*
 	 * Set the check interval to be 1/5 of the estimated time to
@@ -2817,9 +2820,6 @@
 	info->port = state->port;
 	info->flags = state->flags;
 
-	if(check_region(info->port,8))
-		return;		/* Area in use */
-
 	save_flags(flags); cli();
 	
 	/*
@@ -3102,6 +3102,12 @@
 	state->irq = req->irq;
 	state->port = req->port;
 	state->flags = req->flags;
+
+	if (check_region(state->port,8)) {
+		restore_flags(flags);
+		printk("register_serial(): I/O region in use\n");
+		return -1;		/* Area in use */
+	}
 	autoconfig(state);
 	if (state->type == PORT_UNKNOWN) {
 		restore_flags(flags);
diff -u --recursive --new-file v2.1.15/linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c
--- v2.1.15/linux/drivers/char/vc_screen.c	Tue Oct 29 19:58:10 1996
+++ linux/drivers/char/vc_screen.c	Fri Dec 13 16:04:14 1996
@@ -14,24 +14,53 @@
  * administrator can control access using file system permissions.
  *
  * aeb@cwi.nl - efter Friedas begravelse - 950211
+ *
+ * machek@k332.feld.cvut.cz - modified not to send characters to wrong console
+ *	 - fixed some fatal of-by-one bugs (0-- no longer == -1 -> looping and looping and looping...)
+ *	 - making it working with multiple monitor patches
+ *	 - making it shorter - scr_readw are macros which expand in PRETTY long code
  */
 
+#include <linux/config.h>
+
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/errno.h>
 #include <linux/tty.h>
 #include <linux/sched.h>
+#include <linux/interrupt.h>
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 #include "vt_kern.h"
 #include "selection.h"
 
+#undef attr
+#undef org
+#undef addr
 #define HEADER_SIZE	4
 
-static inline int
+static unsigned short
+func_scr_readw(unsigned short *org)
+{
+return scr_readw( org );
+}
+
+static void
+func_scr_writew(unsigned short val, unsigned short *org)
+{
+scr_writew( val, org );
+}
+
+static int
 vcs_size(struct inode *inode)
 {
-	int size = video_num_lines * video_num_columns;
+	int size;
+#ifdef CONFIG_MULTIMON
+   	int currcons = MINOR(inode->i_rdev) & 127;
+	/* Multimon patch	*/
+	if (!vc_cons[currcons].d) return 0;
+#endif
+   	size= video_num_lines * video_num_columns;
 	if (MINOR(inode->i_rdev) & 128)
 		size = 2*size + HEADER_SIZE;
 	return size;
@@ -40,7 +69,8 @@
 static long long
 vcs_lseek(struct inode *inode, struct file *file, long long offset, int orig)
 {
-	int size = vcs_size(inode);
+	int size;
+	size = vcs_size(inode);
 
 	switch (orig) {
 		case 0:
@@ -56,145 +86,154 @@
 			return -EINVAL;
 	}
 	if (file->f_pos < 0 || file->f_pos > size)
-		return -EINVAL;
+		{ file->f_pos = 0; return -EINVAL; }
 	return file->f_pos;
 }
 
+#define RETURN( x ) { enable_bh( CONSOLE_BH ); return x; }
 static long
 vcs_read(struct inode *inode, struct file *file, char *buf, unsigned long count)
 {
-	unsigned long p = file->f_pos;
-	unsigned int cons = MINOR(inode->i_rdev);
+	int p = file->f_pos;
+	unsigned int currcons = MINOR(inode->i_rdev);
 	int viewed, attr, size, read;
 	char *buf0;
 	unsigned short *org;
 
-	attr = (cons & 128);
-	cons = (cons & 127);
-	if (cons == 0) {
-		cons = fg_console;
+	attr = (currcons & 128);
+	currcons = (currcons & 127);
+	disable_bh( CONSOLE_BH );
+	if (currcons == 0) {
+		currcons = fg_console;
 		viewed = 1;
 	} else {
-		cons--;
+		currcons--;
 		viewed = 0;
 	}
-	if (!vc_cons_allocated(cons))
-		return -ENXIO;
+	if (!vc_cons_allocated(currcons))
+		RETURN( -ENXIO );
 
 	size = vcs_size(inode);
-	if (p > size)
-		return -EINVAL;
+	if (p < 0 || p > size)
+		RETURN( -EINVAL );
 	if (count > size - p)
 		count = size - p;
 
 	buf0 = buf;
 	if (!attr) {
-		org = screen_pos(cons, p, viewed);
+		org = screen_pos(currcons, p, viewed);
 		while (count-- > 0)
-			put_user(scr_readw(org++) & 0xff, buf++);
+			put_user(func_scr_readw(org++) & 0xff, buf++);
 	} else {
 		if (p < HEADER_SIZE) {
 			char header[HEADER_SIZE];
 			header[0] = (char) video_num_lines;
 			header[1] = (char) video_num_columns;
-			getconsxy(cons, header+2);
-			while (p < HEADER_SIZE && count-- > 0)
-			    put_user(header[p++], buf++);
-		}
-		p -= HEADER_SIZE;
-		org = screen_pos(cons, p/2, viewed);
-		if ((p & 1) && count-- > 0)
-			put_user(scr_readw(org++) >> 8, buf++);
+			getconsxy(currcons, header+2);
+			while (p < HEADER_SIZE && count > 0)
+			    { count--; put_user(header[p++], buf++); }
+		}
+		if (count > 0) {
+		    p -= HEADER_SIZE;
+		    org = screen_pos(currcons, p/2, viewed);
+		    if ((p & 1) && count > 0)
+			    { count--; put_user(func_scr_readw(org++) >> 8, buf++); }
+		}
 		while (count > 1) {
-			put_user(scr_readw(org++), (unsigned short *) buf);
+			put_user(func_scr_readw(org++), (unsigned short *) buf);
 			buf += 2;
 			count -= 2;
 		}
 		if (count > 0)
-			put_user(scr_readw(org) & 0xff, buf++);
+			put_user(func_scr_readw(org) & 0xff, buf++);
 	}
 	read = buf - buf0;
 	file->f_pos += read;
-	return read;
+	RETURN( read );
 }
 
 static long
 vcs_write(struct inode *inode, struct file *file, const char *buf, unsigned long count)
 {
-	unsigned long p = file->f_pos;
-	unsigned int cons = MINOR(inode->i_rdev);
+	int p = file->f_pos;
+	unsigned int currcons = MINOR(inode->i_rdev);
 	int viewed, attr, size, written;
 	const char *buf0;
 	unsigned short *org;
 
-	attr = (cons & 128);
-	cons = (cons & 127);
-	if (cons == 0) {
-		cons = fg_console;
+	attr = (currcons & 128);
+	currcons = (currcons & 127);
+	disable_bh( CONSOLE_BH );
+	if (currcons == 0) {
+		currcons = fg_console;
 		viewed = 1;
 	} else {
-		cons--;
+		currcons--;
 		viewed = 0;
 	}
-	if (!vc_cons_allocated(cons))
-		return -ENXIO;
+	if (!vc_cons_allocated(currcons))
+		RETURN( -ENXIO );
 
 	size = vcs_size(inode);
-	if (p > size)
-		return -EINVAL;
+	if (p < 0 || p > size)
+		RETURN( -EINVAL );
 	if (count > size - p)
 		count = size - p;
 
 	buf0 = buf;
 	if (!attr) {
-		org = screen_pos(cons, p, viewed);
-		while (count-- > 0) {
+		org = screen_pos(currcons, p, viewed);
+		while (count > 0) {
 			unsigned char c;
+			count--;
 			get_user(c, (const unsigned char*)buf++);
-			scr_writew((scr_readw(org) & 0xff00) | c, org);
+			func_scr_writew((func_scr_readw(org) & 0xff00) | c, org);
 			org++;
 		}
 	} else {
 		if (p < HEADER_SIZE) {
 			char header[HEADER_SIZE];
-			getconsxy(cons, header+2);
-			while (p < HEADER_SIZE && count-- > 0)
-				get_user(header[p++], buf++);
+			getconsxy(currcons, header+2);
+			while (p < HEADER_SIZE && count > 0)
+				{ count--; get_user(header[p++], buf++); }
 			if (!viewed)
-				putconsxy(cons, header+2);
+				putconsxy(currcons, header+2);
 		}
-		p -= HEADER_SIZE;
-		org = screen_pos(cons, p/2, viewed);
-		if ((p & 1) && count-- > 0) {
-			char c;
-			get_user(c,buf++);
-			scr_writew((c << 8) |
-				   (scr_readw(org) & 0xff), org);
-			org++;
+		if (count > 0) {
+		    p -= HEADER_SIZE;
+			org = screen_pos(currcons, p/2, viewed);
+			if ((p & 1) && count > 0) {
+			    char c;
+				count--;
+				get_user(c,buf++);
+				func_scr_writew((c << 8) |
+				     (func_scr_readw(org) & 0xff), org);
+				org++;
+			}
 		}
 		while (count > 1) {
 			unsigned short w;
 			get_user(w, (const unsigned short *) buf);
-			scr_writew(w, org++);
+			func_scr_writew(w, org++);
 			buf += 2;
 			count -= 2;
 		}
 		if (count > 0) {
 			unsigned char c;
 			get_user(c, (const unsigned char*)buf++);
-			scr_writew((scr_readw(org) & 0xff00) | c, org);
+			func_scr_writew((func_scr_readw(org) & 0xff00) | c, org);
 		}
 	}
 	written = buf - buf0;
 	file->f_pos += written;
-	return written;
+	RETURN( written );
 }
 
 static int
 vcs_open(struct inode *inode, struct file *filp)
 {
-	unsigned int cons = (MINOR(inode->i_rdev) & 127);
-	if(cons && !vc_cons_allocated(cons-1))
+	unsigned int currcons = (MINOR(inode->i_rdev) & 127);
+	if(currcons && !vc_cons_allocated(currcons-1))
 		return -ENXIO;
 	return 0;
 }
diff -u --recursive --new-file v2.1.15/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.1.15/linux/drivers/net/Config.in	Thu Dec 12 19:37:04 1996
+++ linux/drivers/net/Config.in	Sat Dec 14 13:40:11 1996
@@ -113,20 +113,22 @@
 
 bool 'Radio network interfaces' CONFIG_NET_RADIO
 if [ "$CONFIG_NET_RADIO" != "n" ]; then
-  if [ "$CONFIG_AX25" != "n" ]; then
-    tristate 'Serial port KISS driver for AX.25' CONFIG_MKISS
-    tristate 'BPQ Ethernet driver for AX.25' CONFIG_BPQETHER
-    tristate 'Gracilis PackeTwin driver for AX.25' CONFIG_PT
-    tristate 'Ottawa PI and PI2 driver for AX.25' CONFIG_PI
-    tristate 'Z8530 SCC driver for AX.25' CONFIG_SCC
-  fi
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    tristate 'BAYCOM ser12 and par96 driver for AX.25' CONFIG_BAYCOM
-    tristate 'Soundcard modem driver for AX.25' CONFIG_SOUNDMODEM
-  fi
   tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP
   tristate 'WaveLAN support' CONFIG_WAVELAN
   tristate 'WIC Radio IP bridge' CONFIG_WIC
+fi
+
+bool 'AX.25 network interfaces' CONFIG_NET_HAM
+if [ "$CONFIG_NET_HAM" != "n" ]; then
+  tristate 'Serial port KISS driver' CONFIG_MKISS
+  tristate 'BPQ Ethernet driver' CONFIG_BPQETHER
+  tristate 'Gracilis PackeTwin driver' CONFIG_PT
+  tristate 'Ottawa PI and PI2 driver' CONFIG_PI
+  tristate 'Z8530 SCC driver' CONFIG_SCC
+  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    tristate 'BAYCOM ser12 and par96 driver' CONFIG_BAYCOM
+    tristate 'Soundcard modem driver' CONFIG_SOUNDMODEM
+  fi
 fi
 
 tristate 'SLIP (serial line) support' CONFIG_SLIP
diff -u --recursive --new-file v2.1.15/linux/drivers/net/baycom.c linux/drivers/net/baycom.c
--- v2.1.15/linux/drivers/net/baycom.c	Fri Nov  1 17:13:17 1996
+++ linux/drivers/net/baycom.c	Wed Dec 18 12:29:11 1996
@@ -49,18 +49,20 @@
  *  picpar: This is a redesign of the par96 modem by Henning Rech, DF9IC. The
  *          modem is protocol compatible to par96, but uses only three low
  *          power ICs and can therefore be fed from the parallel port and
- *          does not require an additional power supply.
+ *          does not require an additional power supply. It features
+ *          built in DCD circuitry. The driver should therefore be configured
+ *          for hardware DCD.
  *
  *
  *  Command line options (insmod command line)
  * 
- *  modem    modem type of the first channel; 1=ser12,
+ *  mode     driver mode string. Valid choices are ser12 and par96. An
+ *           optional * enables software DCD.
  *           2=par96/par97, any other value invalid
  *  iobase   base address of the port; common values are for ser12 0x3f8,
  *           0x2f8, 0x3e8, 0x2e8 and for par96/par97 0x378, 0x278, 0x3bc
  *  irq      interrupt line of the port; common values are for ser12 3,4
  *           and for par96/par97 7
- *  options  0=use hardware DCD, 1=use software DCD
  * 
  *
  *  History:
@@ -94,6 +96,18 @@
 
 #define BAYCOM_DEBUG
 
+/*
+ * modem options; bit mask
+ */
+#define BAYCOM_OPTIONS_SOFTDCD  1
+
+
+/* --------------------------------------------------------------------- */
+
+static const char bc_drvname[] = "baycom";
+static const char bc_drvinfo[] = KERN_INFO "baycom: (C) 1996 Thomas Sailer, HB9JNX/AE4WA\n"
+KERN_INFO "baycom: version 0.3 compiled " __TIME__ " " __DATE__ "\n";
+
 /* --------------------------------------------------------------------- */
 
 #define NR_PORTS 4
@@ -101,8 +115,9 @@
 static struct device baycom_device[NR_PORTS];
 
 static struct {
-	int modem, iobase, irq, options;
-} baycom_ports[NR_PORTS] = { { BAYCOM_MODEM_INVALID, 0, 0, 0, }, };
+	char *mode;
+	int iobase, irq;
+} baycom_ports[NR_PORTS] = { { NULL, 0, 0 }, };
 
 /* --------------------------------------------------------------------- */
 
@@ -185,8 +200,6 @@
 #define max(a, b) (((a) > (b)) ? (a) : (b))
 
 /* --------------------------------------------------------------------- */
-/* --------------------------------------------------------------------- */
-/* --------------------------------------------------------------------- */
 
 static void inline baycom_int_freq(struct baycom_state *bc)
 {
@@ -496,6 +509,7 @@
 	if (check_region(dev->base_addr, SER12_EXTENT))
 		return -EACCES;
 	memset(&bc->modem, 0, sizeof(bc->modem));
+	bc->hdrv.par.bitrate = 1200;
 	if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown)
 		return -EIO;
 	outb(0, FCR(dev->base_addr));  /* disable FIFOs */
@@ -516,9 +530,9 @@
 	 * depending on the usage of the software DCD routine
 	 */
 	ser12_set_divisor(dev, (bc->options & BAYCOM_OPTIONS_SOFTDCD) ? 4 : 6);
-	printk(KERN_INFO "baycom: ser12 at iobase 0x%lx irq %u options "
-	       "0x%x uart %s\n", dev->base_addr, dev->irq, bc->options, 
-	       uart_str[u]);
+	printk(KERN_INFO "%s: ser12 at iobase 0x%lx irq %u options "
+	       "0x%x uart %s\n", bc_drvname, dev->base_addr, dev->irq, 
+	       bc->options, uart_str[u]);
 	MOD_INC_USE_COUNT;
 	return 0;
 }
@@ -538,8 +552,8 @@
 	outb(1, MCR(dev->base_addr));
 	free_irq(dev->irq, dev);	
 	release_region(dev->base_addr, SER12_EXTENT);
-	printk(KERN_INFO "baycom: close ser12 at iobase 0x%lx irq %u\n",
-	       dev->base_addr, dev->irq);
+	printk(KERN_INFO "%s: close ser12 at iobase 0x%lx irq %u\n",
+	       bc_drvname, dev->base_addr, dev->irq);
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
@@ -702,14 +716,15 @@
 	if (check_region(dev->base_addr, PAR96_EXTENT))
 		return -EACCES;
 	memset(&bc->modem, 0, sizeof(bc->modem));
+	bc->hdrv.par.bitrate = 9600;
 	if (par96_check_lpt(dev->base_addr))
 		return -EIO;
 	/* disable interrupt */
 	outb(0, LPT_CONTROL(dev->base_addr));          
 	 /* switch off PTT */
 	outb(PAR96_PTT | PAR97_POWER, LPT_DATA(dev->base_addr));
-	printk(KERN_INFO "baycom: par96 at iobase 0x%lx irq %u "
-	       "options 0x%x\n", dev->base_addr, dev->irq, bc->options);
+	printk(KERN_INFO "%s: par96 at iobase 0x%lx irq %u options 0x%x\n",
+	       bc_drvname, dev->base_addr, dev->irq, bc->options);
 	if (request_irq(dev->irq, par96_interrupt, SA_INTERRUPT, 
 			"baycom_par96", dev))
 		return -EBUSY;
@@ -734,8 +749,8 @@
 	outb(PAR96_PTT | PAR97_POWER, LPT_DATA(dev->base_addr));
 	free_irq(dev->irq, dev);	
 	release_region(dev->base_addr, PAR96_EXTENT);
-	printk(KERN_INFO "baycom: close par96 at iobase 0x%lx irq %u\n",
-	       dev->base_addr, dev->irq);
+	printk(KERN_INFO "%s: close par96 at iobase 0x%lx irq %u\n",
+	       bc_drvname, dev->base_addr, dev->irq);
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
@@ -747,12 +762,14 @@
 
 /* --------------------------------------------------------------------- */
 
-static int baycom_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
+static int baycom_ioctl(struct device *dev, struct ifreq *ifr, 
+			struct hdlcdrv_ioctl *hi, int cmd);
 
 /* --------------------------------------------------------------------- */
 
 static struct hdlcdrv_ops ser12_ops = {
-	1200,
+	bc_drvname,
+	bc_drvinfo,
 	ser12_open,
 	ser12_close,
 	baycom_ioctl
@@ -761,7 +778,8 @@
 /* --------------------------------------------------------------------- */
 
 static struct hdlcdrv_ops par96_ops = {
-	9600,
+	bc_drvname,
+	bc_drvinfo,
 	par96_open,
 	par96_close,
 	baycom_ioctl
@@ -770,7 +788,8 @@
 /* --------------------------------------------------------------------- */
 
 static struct hdlcdrv_ops dummy_ops = {
-	0,
+	bc_drvname,
+	bc_drvinfo,
 	NULL,
 	NULL,
 	baycom_ioctl
@@ -778,17 +797,35 @@
 
 /* --------------------------------------------------------------------- */
 
-static struct hdlcdrv_ops *ops_tab[3] = {
-	&dummy_ops, &ser12_ops, &par96_ops
-};
+static int baycom_setmode(struct baycom_state *bc, char *modestr)
+{
+	struct hdlcdrv_ops *newops = NULL;
+	unsigned long flags;
+	
+	if (!strncmp(modestr, "off", 3))
+		newops = &dummy_ops;
+	else if (!strncmp(modestr, "ser12", 5))
+		newops = &ser12_ops;
+	else if (!strncmp(modestr, "par96", 5))
+		newops = &par96_ops;
+	else
+		return -EINVAL;
+	save_flags(flags);
+	cli();
+	bc->hdrv.ops = newops;
+	bc->options = !!strchr(modestr, '*');
+	restore_flags(flags);
+	return 0;
+}
 
 /* --------------------------------------------------------------------- */
 
-static int baycom_ioctl(struct device *dev, struct ifreq *ifr, int cmd)
+static int baycom_ioctl(struct device *dev, struct ifreq *ifr, 
+			struct hdlcdrv_ioctl *hi, int cmd)
 {
 	struct baycom_state *bc;
 	struct baycom_ioctl bi;
-	unsigned long flags;
+	int cmd2;
 		
 	if (!dev || !dev->priv || 
 	    ((struct baycom_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) {
@@ -799,38 +836,49 @@
 
 	if (cmd != SIOCDEVPRIVATE)
 		return -ENOIOCTLCMD;
-	if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi)))
+	if (get_user(cmd2, (int *)ifr->ifr_data))
 		return -EFAULT;
-
-	switch (bi.cmd) {
+	switch (hi->cmd) {
 	default:
-		return -ENOIOCTLCMD;
-
-	case BAYCOMCTL_GETMODEMTYPE:
-		bi.data.mt.modem_type = BAYCOM_MODEM_INVALID;
+		break;
+		
+	case HDLCDRVCTL_GETMODE:
 		if (bc->hdrv.ops == &ser12_ops)
-			bi.data.mt.modem_type = BAYCOM_MODEM_SER12;
+			strcpy(hi->data.modename, "ser12");
 		else if (bc->hdrv.ops == &par96_ops)
-			bi.data.mt.modem_type = BAYCOM_MODEM_PAR96;
-		else if (bc->hdrv.ops != &dummy_ops) {
-			printk(KERN_ERR "baycom: BAYCOMCTL_GETMODEMTYPE: "
-			       "modem ops invalid\n");
-		}
-		bi.data.mt.options = bc->options;
-		break;
+			strcpy(hi->data.modename, "par96");
+		else if (bc->hdrv.ops == &dummy_ops)
+			strcpy(hi->data.modename, "off");
+		else
+			strcpy(hi->data.modename, "invalid");
+		if (bc->options & 1)
+			strcat(hi->data.modename, "*");
+		if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl)))
+			return -EFAULT;
+		return 0;
 
-	case BAYCOMCTL_SETMODEMTYPE:
+	case HDLCDRVCTL_SETMODE:
 		if (!suser() || dev->start)
 			return -EACCES;
-		if (bi.data.mt.modem_type < BAYCOM_MODEM_SER12 ||
-		    bi.data.mt.modem_type > BAYCOM_MODEM_PAR96)
-			return -EINVAL;
-		save_flags(flags);
-		cli();
-		bc->hdrv.ops = ops_tab[bi.data.mt.modem_type];
-		bc->options = bi.data.mt.options;
-		restore_flags(flags);
+		hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
+		return baycom_setmode(bc, hi->data.modename);
+
+	case HDLCDRVCTL_MODELIST:
+		strcpy(hi->data.modename, "ser12,par96");
+		if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl)))
+			return -EFAULT;
 		return 0;
+		
+	case HDLCDRVCTL_MODEMPARMASK:
+		return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ;
+
+	}
+
+	if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi)))
+		return -EFAULT;
+	switch (bi.cmd) {
+	default:
+		return -ENOIOCTLCMD;
 
 #ifdef BAYCOM_DEBUG
 	case BAYCOMCTL_GETDEBUG:
@@ -860,7 +908,7 @@
 	char ifname[HDLCDRV_IFNAMELEN];
 
 	
-	printk(KERN_INFO "baycom: compiled %s %s\n", __TIME__, __DATE__);
+	printk(bc_drvinfo);
 	/*
 	 * register net devices
 	 */
@@ -868,27 +916,23 @@
 		struct device *dev = baycom_device+i;
 		sprintf(ifname, "bc%d", i);
 
-		if (baycom_ports[i].modem < BAYCOM_MODEM_SER12 ||
-		    baycom_ports[i].modem > BAYCOM_MODEM_PAR96)
+		if (!baycom_ports[i].mode)
 			set_hw = 0;
-		if (set_hw) {
-			j = hdlcdrv_register_hdlcdrv(dev, ops_tab[baycom_ports[i].modem], 
-						     sizeof(struct baycom_state), 
-						     ifname, baycom_ports[i].iobase,
-						     baycom_ports[i].irq, 0);
-			if (!j) {
-				bc = (struct baycom_state *)dev->priv;
-				bc->options = baycom_ports[i].options;
-			}
-		} else 
-			j = hdlcdrv_register_hdlcdrv(dev, &dummy_ops, 
-						     sizeof(struct baycom_state), 
-						     ifname, 0, 0, 0);
-		if (j) {
-			printk(KERN_WARNING "baycom: cannot register net "
-			       "device\n");
-		} else
+		if (!set_hw)
+			baycom_ports[i].iobase = baycom_ports[i].irq = 0;
+		j = hdlcdrv_register_hdlcdrv(dev, &dummy_ops, 
+					     sizeof(struct baycom_state), 
+					     ifname, baycom_ports[i].iobase,
+					     baycom_ports[i].irq, 0);
+		if (!j) {
+			bc = (struct baycom_state *)dev->priv;
+			if (set_hw && baycom_setmode(bc, baycom_ports[i].mode))
+				set_hw = 0;
 			found++;
+		} else {
+			printk(KERN_WARNING "%s: cannot register net device\n",
+			       bc_drvname);
+		}
 	}
 	if (!found)
 		return -ENXIO;
@@ -902,20 +946,16 @@
 /*
  * command line settable parameters
  */
-int modem = BAYCOM_MODEM_INVALID;
+char *mode = NULL;
 int iobase = 0x3f8;
 int irq = 4;
-int options = BAYCOM_OPTIONS_SOFTDCD;
 
 int init_module(void)
 {
-	printk(KERN_INFO "baycom: v0.1 (C) 1996 Thomas Sailer HB9JNX/AE4WA\n");
-
-	baycom_ports[0].modem = modem;
+	baycom_ports[0].mode = mode;
 	baycom_ports[0].iobase = iobase;
 	baycom_ports[0].irq = irq;
-	baycom_ports[0].options = options;
-	baycom_ports[1].modem = BAYCOM_MODEM_INVALID;
+	baycom_ports[1].mode = NULL;
 
 	return baycom_init();
 }
@@ -926,8 +966,6 @@
 {
 	int i;
 
-	printk(KERN_INFO "baycom: cleanup_module called\n");
-
 	for(i = 0; i < NR_PORTS; i++) {
 		struct device *dev = baycom_device+i;
 		struct baycom_state *bc = (struct baycom_state *)dev->priv;
@@ -945,24 +983,26 @@
 #else /* MODULE */
 /* --------------------------------------------------------------------- */
 /*
- * format: baycom=modem,io,irq,options[,modem,io,irq,options]
- * modem=1: ser12, modem=2: par96
- * options=0: hardware DCD, options=1: software DCD
+ * format: baycom=io,irq,mode
+ * mode: {ser12,par96}[*]
+ * * indicates sofware DCD
  */
 
 void baycom_setup(char *str, int *ints)
 {
 	int i;
 
-	for (i = 0; i < NR_PORTS; i++) 
-		if (ints[0] >= 4*i+4) {
-			baycom_ports[i].modem = ints[4*i+1];
-			baycom_ports[i].iobase = ints[4*i+2];
-			baycom_ports[i].irq = ints[4*i+3];
-			baycom_ports[i].options = ints[4*i+4];
-		} else
-			baycom_ports[i].modem = BAYCOM_MODEM_INVALID;
-
+	for (i = 0; (i < NR_PORTS) && (baycom_ports[i].mode); i++);
+	if ((i >= NR_PORTS) || (ints[0] < 3)) {
+		printk(KERN_INFO "%s: too many or invalid interface "
+		       "specifications\n", bc_drvname);
+		return;
+	}
+	baycom_ports[i].mode = str;
+	baycom_ports[i].iobase = ints[1];
+	baycom_ports[i].irq = ints[2];
+	if (i < NR_PORTS-1)
+		baycom_ports[i+1].mode = NULL;
 }
 
 #endif /* MODULE */
diff -u --recursive --new-file v2.1.15/linux/drivers/net/bpqether.c linux/drivers/net/bpqether.c
--- v2.1.15/linux/drivers/net/bpqether.c	Thu Dec 12 19:37:05 1996
+++ linux/drivers/net/bpqether.c	Sat Dec 14 13:40:11 1996
@@ -53,6 +53,8 @@
  *						and accepted source address
  *						can be configured by an ioctl()
  *						call.
+ *						Fixed to match Linux networking
+ *						changes - 2.1.15.
  */
 
 #include <linux/config.h>
@@ -329,7 +331,7 @@
 /*
  *	Statistics
  */
-static struct enet_statistics * bpq_get_stats(struct device *dev)
+static struct enet_statistics *bpq_get_stats(struct device *dev)
 {
 	struct bpqdev *bpq;
 
@@ -338,15 +340,6 @@
 	return &bpq->stats;
 }
 
-
-/*
- *	Rebuild header...
- */
-static int bpq_rebuild_header(void *buff, struct device *dev, unsigned long raddr, struct sk_buff *skb)
-{
-	return ax25_rebuild_header((unsigned char *)buff, dev, raddr, skb);
-}
-
 /*
  *	Set AX.25 callsign
  */
@@ -554,8 +547,6 @@
 		skb_queue_head_init(&dev->buffs[k]);
 
 	dev->hard_start_xmit = bpq_xmit;
-	dev->hard_header     = ax25_encapsulate;
-	dev->rebuild_header  = bpq_rebuild_header;
 	dev->open	     = bpq_open;
 	dev->stop	     = bpq_close;
 	dev->set_mac_address = bpq_set_mac_address;
@@ -574,6 +565,11 @@
 	dev->pa_brdaddr = 0;
 	dev->pa_mask    = 0;
 	dev->pa_alen    = 4;
+#endif
+
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+	dev->hard_header     = ax25_encapsulate;
+	dev->rebuild_header  = ax25_rebuild_header;
 #endif
 
 	dev->type            = ARPHRD_AX25;
diff -u --recursive --new-file v2.1.15/linux/drivers/net/eql.c linux/drivers/net/eql.c
--- v2.1.15/linux/drivers/net/eql.c	Thu Dec 12 19:37:06 1996
+++ linux/drivers/net/eql.c	Wed Dec 18 12:34:05 1996
@@ -377,7 +377,7 @@
 	{
 #ifdef EQL_DEBUG
 		if (eql_debug >= 100)
-			printk ("%s: %d slaves xmitng %ld B %s\n", 
+			printk ("%s: %d slaves xmitng %d B %s\n", 
 				dev->name, eql_number_slaves (eql->queue), skb->len,
 				slave_dev->name);
 #endif
diff -u --recursive --new-file v2.1.15/linux/drivers/net/hdlcdrv.c linux/drivers/net/hdlcdrv.c
--- v2.1.15/linux/drivers/net/hdlcdrv.c	Tue Nov 19 15:53:56 1996
+++ linux/drivers/net/hdlcdrv.c	Sat Dec 14 13:40:12 1996
@@ -29,6 +29,7 @@
  *  History:
  *   0.1  21.09.96  Started
  *        18.10.96  Changed to new user space access routines (copy_{to,from}_user)
+ *	  13.12.96  Fixed for Linux networking changes. (JSN)
  */
 
 /*****************************************************************************/
@@ -737,11 +738,9 @@
  * Rebuild the MAC-level header
  */
 
-static int hdlcdrv_rebuild_header(void *buff, struct device *dev,
-				 unsigned long raddr,
-				 struct sk_buff *skb)
+static int hdlcdrv_rebuild_header(struct sk_buff *skb)
 {
-        return ax25_rebuild_header(buff, dev, raddr, skb);
+        return ax25_rebuild_header(skb);
 }
 #endif /* CONFIG_AX25 */
 
diff -u --recursive --new-file v2.1.15/linux/drivers/net/mkiss.c linux/drivers/net/mkiss.c
--- v2.1.15/linux/drivers/net/mkiss.c	Tue Nov 12 15:56:07 1996
+++ linux/drivers/net/mkiss.c	Sat Dec 14 13:40:12 1996
@@ -18,6 +18,7 @@
  * Hans Alblas Hansa@cuci.nl
  *
  *	History
+ *	Jonathan (G4KLX)	Fixed to match Linux networking changes - 2.1.15.
  */
 
 #include <linux/config.h>
@@ -422,6 +423,7 @@
 	return 0;
 }
 
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 
 /* Return the frame type ID */
 static int ax_header(struct sk_buff *skb, struct device *dev, unsigned short type,
@@ -435,14 +437,16 @@
 }
 
 
-static int ax_rebuild_header(void *buff, struct device *dev, unsigned long raddr, struct sk_buff *skb)
+static int ax_rebuild_header(struct sk_buff *skb)
 {
 #ifdef CONFIG_INET
-	return ax25_rebuild_header(buff, dev, raddr, skb);
-#endif
+	return ax25_rebuild_header(skb);
+#else
 	return 0;
+#endif
 }
 
+#endif	/* CONFIG_{AX25,AX25_MODULE} */
 
 /* Open the low-level part of the AX25 channel. Easy! */
 static int ax_open(struct device *dev)
@@ -881,7 +885,6 @@
 	dev->hard_start_xmit = ax_xmit;
 	dev->open            = ax_open_dev;
 	dev->stop            = ax_close;
-	dev->hard_header     = ax_header;
 	dev->get_stats	     = ax_get_stats;
 #ifdef HAVE_SET_MAC_ADDR
 	dev->set_mac_address = ax_set_dev_mac_address;
@@ -894,7 +897,10 @@
 	memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
 	memcpy(dev->dev_addr,  ax25_test,  AX25_ADDR_LEN);
 
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+	dev->hard_header     = ax_header;
 	dev->rebuild_header  = ax_rebuild_header;
+#endif
 
 	for (i = 0; i < DEV_NUMBUFFS; i++)
 		skb_queue_head_init(&dev->buffs[i]);
diff -u --recursive --new-file v2.1.15/linux/drivers/net/pi2.c linux/drivers/net/pi2.c
--- v2.1.15/linux/drivers/net/pi2.c	Tue Nov 12 15:56:07 1996
+++ linux/drivers/net/pi2.c	Sat Dec 14 13:40:12 1996
@@ -54,6 +54,7 @@
    		       to the proper set_mac_address semantics which will break 
    		       a few programs I suspect.
    Aug  18, 1996 (jsn) Converted to be used as a module.
+   Dec  13, 1996 (jsn) Fixed to match Linux networking changes.
 */
 
 /* The following #define invokes a hack that will improve performance (baud)
@@ -86,6 +87,7 @@
    the PI2 - but it's safer to leave it in. */
 #define REALLY_SLOW_IO 1
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -1065,20 +1067,6 @@
     }
 }
 
-/* Fill in the MAC-level header. */
-static int pi_header(struct sk_buff *skb, struct device *dev, unsigned short type,
-	     void *daddr, void *saddr, unsigned len)
-{
-    return ax25_encapsulate(skb, dev, type, daddr, saddr, len);
-}
-
-/* Rebuild the MAC-level header. */
-static int pi_rebuild_header(void *buff, struct device *dev, unsigned long raddr,
-			     struct sk_buff *skb)
-{
-    return ax25_rebuild_header(buff, dev, raddr, skb);
-}
-
 static void scc_init(struct device *dev)
 {
     unsigned long flags;
@@ -1415,9 +1403,11 @@
     for (i = 0; i < DEV_NUMBUFFS; i++)
 	skb_queue_head_init(&dev->buffs[i]);
 
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+    dev->hard_header    = ax25_encapsulate;
+    dev->rebuild_header = ax25_rebuild_header;
+#endif
 
-    dev->hard_header = pi_header;
-    dev->rebuild_header = pi_rebuild_header;
     dev->set_mac_address = pi_set_mac_address;
 
     dev->type = ARPHRD_AX25;			/* AF_AX25 device */
diff -u --recursive --new-file v2.1.15/linux/drivers/net/pt.c linux/drivers/net/pt.c
--- v2.1.15/linux/drivers/net/pt.c	Tue Nov 12 15:56:07 1996
+++ linux/drivers/net/pt.c	Sat Dec 14 13:40:12 1996
@@ -34,6 +34,7 @@
  * 21/12/95 cs  Got rid of those nasty warnings when compiling, for 1.3.48
  * 08/08/96 jsn Convert to use as a module. Removed send_kiss, empty_scc and
  *		pt_loopback functions - they were unused.
+ * 13/12/96 jsn Fixed to match Linux networking changes.
  */
  
 /* 
@@ -66,6 +67,7 @@
 #define	PARAM_HARDWARE	6
 #define	PARAM_RETURN	255
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/sched.h>
@@ -315,24 +317,6 @@
     dev_kfree_skb(skb, FREE_WRITE);
 }
 
-/* Fill in the MAC-level header */
-static int pt_header (struct sk_buff *skb, struct device *dev, unsigned short type,
-		void *daddr, void *saddr, unsigned len)
-{
-	return ax25_encapsulate(skb, dev, type, daddr, saddr, len);
-}
-
-
-/* Rebuild the MAC-level header */
-static int pt_rebuild_header(void *buff, struct device *dev, unsigned long raddr,
-				struct sk_buff *skb)
-{
-	return ax25_rebuild_header(buff, dev, raddr, skb);
-}
-
-					
-					
-
 
 /*
  * This sets up all the registers in the SCC for the given channel
@@ -870,8 +854,11 @@
     for (i=0; i < DEV_NUMBUFFS; i++)
         skb_queue_head_init(&dev->buffs[i]);
 
-    dev->hard_header = pt_header;
-    dev->rebuild_header = pt_rebuild_header;
+#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
+    dev->hard_header    = ax25_encapsulate;
+    dev->rebuild_header = ax25_rebuild_header;
+#endif
+
     dev->set_mac_address = pt_set_mac_address;
 
     dev->type = ARPHRD_AX25;            /* AF_AX25 device */
diff -u --recursive --new-file v2.1.15/linux/drivers/net/scc.c linux/drivers/net/scc.c
--- v2.1.15/linux/drivers/net/scc.c	Fri Nov  1 17:13:18 1996
+++ linux/drivers/net/scc.c	Sat Dec 14 13:40:12 1996
@@ -85,6 +85,8 @@
    		  The move to version number 3.0 reflects theses changes.
    		  You can use version 2.4a if you need a KISS TNC emulator.
 
+   961213	- Fixed for Linux networking changes.
+
    Thanks to all who contributed to this driver with ideas and bug
    reports!
    
@@ -2015,9 +2017,9 @@
 /* ----> rebuild header <---- */
 
 static int 
-scc_net_rebuild_header(void *buff, struct device *dev, unsigned long raddr, struct sk_buff *skb)
+scc_net_rebuild_header(struct sk_buff *skb)
 {
-    return ax25_rebuild_header(buff, dev, raddr, skb);
+    return ax25_rebuild_header(skb);
 }
 
 /* ----> "hard" header <---- */
diff -u --recursive --new-file v2.1.15/linux/drivers/net/slip.h linux/drivers/net/slip.h
--- v2.1.15/linux/drivers/net/slip.h	Fri Apr 12 09:49:39 1996
+++ linux/drivers/net/slip.h	Wed Dec 18 12:34:31 1996
@@ -87,7 +87,7 @@
   int			xdata, xbits;	/* 6 bit slip controls 		*/
 #endif
 
-  unsigned char		flags;		/* Flag values/ mode etc	*/
+  unsigned int		flags;		/* Flag values/ mode etc	*/
 #define SLF_INUSE	0		/* Channel in use               */
 #define SLF_ESCAPE	1               /* ESC received                 */
 #define SLF_ERROR	2               /* Parity, etc. error           */
diff -u --recursive --new-file v2.1.15/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c
--- v2.1.15/linux/drivers/net/sunhme.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/sunhme.c	Fri Dec 13 11:37:32 1996
@@ -0,0 +1,2211 @@
+/* sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
+ *           auto carrier detecting ethernet driver.  Also known as the
+ *           "Happy Meal Ethernet" found on SunSwift SBUS cards.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+static char *version =
+        "sunhme.c:v1.1 10/Oct/96 David S. Miller (davem@caipfs.rutgers.edu)\n";
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+#include <asm/byteorder.h>
+
+#include <asm/idprom.h>
+#include <asm/sbus.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/auxio.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "sunhme.h"
+
+#ifdef MODULE
+static struct happy_meal *root_happy_dev = NULL;
+#endif
+
+/* #define HMEDEBUG */
+
+#ifdef HMEDEBUG
+#define HMD(x)  printk x
+#else
+#define HMD(x)
+#endif
+
+/* #define AUTO_SWITCH_DEBUG */
+
+#ifdef AUTO_SWITCH_DEBUG
+#define ASD(x)  printk x
+#else
+#define ASD(x)
+#endif
+
+#define DEFAULT_IPG0      32 /* For lance-mode only */
+#define DEFAULT_IPG1       8 /* For all modes */
+#define DEFAULT_IPG2       4 /* For all modes */
+#define DEFAULT_JAMSIZE    4 /* Toe jam */
+
+/* Oh yes, the MIF BitBang is mighty fun to program.  BitBucket is more like it. */
+#define BB_PUT_BIT(tregs, bit) \
+do { (tregs)->bb_data = (bit); (tregs)->bb_clock = 0; (tregs)->bb_clock = 1; } while(0)
+
+#define BB_GET_BIT(tregs, internal)              \
+({                                               \
+	(tregs)->bb_clock = 0;                   \
+	(tregs)->bb_clock = 1;                   \
+	if(internal)                             \
+		((tregs)->cfg & TCV_CFG_MDIO0);  \
+	else                                     \
+		((tregs)->cfg & TCV_CFG_MDIO1);  \
+})
+
+#define BB_GET_BIT2(tregs, internal)                      \
+({                                                        \
+	int retval;                                       \
+	(tregs)->bb_clock = 0;                            \
+	udelay(1);                                        \
+	if(internal)                                      \
+		retval = ((tregs)->cfg & TCV_CFG_MDIO0);  \
+	else                                              \
+		retval = ((tregs)->cfg & TCV_CFG_MDIO1);  \
+	(tregs)->bb_clock = 1;                            \
+	retval;                                           \
+})
+
+#define TCVR_FAILURE      0x80000000     /* Impossible MIF read value */
+
+static inline int happy_meal_bb_read(struct happy_meal *hp,
+				     struct hmeal_tcvregs *tregs, int reg)
+{
+	volatile int unused;
+	unsigned long tmp;
+	int retval = 0;
+	int i;
+
+	ASD(("happy_meal_bb_read: reg=%d ", reg));
+
+	/* Enable the MIF BitBang outputs. */
+	tregs->bb_oenab = 1;
+
+	/* Force BitBang into the idle state. */
+	for(i = 0; i < 32; i++)
+		BB_PUT_BIT(tregs, 1);
+
+	/* Give it the read sequence. */
+	BB_PUT_BIT(tregs, 0);
+	BB_PUT_BIT(tregs, 1);
+	BB_PUT_BIT(tregs, 1);
+	BB_PUT_BIT(tregs, 0);
+
+	/* Give it the PHY address. */
+	tmp = hp->paddr & 0xff;
+	for(i = 4; i >= 0; i--)
+		BB_PUT_BIT(tregs, ((tmp >> i) & 1));
+
+	/* Tell it what register we want to read. */
+	tmp = (reg & 0xff);
+	for(i = 4; i >= 0; i--)
+		BB_PUT_BIT(tregs, ((tmp >> i) & 1));
+
+	/* Close down the MIF BitBang outputs. */
+	tregs->bb_oenab = 0;
+
+	/* Now read in the value. */
+	unused = BB_GET_BIT2(tregs, (hp->tcvr_type == internal));
+	for(i = 15; i >= 0; i--)
+		retval |= BB_GET_BIT2(tregs, (hp->tcvr_type == internal));
+	unused = BB_GET_BIT2(tregs, (hp->tcvr_type == internal));
+	unused = BB_GET_BIT2(tregs, (hp->tcvr_type == internal));
+	unused = BB_GET_BIT2(tregs, (hp->tcvr_type == internal));
+	ASD(("value=%x\n", retval));
+	return retval;
+}
+
+static inline void happy_meal_bb_write(struct happy_meal *hp,
+				       struct hmeal_tcvregs *tregs, int reg,
+				       unsigned short value)
+{
+	unsigned long tmp;
+	int i;
+
+	ASD(("happy_meal_bb_write: reg=%d value=%x\n", reg, value));
+
+	/* Enable the MIF BitBang outputs. */
+	tregs->bb_oenab = 1;
+
+	/* Force BitBang into the idle state. */
+	for(i = 0; i < 32; i++)
+		BB_PUT_BIT(tregs, 1);
+
+	/* Give it write sequence. */
+	BB_PUT_BIT(tregs, 0);
+	BB_PUT_BIT(tregs, 1);
+	BB_PUT_BIT(tregs, 0);
+	BB_PUT_BIT(tregs, 1);
+
+	/* Give it the PHY address. */
+	tmp = (hp->paddr & 0xff);
+	for(i = 4; i >= 0; i--)
+		BB_PUT_BIT(tregs, ((tmp >> i) & 1));
+
+	/* Tell it what register we will be writing. */
+	tmp = (reg & 0xff);
+	for(i = 4; i >= 0; i--)
+		BB_PUT_BIT(tregs, ((tmp >> i) & 1));
+
+	/* Tell it to become ready for the bits. */
+	BB_PUT_BIT(tregs, 1);
+	BB_PUT_BIT(tregs, 0);
+
+	for(i = 15; i >= 0; i--)
+		BB_PUT_BIT(tregs, ((value >> i) & 1));
+
+	/* Close down the MIF BitBang outputs. */
+	tregs->bb_oenab = 0;
+}
+
+#define TCVR_READ_TRIES   16
+
+static inline int happy_meal_tcvr_read(struct happy_meal *hp,
+				       struct hmeal_tcvregs *tregs, int reg)
+{
+	int tries = TCVR_READ_TRIES;
+	int retval;
+
+	ASD(("happy_meal_tcvr_read: reg=0x%02x ", reg));
+	if(hp->tcvr_type == none) {
+		ASD(("no transceiver, value=TCVR_FAILURE\n"));
+		return TCVR_FAILURE;
+	}
+
+	if(!(hp->happy_flags & HFLAG_FENABLE)) {
+		ASD(("doing bit bang\n"));
+		return happy_meal_bb_read(hp, tregs, reg);
+	}
+
+	tregs->frame = (FRAME_READ | (hp->paddr << 23) | ((reg & 0xff) << 18));
+	while(!(tregs->frame & 0x10000) && --tries)
+		udelay(20);
+	if(!tries) {
+		printk("happy meal: Aieee, transceiver MIF read bolixed\n");
+		return TCVR_FAILURE;
+	}
+	retval = tregs->frame & 0xffff;
+	ASD(("value=%04x\n", retval));
+	return retval;
+}
+
+#define TCVR_WRITE_TRIES  16
+
+static inline void happy_meal_tcvr_write(struct happy_meal *hp,
+					 struct hmeal_tcvregs *tregs, int reg,
+					 unsigned short value)
+{
+	int tries = TCVR_WRITE_TRIES;
+	
+	ASD(("happy_meal_tcvr_write: reg=0x%02x value=%04x\n", reg, value));
+
+	/* Welcome to Sun Microsystems, can I take your order please? */
+	if(!hp->happy_flags & HFLAG_FENABLE)
+		return happy_meal_bb_write(hp, tregs, reg, value);
+
+	/* Would you like fries with that? */
+	tregs->frame = (FRAME_WRITE | (hp->paddr << 23) |
+			((reg & 0xff) << 18) | (value & 0xffff));
+	while(!(tregs->frame & 0x10000) && --tries)
+		udelay(20);
+
+	/* Anything else? */
+	if(!tries)
+		printk("happy meal: Aieee, transceiver MIF write bolixed\n");
+
+	/* Fifty-two cents is your change, have a nice day. */
+}
+
+/* Auto negotiation.  The scheme is very simple.  We have a timer routine
+ * that keeps watching the auto negotiation process as it progresses.
+ * The DP83840 is first told to start doing it's thing, we set up the time
+ * and place the timer state machine in it's initial state.
+ *
+ * Here the timer peeks at the DP83840 status registers at each click to see
+ * if the auto negotiation has completed, we assume here that the DP83840 PHY
+ * will time out at some point and just tell us what (didn't) happen.  For
+ * complete coverage we only allow so many of the ticks at this level to run,
+ * when this has expired we print a warning message and try another strategy.
+ * This "other" strategy is to force the interface into various speed/duplex
+ * configurations and we stop when we see a link-up condition before the
+ * maximum number of "peek" ticks have occurred.
+ *
+ * Once a valid link status has been detected we configure the BigMAC and
+ * the rest of the Happy Meal to speak the most efficient protocol we could
+ * get a clean link for.  The priority for link configurations, highest first
+ * is:
+ *                 100 Base-T Full Duplex
+ *                 100 Base-T Half Duplex
+ *                 10 Base-T Full Duplex
+ *                 10 Base-T Half Duplex
+ *
+ * We start a new timer now, after a successful auto negotiation status has
+ * been detected.  This timer just waits for the link-up bit to get set in
+ * the BMCR of the DP83840.  When this occurs we print a kernel log message
+ * describing the link type in use and the fact that it is up.
+ *
+ * If a fatal error of some sort is signalled and detected in the interrupt
+ * service routine, and the chip is reset, or the link is ifconfig'd down
+ * and then back up, this entire process repeats itself all over again.
+ */
+static int try_next_permutation(struct happy_meal *hp, struct hmeal_tcvregs *tregs)
+{
+	hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
+
+	/* Downgrade duplex if full. */
+	if(hp->sw_bmcr & BMCR_FULLDPLX) {
+		hp->sw_bmcr &= ~(BMCR_FULLDPLX);
+		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
+		return 0;
+	}
+
+	/* Downgrade from 100 to 10. */
+	if(hp->sw_bmcr & BMCR_SPEED100) {
+		hp->sw_bmcr &= ~(BMCR_SPEED100);
+		hp->sw_bmcr |= (BMCR_FULLDPLX);
+		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
+		return 0;
+	}
+
+	/* We've tried everything. */
+	return -1;
+}
+
+static void display_link_mode(struct happy_meal *hp, struct hmeal_tcvregs *tregs)
+{
+	printk("%s: Link is up using ", hp->dev->name);
+	if(hp->tcvr_type == external)
+		printk("external ");
+	else
+		printk("internal ");
+	printk("transceiver at ");
+	hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, DP83840_LPA);
+	if(hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) {
+		if(hp->sw_lpa & LPA_100FULL)
+			printk("100Mb/s, Full Duplex.\n");
+		else
+			printk("100Mb/s, Half Duplex.\n");
+	} else {
+		if(hp->sw_lpa & LPA_10FULL)
+			printk("10Mb/s, Full Duplex.\n");
+		else
+			printk("10Mb/s, Half Duplex.\n");
+	}
+}
+
+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);
+	if(hp->tcvr_type == external)
+		printk("external ");
+	else
+		printk("internal ");
+	printk("transceiver at ");
+	hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
+	if(hp->sw_bmcr & BMCR_SPEED100)
+		printk("100Mb/s, ");
+	else
+		printk("10Mb/s, ");
+	if(hp->sw_bmcr & BMCR_FULLDPLX)
+		printk("Full Duplex.\n");
+	else
+		printk("Half Duplex.\n");
+}
+
+static int set_happy_link_modes(struct happy_meal *hp, struct hmeal_tcvregs *tregs)
+{
+	int full;
+
+	/* All we care about is making sure the bigmac tx_cfg has a
+	 * proper duplex setting.
+	 */
+	if(hp->timer_state == lupwait) {
+		hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, DP83840_LPA);
+		if((hp->sw_lpa & LPA_100FULL) ||
+		   (!(hp->sw_lpa & LPA_100HALF) && (hp->sw_lpa & LPA_10FULL)))
+			full = 1;
+		else
+			full = 0;
+	} else {
+		hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
+		if(hp->sw_bmcr & BMCR_FULLDPLX)
+			full = 1;
+		else
+			full = 0;
+	}
+
+	/* XXX This may not be enough, we may need to reinit the entire
+	 * XXX Happy Meal front end for this to work every time.
+	 */
+	if(full)
+		hp->bigmacregs->tx_cfg |= BIGMAC_TXCFG_FULLDPLX;
+	else
+		hp->bigmacregs->tx_cfg &= ~(BIGMAC_TXCFG_FULLDPLX);
+
+	return 0;
+}
+
+static int happy_meal_init(struct happy_meal *hp, int from_irq);
+
+static void happy_meal_timer(unsigned long data)
+{
+	struct happy_meal *hp = (struct happy_meal *) data;
+	struct hmeal_tcvregs *tregs = hp->tcvregs;
+	int restart_timer = 0;
+
+	hp->timer_ticks++;
+	switch(hp->timer_state) {
+	case arbwait:
+		/* Only allow for 5 ticks, thats 10 seconds and much too
+		 * long to wait for arbitration to complete.
+		 */
+		if(hp->timer_ticks >= 10) {
+			/* Enter force mode. */
+	do_force_mode:
+			hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
+			printk("%s: Auto-Negotiation timeout, trying force link "
+			       "mode BMCR=0x%04x.\n", hp->dev->name, hp->sw_bmcr);
+			hp->sw_bmcr &= ~(BMCR_ANRESTART | BMCR_ANENABLE);
+			hp->sw_bmcr |= (BMCR_FULLDPLX | BMCR_ANENABLE);
+			happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
+			hp->timer_state = ltrywait;
+			hp->timer_ticks = 0;
+			restart_timer = 1;
+		} else {
+			/* Anything interesting happen? */
+			hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR);
+			if(hp->sw_bmsr & BMSR_ANEGCOMPLETE) {
+				int ret;
+
+				/* Just what we've been waiting for... */
+				ret = set_happy_link_modes(hp, tregs);
+				if(ret) {
+					/* Ooops, something bad happened, go to force
+					 * mode.
+					 */
+					goto do_force_mode;
+				}
+
+				/* Success, at least so far, advance our state engine. */
+				hp->timer_state = lupwait;
+				restart_timer = 1;
+			} else {
+				restart_timer = 1;
+			}
+		}
+		break;
+
+	case lupwait:
+		/* Auto negotiation was successful and we are awaiting a
+		 * link up status.  I have decided to let this timer run
+		 * forever until some sort of error is signalled, reporting
+		 * a message to the user at 10 second intervals.
+		 */
+		hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR);
+		if(hp->sw_bmsr & BMSR_LSTATUS) {
+			/* Wheee, it's up, display the link mode in use and put
+			 * the timer to sleep.
+			 */
+			display_link_mode(hp, tregs);
+			hp->timer_state = asleep;
+			restart_timer = 0;
+		} else {
+			if(hp->timer_ticks >= 10) {
+				printk("%s: Auto negotiation successful, link still "
+				       "not completely up.\n", hp->dev->name);
+				hp->timer_ticks = 0;
+				restart_timer = 1;
+			} else {
+				restart_timer = 1;
+			}
+		}
+		break;
+
+	case ltrywait:
+		/* Making the timeout here too long can make it take
+		 * annoyingly long to attempt all of the link mode
+		 * permutations, but then again this is essentially
+		 * error recovery code for the most part.
+		 */
+		hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR);
+		if(hp->sw_bmsr & BMSR_LSTATUS) {
+			/* Force mode selection success. */
+			display_forced_link_mode(hp, tregs);
+			set_happy_link_modes(hp, tregs); /* XXX error? then what? */
+			hp->timer_state = asleep;
+			restart_timer = 0;
+		} else {
+			if(hp->timer_ticks >= 3) { /* 6 seconds or so... */
+				int ret;
+
+				ret = try_next_permutation(hp, tregs);
+				if(ret == -1) {
+					/* Aieee, tried them all, reset the
+					 * chip and try all over again.
+					 */
+
+					/* Let the user know... */
+					printk("%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 "
+						       "Happy Meal.\n", hp->dev->name);
+					}
+					return;
+				}
+				hp->timer_ticks = 0;
+				restart_timer = 1;
+			} else {
+				restart_timer = 1;
+			}
+		}
+		break;
+
+	case asleep:
+	default:
+		/* Can't happens.... */
+		printk("%s: Aieee, link timer is asleep but we got one anyways!\n",
+		       hp->dev->name);
+		restart_timer = 0;
+		hp->timer_ticks = 0;
+		hp->timer_state = asleep; /* foo on you */
+		break;
+	};
+
+	if(restart_timer) {
+		hp->happy_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2 sec. */
+		add_timer(&hp->happy_timer);
+	}
+}
+
+#define TX_RESET_TRIES     32
+#define RX_RESET_TRIES     32
+
+static inline void happy_meal_tx_reset(struct hmeal_bigmacregs *bregs)
+{
+	int tries = TX_RESET_TRIES;
+
+	HMD(("happy_meal_tx_reset: reset, "));
+
+	/* Would you like to try our SMCC Delux? */
+	bregs->tx_swreset = 0;
+	while((bregs->tx_swreset & 1) && --tries)
+		udelay(20);
+
+	/* Lettuce, tomato, buggy hardware (no extra charge)? */
+	if(!tries)
+		printk("happy meal: Transceiver BigMac ATTACK!");
+
+	/* Take care. */
+	HMD(("done\n"));
+}
+
+static inline void happy_meal_rx_reset(struct hmeal_bigmacregs *bregs)
+{
+	int tries = RX_RESET_TRIES;
+
+	HMD(("happy_meal_rx_reset: reset, "));
+
+	/* We have a special on GNU/Viking hardware bugs today. */
+	bregs->rx_swreset = 0;
+	while((bregs->rx_swreset & 1) && --tries)
+		udelay(20);
+
+	/* Will that be all? */
+	if(!tries)
+		printk("happy meal: Receiver BigMac ATTACK!");
+
+	/* Don't forget your vik_1137125_wa.  Have a nice day. */
+	HMD(("done\n"));
+}
+
+#define STOP_TRIES         16
+
+static inline void happy_meal_stop(struct hmeal_gregs *gregs)
+{
+	int tries = STOP_TRIES;
+
+	HMD(("happy_meal_stop: reset, "));
+
+	/* We're consolidating our STB products, it's your lucky day. */
+	gregs->sw_reset = GREG_RESET_ALL;
+	while(gregs->sw_reset && --tries)
+		udelay(20);
+
+	/* Come back next week when we are "Sun Microelectronics". */
+	if(!tries)
+		printk("happy meal: Fry guys.");
+
+	/* Remember: "Different name, same old buggy as shit hardware." */
+	HMD(("done\n"));
+}
+
+static void happy_meal_get_counters(struct happy_meal *hp,
+				    struct hmeal_bigmacregs *bregs)
+{
+	struct enet_statistics *stats = &hp->enet_stats;
+
+	stats->rx_crc_errors += bregs->rcrce_ctr;
+	bregs->rcrce_ctr = 0;
+
+	stats->rx_frame_errors += bregs->unale_ctr;
+	bregs->unale_ctr = 0;
+
+	stats->rx_length_errors += bregs->gle_ctr;
+	bregs->gle_ctr = 0;
+
+	stats->tx_aborted_errors += bregs->ex_ctr;
+
+	stats->collisions += (bregs->ex_ctr + bregs->lt_ctr);
+	bregs->ex_ctr = bregs->lt_ctr = 0;
+}
+
+static inline void happy_meal_poll_start(struct happy_meal *hp,
+					 struct hmeal_tcvregs *tregs)
+{
+	unsigned long tmp;
+	int speed;
+
+	ASD(("happy_meal_poll_start: "));
+	if(!(hp->happy_flags & HFLAG_POLLENABLE)) {
+		HMD(("polling disabled, return\n"));
+		return;
+	}
+
+	/* Start the MIF polling on the external transceiver. */
+	ASD(("polling on, "));
+	tmp = tregs->cfg;
+	tmp &= ~(TCV_CFG_PDADDR | TCV_CFG_PREGADDR);
+	tmp |= ((hp->paddr & 0x1f) << 10);
+	tmp |= (TCV_PADDR_ETX << 3);
+	tmp |= TCV_CFG_PENABLE;
+	tregs->cfg = tmp;
+
+	/* Let the bits set. */
+	udelay(200);
+
+	/* We are polling now. */
+	ASD(("now polling, "));
+	hp->happy_flags |= HFLAG_POLL;
+
+	/* Clear the poll flags, get the basic status as of now. */
+	hp->poll_flag = 0;
+	hp->poll_data = tregs->status >> 16;
+
+	if(hp->happy_flags & HFLAG_AUTO)
+		speed = hp->auto_speed;
+	else
+		speed = hp->forced_speed;
+
+	/* Listen only for the MIF interrupts we want to hear. */
+	ASD(("mif ints on, "));
+	if(speed == 100)
+		tregs->int_mask = 0xfffb;
+	else
+		tregs->int_mask = 0xfff9;
+	ASD(("done\n"));
+}
+
+static inline void happy_meal_poll_stop(struct happy_meal *hp,
+					struct hmeal_tcvregs *tregs)
+{
+	ASD(("happy_meal_poll_stop: "));
+
+	/* If polling disabled or not polling already, nothing to do. */
+	if((hp->happy_flags & (HFLAG_POLLENABLE | HFLAG_POLL)) !=
+	   (HFLAG_POLLENABLE | HFLAG_POLL)) {
+		HMD(("not polling, return\n"));
+		return;
+	}
+
+	/* Shut up the MIF. */
+	ASD(("were polling, mif ints off, "));
+	tregs->int_mask = 0xffff;
+
+	/* Turn off polling. */
+	ASD(("polling off, "));
+	tregs->cfg &= ~(TCV_CFG_PENABLE);
+
+	/* We are no longer polling. */
+	hp->happy_flags &= ~(HFLAG_POLL);
+
+	/* Let the bits set. */
+	udelay(200);
+	ASD(("done\n"));
+}
+
+/* Only Sun can take such nice parts and fuck up the programming interface
+ * like this.  Good job guys...
+ */
+#define TCVR_RESET_TRIES       16 /* It should reset quickly        */
+#define TCVR_UNISOLATE_TRIES   32 /* Dis-isolation can take longer. */
+
+static int happy_meal_tcvr_reset(struct happy_meal *hp,
+				 struct hmeal_tcvregs *tregs)
+{
+	unsigned long tconfig;
+	int result, tries = TCVR_RESET_TRIES;
+
+	tconfig = tregs->cfg;
+	ASD(("happy_meal_tcvr_reset: tcfg<%08lx> ", tconfig));
+	if(hp->tcvr_type == external) {
+		ASD(("external<"));
+		tregs->cfg = tconfig & ~(TCV_CFG_PSELECT);
+		hp->tcvr_type = internal;
+		hp->paddr = TCV_PADDR_ITX;
+		ASD(("ISOLATE,"));
+		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR,
+				      (BMCR_LOOPBACK|BMCR_PDOWN|BMCR_ISOLATE));
+		result = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
+		if(result == TCVR_FAILURE) {
+			ASD(("phyread_fail>\n"));
+			return -1;
+		}
+		ASD(("phyread_ok,PSELECT>"));
+		tregs->cfg = tconfig | TCV_CFG_PSELECT;
+		hp->tcvr_type = external;
+		hp->paddr = TCV_PADDR_ETX;
+	} else {
+		if(tconfig & TCV_CFG_MDIO1) {
+			ASD(("internal<PSELECT,"));
+			tregs->cfg = (tconfig | TCV_CFG_PSELECT);
+			ASD(("ISOLATE,"));
+			happy_meal_tcvr_write(hp, tregs, DP83840_BMCR,
+					      (BMCR_LOOPBACK|BMCR_PDOWN|BMCR_ISOLATE));
+			result = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
+			if(result == TCVR_FAILURE) {
+				ASD(("phyread_fail>\n"));
+				return -1;
+			}
+			ASD(("phyread_ok,~PSELECT>"));
+			tregs->cfg = (tconfig & ~(TCV_CFG_PSELECT));
+			hp->tcvr_type = internal;
+			hp->paddr = TCV_PADDR_ITX;
+		}
+	}
+
+	ASD(("BMCR_RESET "));
+	happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, BMCR_RESET);
+
+	while(--tries) {
+		result = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
+		if(result == TCVR_FAILURE)
+			return -1;
+		hp->sw_bmcr = result;
+		if(!(result & BMCR_RESET))
+			break;
+		udelay(20);
+	}
+	if(!tries) {
+		ASD(("BMCR RESET FAILED!\n"));
+		return -1;
+	}
+	ASD(("RESET_OK\n"));
+
+	/* Get fresh copies of the PHY registers. */
+	hp->sw_bmsr      = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR);
+	hp->sw_physid1   = happy_meal_tcvr_read(hp, tregs, DP83840_PHYSID1);
+	hp->sw_physid2   = happy_meal_tcvr_read(hp, tregs, DP83840_PHYSID2);
+	hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, DP83840_ADVERTISE);
+
+	ASD(("UNISOLATE"));
+	hp->sw_bmcr &= ~(BMCR_ISOLATE);
+	happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
+
+	tries = TCVR_UNISOLATE_TRIES;
+	while(--tries) {
+		result = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
+		if(result == TCVR_FAILURE)
+			return -1;
+		if(!(result & BMCR_ISOLATE))
+			break;
+		udelay(20);
+	}
+	if(!tries) {
+		ASD((" FAILED!\n"));
+		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));
+	return 0;
+}
+
+/* Figure out whether we have an internal or external transceiver. */
+static void happy_meal_transceiver_check(struct happy_meal *hp,
+					 struct hmeal_tcvregs *tregs)
+{
+	unsigned long tconfig = tregs->cfg;
+
+	ASD(("happy_meal_transceiver_check: tcfg=%08lx ", tconfig));
+	if(hp->happy_flags & HFLAG_POLL) {
+		/* If we are polling, we must stop to get the transceiver type. */
+		ASD(("<polling> "));
+		if(hp->tcvr_type == internal) {
+			if(tconfig & TCV_CFG_MDIO1) {
+				ASD(("<internal> <poll stop> "));
+				happy_meal_poll_stop(hp, tregs);
+				hp->paddr = TCV_PADDR_ETX;
+				hp->tcvr_type = external;
+				ASD(("<external>\n"));
+				tconfig &= ~(TCV_CFG_PENABLE);
+				tconfig |= TCV_CFG_PSELECT;
+				tregs->cfg = tconfig;
+			}
+		} else {
+			if(hp->tcvr_type == external) {
+				ASD(("<external> "));
+				if(!(tregs->status >> 16)) {
+					ASD(("<poll stop> "));
+					happy_meal_poll_stop(hp, tregs);
+					hp->paddr = TCV_PADDR_ITX;
+					hp->tcvr_type = internal;
+					ASD(("<internal>\n"));
+					tregs->cfg &= ~(TCV_CFG_PSELECT);
+				}
+				ASD(("\n"));
+			} else {
+				ASD(("<none>\n"));
+			}
+		}
+	} else {
+		unsigned long reread = tregs->cfg;
+
+		/* Else we can just work off of the MDIO bits. */
+		ASD(("<not polling> "));
+		if(reread & TCV_CFG_MDIO1) {
+			tregs->cfg = tconfig | TCV_CFG_PSELECT;
+			hp->paddr = TCV_PADDR_ETX;
+			hp->tcvr_type = external;
+			ASD(("<external>\n"));
+		} else {
+			if(reread & TCV_CFG_MDIO0) {
+				tregs->cfg = tconfig & ~(TCV_CFG_PSELECT);
+				hp->paddr = TCV_PADDR_ITX;
+				hp->tcvr_type = internal;
+				ASD(("<internal>\n"));
+			} else {
+				printk("happy meal: Transceiver and a coke please.");
+				hp->tcvr_type = none; /* Grrr... */
+				ASD(("<none>\n"));
+			}
+		}
+	}
+}
+
+/* The receive ring buffers are a bit tricky to get right.  Here goes...
+ *
+ * The buffers we dma into must be 64 byte aligned.  So we use a special
+ * alloc_skb() routine for the happy meal to allocate 64 bytes more than
+ * we really need.
+ *
+ * We use skb_reserve() to align the data block we get in the skb.  We
+ * also program the etxregs->cfg register to use an offset of 2.  This
+ * imperical constant plus the ethernet header size will always leave
+ * us with a nicely aligned ip header once we pass things up to the
+ * protocol layers.
+ *
+ * The numbers work out to:
+ *
+ *         Max ethernet frame size         1518
+ *         Ethernet header size              14
+ *         Happy Meal base offset             2
+ *
+ * Say a skb data area is at 0xf001b010, and its size alloced is
+ * (ETH_FRAME_LEN + 64 + 2) = (1514 + 64 + 2) = 1580 bytes.
+ *
+ * First our alloc_skb() routine aligns the data base to a 64 byte
+ * boundry.  We now have 0xf001b040 as our skb data address.  We
+ * plug this into the receive descriptor address.
+ *
+ * Next, we skb_reserve() 2 bytes to account for the Happy Meal offset.
+ * So now the data we will end up looking at starts at 0xf001b042.  When
+ * the packet arrives, we will check out the size received and subtract
+ * this from the skb->length.  Then we just pass the packet up to the
+ * protocols as is, and allocate a new skb to replace this slot we have
+ * just received from.
+ *
+ * The ethernet layer will strip the ether header from the front of the
+ * skb we just sent to it, this leaves us with the ip header sitting
+ * nicely aligned at 0xf001b050.  Also, for tcp and udp packets the
+ * Happy Meal has even checksummed the tcp/udp data for us.  The 16
+ * bit checksum is obtained from the low bits of the receive descriptor
+ * flags, thus:
+ *
+ * 	skb->csum = rxd->rx_flags & 0xffff;
+ * 	skb->ip_summed = CHECKSUM_HW;
+ *
+ * before sending off the skb to the protocols, and we are good as gold.
+ */
+static inline void happy_meal_clean_rings(struct happy_meal *hp)
+{
+	int i;
+
+	for(i = 0; i < RX_RING_SIZE; i++) {
+		if(hp->rx_skbs[i] != NULL) {
+			dev_kfree_skb(hp->rx_skbs[i], FREE_READ);
+			hp->rx_skbs[i] = NULL;
+		}
+	}
+
+	for(i = 0; i < TX_RING_SIZE; i++) {
+		if(hp->tx_skbs[i] != NULL) {
+			dev_kfree_skb(hp->tx_skbs[i], FREE_WRITE);
+			hp->tx_skbs[i] = NULL;
+		}
+	}
+}
+
+static void happy_meal_init_rings(struct happy_meal *hp, int from_irq)
+{
+	struct hmeal_init_block *hb = hp->happy_block;
+	struct device *dev = hp->dev;
+	int i, gfp_flags = GFP_KERNEL;
+
+	if(from_irq || intr_count)
+		gfp_flags = GFP_ATOMIC;
+
+	HMD(("happy_meal_init_rings: counters to zero, "));
+	hp->rx_new = hp->rx_old = hp->tx_new = hp->tx_old = 0;
+
+	/* Free any skippy bufs left around in the rings. */
+	HMD(("clean, "));
+	happy_meal_clean_rings(hp);
+
+	/* Now get new skippy bufs for the receive ring. */
+	HMD(("init rxring, "));
+	for(i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb;
+
+		skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags);
+		if(!skb)
+			continue;
+		hp->rx_skbs[i] = skb;
+		skb->dev = dev;
+
+		/* Because we reserve afterwards. */
+		skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET));
+
+		hb->happy_meal_rxd[i].rx_addr = (unsigned int) skb->data;
+		skb_reserve(skb, RX_OFFSET);
+		hb->happy_meal_rxd[i].rx_flags =
+			(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
+	}
+
+	HMD(("init txring, "));
+	for(i = 0; i < TX_RING_SIZE; i++)
+		hb->happy_meal_txd[i].tx_flags = 0;
+	HMD(("done\n"));
+}
+
+static void sun4c_happy_meal_init_rings(struct happy_meal *hp)
+{
+	struct hmeal_init_block *hb = hp->happy_block;
+	struct hmeal_buffers *hbufs = hp->sun4c_buffers;
+	int i;
+
+	HMD(("happy_meal_init_rings: counters to zero, "));
+	hp->rx_new = hp->rx_old = hp->tx_new = hp->tx_old = 0;
+
+	HMD(("init rxring, "));
+	for(i = 0; i < RX_RING_SIZE; i++) {
+		unsigned char *this_buf = &hbufs->rx_buf[i][0];
+
+		hb->happy_meal_rxd[i].rx_addr = (unsigned int) this_buf;
+		hb->happy_meal_rxd[i].rx_flags =
+			(RXFLAG_OWN | ((SUN4C_RX_BUFF_SIZE - RX_OFFSET) << 16));
+	}
+
+	HMD(("init txring, "));
+	for(i = 0; i < TX_RING_SIZE; i++)
+		hb->happy_meal_txd[i].tx_flags = 0;
+	HMD(("done\n"));
+}
+
+static void happy_meal_begin_auto_negotiation(struct happy_meal *hp,
+					      struct hmeal_tcvregs *tregs)
+{
+	int timeout;
+
+	/* Read all of the registers we are interested in now. */
+	hp->sw_bmsr      = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR);
+	hp->sw_bmcr      = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
+	hp->sw_physid1   = happy_meal_tcvr_read(hp, tregs, DP83840_PHYSID1);
+	hp->sw_physid2   = happy_meal_tcvr_read(hp, tregs, DP83840_PHYSID2);
+	hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, DP83840_ADVERTISE);
+
+	/* XXX Check BMSR_ANEGCAPABLE, should not be necessary though. */
+
+	/* Advertise everything we can support. */
+	if(hp->sw_bmsr & BMSR_10HALF)
+		hp->sw_advertise |= (ADVERTISE_10HALF);
+	else
+		hp->sw_advertise &= ~(ADVERTISE_10HALF);
+
+	if(hp->sw_bmsr & BMSR_10FULL)
+		hp->sw_advertise |= (ADVERTISE_10FULL);
+	else
+		hp->sw_advertise &= ~(ADVERTISE_10FULL);
+	if(hp->sw_bmsr & BMSR_100HALF)
+		hp->sw_advertise |= (ADVERTISE_100HALF);
+	else
+		hp->sw_advertise &= ~(ADVERTISE_100HALF);
+	if(hp->sw_bmsr & BMSR_100FULL)
+		hp->sw_advertise |= (ADVERTISE_100FULL);
+	else
+		hp->sw_advertise &= ~(ADVERTISE_100FULL);
+
+	/* XXX Currently no Happy Meal cards I know off support 100BaseT4,
+	 * XXX and this is because the DP83840 does not support it, changes
+	 * XXX would need to be made to the tx/rx logic in the driver as well
+	 * XXX so I completely skip checking for it in the BMSR for now.
+	 */
+
+#ifdef AUTO_SWITCH_DEBUG
+	ASD(("%s: Advertising [ ", hp->dev->name));
+	if(hp->sw_advertise & ADVERTISE_10HALF)
+		ASD(("10H "));
+	if(hp->sw_advertise & ADVERTISE_10FULL)
+		ASD(("10F "));
+	if(hp->sw_advertise & ADVERTISE_100HALF)
+		ASD(("100H "));
+	if(hp->sw_advertise & ADVERTISE_100FULL)
+		ASD(("100F "));
+#endif
+
+	happy_meal_tcvr_write(hp, tregs, DP83840_ADVERTISE, hp->sw_advertise);
+
+	/* Enable Auto-Negotiation, this is usually on already... */
+	hp->sw_bmcr |= BMCR_ANENABLE;
+	happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
+
+	/* Restart it to make sure it is going. */
+	hp->sw_bmcr |= BMCR_ANRESTART;
+	happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
+
+	/* BMCR_ANRESTART self clears when the process has begun. */
+
+	timeout = 64;  /* More than enough. */
+	while(--timeout) {
+		hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, DP83840_BMCR);
+		if(!(hp->sw_bmcr & BMCR_ANRESTART))
+			break; /* got it. */
+		udelay(10);
+	}
+	if(!timeout) {
+		printk("%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", hp->dev->name);
+
+		/* Disable auto-negotiation in BMCR, enable FULL duplex and 100mb/s,
+		 * setup the timer state machine, and fire it off.
+		 *
+		 * XXX Should probably reset the DP83840 first
+		 * XXX as this is a gross fatal error...
+		 */
+		hp->sw_bmcr &= ~(BMCR_ANRESTART | BMCR_ANENABLE);
+		hp->sw_bmcr |= (BMCR_FULLDPLX | BMCR_SPEED100);
+		happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
+		hp->timer_state = ltrywait;
+	} else {
+		hp->timer_state = arbwait;
+	}
+
+	hp->timer_ticks = 0;
+	hp->happy_timer.expires = jiffies + (12 * HZ)/10;  /* 1.2 sec. */
+	hp->happy_timer.data = (unsigned long) hp;
+	hp->happy_timer.function = &happy_meal_timer;
+	add_timer(&hp->happy_timer);
+}
+
+static int happy_meal_init(struct happy_meal *hp, int from_irq)
+{
+	struct hmeal_gregs   *gregs        = hp->gregs;
+	struct hmeal_etxregs *etxregs      = hp->etxregs;
+	struct hmeal_erxregs *erxregs      = hp->erxregs;
+	struct hmeal_bigmacregs *bregs     = hp->bigmacregs;
+	struct hmeal_tcvregs *tregs        = hp->tcvregs;
+	unsigned long regtmp;
+	unsigned char *e = &hp->dev->dev_addr[0];
+
+	HMD(("happy_meal_init: "));
+	if(!(hp->happy_flags & HFLAG_INIT)) {
+		HMD(("set HFLAG_INIT, "));
+		hp->happy_flags |= HFLAG_INIT;
+		happy_meal_get_counters(hp, bregs);
+	}
+
+	/* Stop polling. */
+	HMD(("to happy_meal_poll_stop\n"));
+	happy_meal_poll_stop(hp, tregs);
+
+	/* Stop transmitter and receiver. */
+	HMD(("happy_meal_init: to happy_meal_stop\n"));
+	happy_meal_stop(gregs);
+
+	/* Alloc and reset the tx/rx descriptor chains. */
+	HMD(("happy_meal_init: to happy_meal_init_rings\n"));
+	if(sparc_cpu_model == sun4c)
+		sun4c_happy_meal_init_rings(hp);
+	else
+		happy_meal_init_rings(hp, from_irq);
+
+	/* Shut up the MIF. */
+	HMD(("happy_meal_init: Disable all MIF irqs, "));
+	tregs->int_mask = 0xffff;
+
+	/* See if we can enable the MIF frame on this card to speak to the DP83840. */
+	if(hp->happy_flags & HFLAG_FENABLE) {
+		HMD(("use frame, "));
+		tregs->cfg &= ~(TCV_CFG_BENABLE);
+	} else {
+		HMD(("use bitbang, "));
+		tregs->cfg |= TCV_CFG_BENABLE;
+	}
+
+	/* Check the state of the transceiver. */
+	HMD(("to happy_meal_transceiver_check\n"));
+	happy_meal_transceiver_check(hp, tregs);
+
+	/* Put the Big Mac into a sane state. */
+	HMD(("happy_meal_init: "));
+	switch(hp->tcvr_type) {
+	case none:
+		/* Cannot operate if we don't know the transceiver type! */
+		HMD(("AAIEEE no transceiver type, EAGAIN"));
+		return -EAGAIN;
+
+	case internal:
+		/* Using the MII buffers. */
+		HMD(("internal, using MII, "));
+		bregs->xif_cfg = 0;
+		break;
+
+	case external:
+		/* Not using the MII, disable it. */
+		HMD(("external, disable MII, "));
+		bregs->xif_cfg = BIGMAC_XCFG_MIIDISAB;
+		break;
+	};
+
+	if(happy_meal_tcvr_reset(hp, tregs))
+		return -EAGAIN;
+
+	/* Reset the Happy Meal Big Mac transceiver and the receiver. */
+	HMD(("tx/rx reset, "));
+	happy_meal_tx_reset(bregs);
+	happy_meal_rx_reset(bregs);
+
+	/* Set jam size and inter-packet gaps to reasonable defaults. */
+	HMD(("jsize/ipg1/ipg2, "));
+	bregs->jsize     = DEFAULT_JAMSIZE;
+	bregs->ipkt_gap1 = DEFAULT_IPG1;
+	bregs->ipkt_gap2 = DEFAULT_IPG2;
+
+	/* Load up the MAC address and random seed. */
+	HMD(("rseed/macaddr, "));
+
+	/* XXX use something less deterministic... */
+	bregs->rand_seed = 0xbd;
+
+	bregs->mac_addr2 = ((e[4] << 8) | e[5]);
+	bregs->mac_addr1 = ((e[2] << 8) | e[3]);
+	bregs->mac_addr0 = ((e[0] << 8) | e[1]);
+
+	/* Ick, figure out how to properly program the hash table later... */
+	HMD(("htable, "));
+	bregs->htable3 = 0;
+	bregs->htable2 = 0;
+	bregs->htable1 = 0;
+	bregs->htable0 = 0;
+
+	/* Set the RX and TX ring ptrs. */
+	HMD(("ring ptrs\n"));
+	erxregs->rx_ring = (unsigned long) &hp->happy_block->happy_meal_rxd[0];
+	etxregs->tx_ring = (unsigned long) &hp->happy_block->happy_meal_txd[0];
+
+	/* Set the supported SBUS burst sizes. */
+	HMD(("happy_meal_init: bursts<"));
+
+#if 0 /* XXX take down huahaga and debug this... */
+	/* Grrr... */
+	if(hp->happy_bursts & DMA_BURST64) {
+		HMD(("64>"));
+		gregs->cfg = GREG_CFG_BURST64;
+	} else
+#endif
+	if(hp->happy_bursts & DMA_BURST32) {
+		HMD(("32>"));
+		gregs->cfg = GREG_CFG_BURST32;
+	} else if(hp->happy_bursts & DMA_BURST16) {
+		HMD(("16>"));
+		gregs->cfg = GREG_CFG_BURST16;
+	} else {
+		HMD(("XXX>"));
+		gregs->cfg = 0;
+	}
+
+	/* Turn off interrupts we do not want to hear. */
+	HMD((", enable global interrupts, "));
+	gregs->imask = (GREG_IMASK_GOTFRAME | GREG_IMASK_RCNTEXP |
+			GREG_IMASK_SENTFRAME | GREG_IMASK_TXPERR);
+
+	/* Set the transmit ring buffer size. */
+	HMD(("tx rsize=%d, ", (int)TX_RING_SIZE));
+	etxregs->tx_rsize = (TX_RING_SIZE >> ETX_RSIZE_SHIFT) - 1;
+
+	/* Enable transmitter DVMA. */
+	HMD(("tx dma enable, "));
+	etxregs->cfg |= ETX_CFG_DMAENABLE;
+
+	/* This chip really rots, for the receiver sometimes when you
+	 * write to it's control registers not all the bits get there
+	 * properly.  I cannot think of a sane way to provide complete
+	 * coverage for this hardware bug yet.
+	 */
+	HMD(("erx regs bug\n"));
+	erxregs->cfg = ERX_CFG_DEFAULT(RX_OFFSET);
+	regtmp = erxregs->cfg;
+	erxregs->cfg = ERX_CFG_DEFAULT(RX_OFFSET);
+	if(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",
+		       ERX_CFG_DEFAULT(RX_OFFSET), regtmp);
+		/* XXX Should return failure here... */
+	}
+
+	/* Enable Big Mac hash table filter. */
+	HMD(("happy_meal_init: enable hash, "));
+	bregs->rx_cfg = BIGMAC_RXCFG_HENABLE;
+
+	/* Let the bits settle in the chip. */
+	udelay(10);
+
+	/* Ok, configure the Big Mac transmitter. */
+	HMD(("BIGMAC init, "));
+	regtmp = 0;
+	if(hp->happy_flags & HFLAG_FULL)
+		regtmp |= BIGMAC_TXCFG_FULLDPLX;
+	bregs->tx_cfg = regtmp | BIGMAC_TXCFG_DGIVEUP;
+
+	/* Enable the output drivers no matter what. */
+	regtmp = BIGMAC_XCFG_ODENABLE;
+
+	/* If card can do lance mode, enable it. */
+	if(hp->happy_flags & HFLAG_LANCE)
+		regtmp |= (DEFAULT_IPG0 << 5) | BIGMAC_XCFG_LANCE;
+
+	/* Disable the MII buffers if using external transceiver. */
+	if(hp->tcvr_type == external)
+		regtmp |= BIGMAC_XCFG_MIIDISAB;
+
+	HMD(("XIF config, "));
+	bregs->xif_cfg = regtmp;
+
+	/* Start things up. */
+	HMD(("tx and rx ON!\n"));
+	bregs->tx_cfg |= BIGMAC_TXCFG_ENABLE;
+	bregs->rx_cfg |= BIGMAC_RXCFG_ENABLE;
+
+	/* Get the autonegotiation started, and the watch timer ticking. */
+	happy_meal_begin_auto_negotiation(hp, tregs);
+
+	/* Success. */
+	return 0;
+}
+
+static void happy_meal_set_initial_advertisement(struct happy_meal *hp)
+{
+	struct hmeal_tcvregs *tregs	= hp->tcvregs;
+	struct hmeal_bigmacregs *bregs	= hp->bigmacregs;
+	struct hmeal_gregs *gregs	= hp->gregs;
+
+	happy_meal_stop(gregs);
+	tregs->int_mask = 0xffff;
+	if(hp->happy_flags & HFLAG_FENABLE)
+		tregs->cfg &= ~(TCV_CFG_BENABLE);
+	else
+		tregs->cfg |= TCV_CFG_BENABLE;
+	happy_meal_transceiver_check(hp, tregs);
+	switch(hp->tcvr_type) {
+	case none:
+		return;
+	case internal:
+		bregs->xif_cfg = 0;
+		break;
+	case external:
+		bregs->xif_cfg = BIGMAC_XCFG_MIIDISAB;
+		break;
+	};
+	if(happy_meal_tcvr_reset(hp, tregs))
+		return;
+
+	/* Latch PHY registers as of now. */
+	hp->sw_bmsr      = happy_meal_tcvr_read(hp, tregs, DP83840_BMSR);
+	hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, DP83840_ADVERTISE);
+
+	/* Advertise everything we can support. */
+	if(hp->sw_bmsr & BMSR_10HALF)
+		hp->sw_advertise |= (ADVERTISE_10HALF);
+	else
+		hp->sw_advertise &= ~(ADVERTISE_10HALF);
+
+	if(hp->sw_bmsr & BMSR_10FULL)
+		hp->sw_advertise |= (ADVERTISE_10FULL);
+	else
+		hp->sw_advertise &= ~(ADVERTISE_10FULL);
+	if(hp->sw_bmsr & BMSR_100HALF)
+		hp->sw_advertise |= (ADVERTISE_100HALF);
+	else
+		hp->sw_advertise &= ~(ADVERTISE_100HALF);
+	if(hp->sw_bmsr & BMSR_100FULL)
+		hp->sw_advertise |= (ADVERTISE_100FULL);
+	else
+		hp->sw_advertise &= ~(ADVERTISE_100FULL);
+
+	/* Update the PHY advertisement register. */
+	happy_meal_tcvr_write(hp, tregs, DP83840_ADVERTISE, hp->sw_advertise);
+}
+
+/* Once status is latched (by happy_meal_interrupt) it is cleared by
+ * the hardware, so we cannot re-read it and get a correct value.
+ */
+static int happy_meal_is_not_so_happy(struct happy_meal *hp,
+				      struct hmeal_gregs *gregs,
+				      unsigned long status)
+{
+	int reset = 0;
+
+	printk("%s: Error interrupt for happy meal, status = %08lx\n",
+	       hp->dev->name, status);
+
+	if(status &
+	   (GREG_STAT_RCNTEXP|GREG_STAT_ACNTEXP|GREG_STAT_CCNTEXP|GREG_STAT_LCNTEXP)) {
+		/* Some stupid counter expired, we should be not
+		 * have interrupts for this enabled, but we check
+		 * for it anyways.
+		 */
+
+		printk("%s: Happy Meal counters expired [ ", hp->dev->name);
+		if(status & GREG_STAT_RCNTEXP)
+			printk("ReceiveFrame ");
+		if(status & GREG_STAT_ACNTEXP)
+			printk("AlignError ");
+		if(status & GREG_STAT_CCNTEXP)
+			printk("CrcError ");
+		if(status & GREG_STAT_LCNTEXP)
+			printk("LengthError ");
+		printk("]\n");
+	}
+
+	if(status & GREG_STAT_RFIFOVF) {
+		/* The receive FIFO overflowwed, usually a DMA error. */
+		printk("%s: Happy Meal receive FIFO overflow.\n", hp->dev->name);
+		reset = 1;
+	}
+
+	if(status & GREG_STAT_CVCNTEXP) {
+		/* See above about counter expiration... */
+		printk("%s: Code Violation error counter expired.\n", hp->dev->name);
+	}
+
+	if(status & GREG_STAT_STSTERR) {
+		/* BigMAC SQE link test failed. */
+		printk("%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",
+		       hp->dev->name);
+		reset = 1;
+	}
+
+	if(status & GREG_STAT_MAXPKTERR) {
+		/* Driver error, tried to transmit something larger
+		 * than ethernet max mtu.
+		 */
+		printk("%s: Happy Meal MAX Packet size error.\n", hp->dev->name);
+		reset = 1;
+	}
+
+	if(status & (GREG_STAT_NCNTEXP|GREG_STAT_ECNTEXP|GREG_STAT_LCCNTEXP|
+		     GREG_STAT_FCNTEXP)) {
+		/* More stupid error counters... */
+		printk("%s: Happy Meal counters expired [ ", hp->dev->name);
+		if(status & GREG_STAT_NCNTEXP)
+			printk("NormalCollision ");
+		if(status & GREG_STAT_ECNTEXP)
+			printk("ExcessCollision ");
+		if(status & GREG_STAT_LCCNTEXP)
+			printk("LateCollision ");
+		if(status & GREG_STAT_FCNTEXP)
+			printk("FirstCollision ");
+		printk("]\n");
+	}
+
+	if(status & GREG_STAT_DTIMEXP) {
+		/* Defer-timer expired.  Probably means the happy meal needed
+		 * to back off too much before it could transmit one frame.
+		 */
+		printk("%s: Transmit defer timer expired, subnet congested?\n",
+		       hp->dev->name);
+		reset = 1;
+	}
+
+	if(status & GREG_STAT_NORXD) {
+		/* AIEEE, out of receive descriptors.  Check out our drop
+		 * processing in happy_meal_rx to see how we try very hard
+		 * to avoid this situation.
+		 */
+		printk("%s: Happy Meal out of receive descriptors, aieee!\n",
+		       hp->dev->name);
+		reset = 1;
+	}
+
+	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);
+		if(status & GREG_STAT_RXERR)
+			printk("GenericError ");
+		if(status & GREG_STAT_RXPERR)
+			printk("ParityError ");
+		if(status & GREG_STAT_RXTERR)
+			printk("RxTagBotch ");
+		printk("]\n");
+		reset = 1;
+	}
+
+	if(status & GREG_STAT_EOPERR) {
+		/* 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",
+		       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);
+	}
+
+	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);
+		if(status & GREG_STAT_TXEACK)
+			printk("GenericError ");
+		if(status & GREG_STAT_TXLERR)
+			printk("LateError ");
+		if(status & GREG_STAT_TXPERR)
+			printk("ParityErro ");
+		if(status & GREG_STAT_TXTERR)
+			printk("TagBotch ");
+		printk("]\n");
+		reset = 1;
+	}
+
+	if(status & (GREG_STAT_SLVERR|GREG_STAT_SLVPERR)) {
+		/* 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",
+		       hp->dev->name,
+		       (status & GREG_STAT_SLVPERR) ? "parity" : "generic");
+		reset = 1;
+	}
+
+	if(reset) {
+		printk("%s: Resetting...\n", hp->dev->name);
+		happy_meal_init(hp, 1);
+		return 1;
+	}
+	return 0;
+}
+
+static inline void happy_meal_mif_interrupt(struct happy_meal *hp,
+					    struct hmeal_gregs *gregs,
+					    struct hmeal_tcvregs *tregs)
+{
+	printk("%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);
+		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);
+		hp->sw_bmcr |= BMCR_SPEED100;
+	} else if(hp->sw_lpa & LPA_10FULL) {
+		printk("%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);
+	}
+	happy_meal_tcvr_write(hp, tregs, DP83840_BMCR, hp->sw_bmcr);
+
+	/* Finally stop polling and shut up the MIF. */
+	happy_meal_poll_stop(hp, tregs);
+}
+
+/* #define TXD(x) printk x */
+#define TXD(x)
+
+static inline void happy_meal_tx(struct happy_meal *hp)
+{
+	struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0];
+	struct happy_meal_txd *this;
+	int elem = hp->tx_old;
+
+	TXD(("TX<"));
+	while(elem != hp->tx_new) {
+		struct sk_buff *skb;
+
+		TXD(("[%d]", elem));
+		this = &txbase[elem];
+		if(this->tx_flags & TXFLAG_OWN)
+			break;
+		skb = hp->tx_skbs[elem];
+		hp->tx_skbs[elem] = NULL;
+		dev_kfree_skb(skb, FREE_WRITE);
+
+		hp->enet_stats.tx_packets++;
+		elem = NEXT_TX(elem);
+	}
+	hp->tx_old = elem;
+	TXD((">"));
+}
+
+static inline void sun4c_happy_meal_tx(struct happy_meal *hp)
+{
+	struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0];
+	struct happy_meal_txd *this;
+	int elem = hp->tx_old;
+
+	TXD(("TX<"));
+	while(elem != hp->tx_new) {
+		TXD(("[%d]", elem));
+
+		this = &txbase[elem];
+
+		if(this->tx_flags & TXFLAG_OWN)
+			break;
+
+		hp->enet_stats.tx_packets++;
+		elem = NEXT_TX(elem);
+	}
+	hp->tx_old = elem;
+	TXD((">"));
+}
+
+/* #define RXD(x) printk x */
+#define RXD(x)
+
+/* Originally I use to handle the allocation failure by just giving back just
+ * that one ring buffer to the happy meal.  Problem is that usually when that
+ * condition is triggered, the happy meal expects you to do something reasonable
+ * with all of the packets it has DMA'd in.  So now I just drop the entire
+ * ring when we cannot get a new skb and give them all back to the happy meal,
+ * maybe things will be "happier" now.
+ */
+static inline void happy_meal_rx(struct happy_meal *hp, struct device *dev,
+				 struct hmeal_gregs *gregs)
+{
+	struct happy_meal_rxd *rxbase = &hp->happy_block->happy_meal_rxd[0];
+	struct happy_meal_rxd *this;
+	int elem = hp->rx_new, drops = 0;
+
+	RXD(("RX<"));
+	this = &rxbase[elem];
+	while(!(this->rx_flags & RXFLAG_OWN)) {
+		struct sk_buff *skb;
+		unsigned int flags = this->rx_flags;
+		int len = flags >> 16;
+		u16 csum = flags & RXFLAG_CSUM;
+
+		RXD(("[%d ", elem));
+
+		/* Check for errors. */
+		if((len < ETH_ZLEN) || (flags & RXFLAG_OVERFLOW)) {
+			RXD(("ERR(%08lx)]", flags));
+			hp->enet_stats.rx_errors++;
+			if(len < ETH_ZLEN)
+				hp->enet_stats.rx_length_errors++;
+			if(len & (RXFLAG_OVERFLOW >> 16)) {
+				hp->enet_stats.rx_over_errors++;
+				hp->enet_stats.rx_fifo_errors++;
+			}
+
+			/* Return it to the Happy meal. */
+	drop_it:
+			hp->enet_stats.rx_dropped++;
+			this->rx_addr = (unsigned int) hp->rx_skbs[elem]->data;
+			this->rx_flags =
+				(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
+			goto next;
+		}
+		skb = hp->rx_skbs[elem];
+		if(len > RX_COPY_THRESHOLD) {
+			struct sk_buff *new_skb;
+
+			/* Now refill the entry, if we can. */
+			new_skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
+			if(!new_skb) {
+				drops++;
+				goto drop_it;
+			}
+
+			hp->rx_skbs[elem] = new_skb;
+			new_skb->dev = dev;
+			skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET));
+			rxbase[elem].rx_addr = (unsigned int) new_skb->data;
+			skb_reserve(new_skb, RX_OFFSET);
+			rxbase[elem].rx_flags =
+				(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
+
+			/* Trim the original skb for the netif. */
+			skb_trim(skb, len);
+		} else {
+			struct sk_buff *copy_skb = dev_alloc_skb(len+2);
+
+			if(!copy_skb) {
+				drops++;
+				goto drop_it;
+			}
+
+			copy_skb->dev = dev;
+			skb_reserve(copy_skb, 2);
+			skb_put(copy_skb, len);
+			memcpy(copy_skb->data, skb->data, len);
+
+			/* Reuse original ring buffer. */
+			rxbase[elem].rx_addr = (unsigned int) skb->data;
+			rxbase[elem].rx_flags =
+				(RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16));
+
+			skb = copy_skb;
+		}
+
+		/* This card is _fucking_ hot... */
+		if(!~(csum))
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		else
+			skb->ip_summed = CHECKSUM_NONE;
+
+		RXD(("len=%d csum=%4x]", len, csum));
+		skb->protocol = eth_type_trans(skb, dev);
+		netif_rx(skb);
+
+		hp->enet_stats.rx_packets++;
+	next:
+		elem = NEXT_RX(elem);
+		this = &rxbase[elem];
+	}
+	hp->rx_new = elem;
+	if(drops)
+		printk("%s: Memory squeeze, deferring packet.\n", hp->dev->name);
+	RXD((">"));
+}
+
+static inline void sun4c_happy_meal_rx(struct happy_meal *hp, struct device *dev,
+				       struct hmeal_gregs *gregs)
+{
+	struct happy_meal_rxd *rxbase = &hp->happy_block->happy_meal_rxd[0];
+	struct happy_meal_rxd *this;
+	struct hmeal_buffers *hbufs = hp->sun4c_buffers;
+	int elem = hp->rx_new, drops = 0;
+
+	RXD(("RX<"));
+	this = &rxbase[elem];
+	while(!(this->rx_flags & RXFLAG_OWN)) {
+		struct sk_buff *skb;
+		unsigned int flags = this->rx_flags;
+		unsigned char *thisbuf = &hbufs->rx_buf[elem][0];
+		int len = flags >> 16;
+
+		RXD(("[%d ", elem));
+
+		/* Check for errors. */
+		if((len < ETH_ZLEN) || (flags & RXFLAG_OVERFLOW)) {
+			RXD(("ERR(%08lx)]", flags));
+			hp->enet_stats.rx_errors++;
+			if(len < ETH_ZLEN)
+				hp->enet_stats.rx_length_errors++;
+			if(len & (RXFLAG_OVERFLOW >> 16)) {
+				hp->enet_stats.rx_over_errors++;
+				hp->enet_stats.rx_fifo_errors++;
+			}
+
+			hp->enet_stats.rx_dropped++;
+		} else {
+			skb = dev_alloc_skb(len + 2);
+			if(skb == 0) {
+				drops++;
+				hp->enet_stats.rx_dropped++;
+			} else {
+				RXD(("len=%d]", len));
+				skb->dev = hp->dev;
+				skb_reserve(skb, 2);
+				skb_put(skb, len);
+				eth_copy_and_sum(skb, (thisbuf+2), len, 0);
+				skb->protocol = eth_type_trans(skb, dev);
+				netif_rx(skb);
+				hp->enet_stats.rx_packets++;
+			}
+		}
+		/* Return the buffer to the Happy Meal. */
+		this->rx_addr = (unsigned int) thisbuf;
+		this->rx_flags =
+			(RXFLAG_OWN | ((SUN4C_RX_BUFF_SIZE - RX_OFFSET) << 16));
+
+		elem = NEXT_RX(elem);
+		this = &rxbase[elem];
+	}
+	hp->rx_new = elem;
+	if(drops)
+		printk("%s: Memory squeeze, deferring packet.\n", hp->dev->name);
+	RXD((">"));
+}
+
+static void happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct device *dev            = (struct device *) dev_id;
+	struct happy_meal *hp         = (struct happy_meal *) dev->priv;
+	struct hmeal_gregs *gregs     = hp->gregs;
+	struct hmeal_tcvregs *tregs   = hp->tcvregs;
+	unsigned long happy_status    = gregs->stat;
+
+	HMD(("happy_meal_interrupt: status=%08lx ", happy_status));
+
+	dev->interrupt = 1;
+
+	if(happy_status & GREG_STAT_ERRORS) {
+		HMD(("ERRORS "));
+		if(happy_meal_is_not_so_happy(hp, gregs, /* un- */ happy_status)) {
+			dev->interrupt = 0;
+			return;
+		}
+	}
+
+	if(happy_status & GREG_STAT_MIFIRQ) {
+		HMD(("MIFIRQ "));
+		happy_meal_mif_interrupt(hp, gregs, tregs);
+	}
+
+	if(happy_status & GREG_STAT_TXALL) {
+		HMD(("TXALL "));
+		happy_meal_tx(hp);
+	}
+
+	if(happy_status & GREG_STAT_RXTOHOST) {
+		HMD(("RXTOHOST "));
+		happy_meal_rx(hp, dev, gregs);
+	}
+
+	if(dev->tbusy && (TX_BUFFS_AVAIL(hp) >= 0)) {
+		hp->dev->tbusy = 0;
+		mark_bh(NET_BH);
+	}
+
+	dev->interrupt = 0;
+	HMD(("done\n"));
+}
+
+static void sun4c_happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct device *dev            = (struct device *) dev_id;
+	struct happy_meal *hp         = (struct happy_meal *) dev->priv;
+	struct hmeal_gregs *gregs     = hp->gregs;
+	struct hmeal_tcvregs *tregs   = hp->tcvregs;
+	unsigned long happy_status    = gregs->stat;
+
+	HMD(("happy_meal_interrupt: status=%08lx ", happy_status));
+
+	dev->interrupt = 1;
+
+	if(happy_status & GREG_STAT_ERRORS) {
+		HMD(("ERRORS "));
+		if(happy_meal_is_not_so_happy(hp, gregs, /* un- */ happy_status)) {
+			dev->interrupt = 0;
+			return;
+		}
+	}
+
+	if(happy_status & GREG_STAT_MIFIRQ) {
+		HMD(("MIFIRQ "));
+		happy_meal_mif_interrupt(hp, gregs, tregs);
+	}
+
+	if(happy_status & GREG_STAT_TXALL) {
+		HMD(("TXALL "));
+		sun4c_happy_meal_tx(hp);
+	}
+
+	if(happy_status & GREG_STAT_RXTOHOST) {
+		HMD(("RXTOHOST "));
+		sun4c_happy_meal_rx(hp, dev, gregs);
+	}
+
+	if(dev->tbusy && (TX_BUFFS_AVAIL(hp) >= 0)) {
+		hp->dev->tbusy = 0;
+		mark_bh(NET_BH);
+	}
+
+	dev->interrupt = 0;
+	HMD(("done\n"));
+}
+
+static int happy_meal_open(struct device *dev)
+{
+	struct happy_meal *hp = (struct happy_meal *) dev->priv;
+	int res;
+
+	HMD(("happy_meal_open: "));
+	if(sparc_cpu_model == sun4c) {
+		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);
+			return -EAGAIN;
+		}
+	} else {
+		if(request_irq(dev->irq, &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);
+			return -EAGAIN;
+		}
+	}
+	HMD(("Init happy timer\n"));
+	init_timer(&hp->happy_timer);
+	HMD(("to happy_meal_init\n"));
+	res = happy_meal_init(hp, 0);
+	if(!res) {
+		MOD_INC_USE_COUNT;
+	}
+	return res;
+}
+
+static int happy_meal_close(struct device *dev)
+{
+	struct happy_meal *hp = (struct happy_meal *) dev->priv;
+
+	happy_meal_stop(hp->gregs);
+	happy_meal_clean_rings(hp);
+	free_irq(dev->irq, (void *)dev);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/* #define SXD(x) printk x */
+#define SXD(x)
+
+static int happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct happy_meal *hp = (struct happy_meal *) dev->priv;
+	int len, entry;
+
+	if(dev->tbusy) {
+		int tickssofar = jiffies - dev->trans_start;
+	    
+		if (tickssofar < 40) {
+			return 1;
+		} else {
+			printk ("%s: transmit timed out, resetting\n", dev->name);
+			hp->enet_stats.tx_errors++;
+			happy_meal_init(hp, 0);
+			dev->tbusy = 0;
+			dev->trans_start = jiffies;
+			return 0;
+		}
+	}
+
+	if(skb == NULL || skb->len <= 0) {
+		printk("%s: skb is NULL\n", dev->name);
+		dev_tint(dev);
+		return 0;
+	}
+
+	if(set_bit(0, (void *) &dev->tbusy) != 0) {
+		printk("happy meal: Transmitter access conflict.\n");
+		return 1;
+	}
+
+	if(!TX_BUFFS_AVAIL(hp))
+		return 1;
+
+	len = skb->len;
+	entry = hp->tx_new;
+
+	SXD(("SX<l[%d]e[%d]>", len, entry));
+	hp->tx_skbs[entry] = skb;
+	hp->happy_block->happy_meal_txd[entry].tx_addr = (unsigned int) skb->data;
+	hp->happy_block->happy_meal_txd[entry].tx_flags =
+		(TXFLAG_OWN | TXFLAG_SOP | TXFLAG_EOP | (len & TXFLAG_SIZE));
+	hp->tx_new = NEXT_TX(entry);
+
+	/* Get it going. */
+	dev->trans_start = jiffies;
+	hp->etxregs->tx_pnding = ETX_TP_DMAWAKEUP;
+
+	if(TX_BUFFS_AVAIL(hp))
+		dev->tbusy = 0;
+
+	return 0;
+}
+
+static int sun4c_happy_meal_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct happy_meal *hp = (struct happy_meal *) dev->priv;
+	struct hmeal_buffers *hbufs = hp->sun4c_buffers;
+	unsigned char *txbuf;
+	int len, entry;
+
+	if(dev->tbusy) {
+		int tickssofar = jiffies - dev->trans_start;
+	    
+		if (tickssofar < 40) {
+			return 1;
+		} else {
+			printk ("%s: transmit timed out, resetting\n", dev->name);
+			hp->enet_stats.tx_errors++;
+			happy_meal_init(hp, 0);
+			dev->tbusy = 0;
+			dev->trans_start = jiffies;
+			return 0;
+		}
+	}
+
+	if(skb == NULL || skb->len <= 0) {
+		printk("%s: skb is NULL\n", dev->name);
+		dev_tint(dev);
+		return 0;
+	}
+
+	if(set_bit(0, (void *) &dev->tbusy) != 0) {
+		printk("happy meal: Transmitter access conflict.\n");
+		return 1;
+	}
+
+	if(!TX_BUFFS_AVAIL(hp))
+		return 1;
+
+	len = skb->len;
+	entry = hp->tx_new;
+
+	txbuf = &hbufs->tx_buf[entry][0];
+	memcpy(txbuf, skb->data, len);
+
+	SXD(("SX<l[%d]e[%d]>", len, entry));
+	hp->happy_block->happy_meal_txd[entry].tx_addr = (unsigned int) txbuf;
+	hp->happy_block->happy_meal_txd[entry].tx_flags =
+		(TXFLAG_OWN | TXFLAG_SOP | TXFLAG_EOP | (len & TXFLAG_SIZE));
+	hp->tx_new = NEXT_TX(entry);
+
+	/* Get it going. */
+	dev->trans_start = jiffies;
+	hp->etxregs->tx_pnding = ETX_TP_DMAWAKEUP;
+
+	dev_kfree_skb(skb, FREE_WRITE);
+
+	if(TX_BUFFS_AVAIL(hp))
+		dev->tbusy = 0;
+
+	return 0;
+}
+
+static struct enet_statistics *happy_meal_get_stats(struct device *dev)
+{
+	struct happy_meal *hp = (struct happy_meal *) dev->priv;
+
+	happy_meal_get_counters(hp, hp->bigmacregs);
+	return &hp->enet_stats;
+}
+
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
+
+static void happy_meal_set_multicast(struct device *dev)
+{
+	struct happy_meal *hp = (struct happy_meal *) dev->priv;
+	struct hmeal_bigmacregs *bregs = hp->bigmacregs;
+	struct dev_mc_list *dmi = dev->mc_list;
+	char *addrs;
+	int i, j, bit, byte;
+	u32 crc, poly = CRC_POLYNOMIAL_LE;
+
+	/* Let the transmits drain. */
+	while(dev->tbusy)
+		schedule();
+
+	/* Lock out others. */
+	set_bit(0, (void *) &dev->tbusy);
+
+	if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
+		bregs->htable0 = 0xffff;
+		bregs->htable1 = 0xffff;
+		bregs->htable2 = 0xffff;
+		bregs->htable3 = 0xffff;
+	} else if(dev->flags & IFF_PROMISC) {
+		bregs->rx_cfg |= BIGMAC_RXCFG_PMISC;
+	} else {
+		u16 hash_table[4];
+
+		for(i = 0; i < 4; i++)
+			hash_table[i] = 0;
+
+		for(i = 0; i < dev->mc_count; i++) {
+			addrs = dmi->dmi_addr;
+			dmi = dmi->next;
+
+			if(!(*addrs & 1))
+				continue;
+
+			crc = 0xffffffffU;
+			for(byte = 0; byte < 6; byte++) {
+				for(bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
+					int test;
+
+					test = ((bit ^ crc) & 0x01);
+					crc >>= 1;
+					if(test)
+						crc = crc ^ poly;
+				}
+			}
+			crc >>= 26;
+			hash_table[crc >> 4] |= 1 << (crc & 0xf);
+		}
+		bregs->htable0 = hash_table[0];
+		bregs->htable1 = hash_table[1];
+		bregs->htable2 = hash_table[2];
+		bregs->htable3 = hash_table[3];
+	}
+
+	/* Let us get going again. */
+	dev->tbusy = 0;
+}
+
+static int happy_meal_ether_init(struct device *dev, struct linux_sbus_device *sdev)
+{
+	static unsigned version_printed = 0;
+	struct happy_meal *hp;
+	int i;
+
+	if(dev == NULL) {
+		dev = init_etherdev(0, sizeof(struct happy_meal));
+	} else {
+		dev->priv = kmalloc(sizeof(struct happy_meal), GFP_KERNEL);
+		if(dev->priv == NULL)
+			return -ENOMEM;
+	}
+	if(version_printed++ == 0)
+		printk(version);
+
+	printk("%s: HAPPY MEAL 10/100baseT Ethernet ", dev->name);
+
+	dev->base_addr = (long) sdev;
+	for(i = 0; i < 6; i++)
+		printk("%2.2x%c",
+		       dev->dev_addr[i] = idprom->id_ethaddr[i],
+		       i == 5 ? ' ' : ':');
+	printk("\n");
+
+	hp = (struct happy_meal *) dev->priv;
+	hp->happy_sbus_dev = sdev;
+
+	if(sdev->num_registers != 5) {
+		printk("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");
+		return ENODEV;
+	}
+
+	prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], sdev->num_registers);
+	hp->gregs = sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0,
+				   sizeof(struct hmeal_gregs),
+				   "Happy Meal Global Regs",
+				   sdev->reg_addrs[0].which_io, 0);
+	if(!hp->gregs) {
+		printk("happymeal: Cannot map Happy Meal global registers.\n");
+		return ENODEV;
+	}
+
+	hp->etxregs = sparc_alloc_io(sdev->reg_addrs[1].phys_addr, 0,
+				     sizeof(struct hmeal_etxregs),
+				     "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");
+		return ENODEV;
+	}
+
+	hp->erxregs = sparc_alloc_io(sdev->reg_addrs[2].phys_addr, 0,
+				     sizeof(struct hmeal_erxregs),
+				     "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");
+		return ENODEV;
+	}
+
+	hp->bigmacregs = sparc_alloc_io(sdev->reg_addrs[3].phys_addr, 0,
+					sizeof(struct hmeal_bigmacregs),
+					"Happy Meal BIGMAC Regs",
+					sdev->reg_addrs[3].which_io, 0);
+	if(!hp->bigmacregs) {
+		printk("happymeal: Cannot map Happy Meal BIGMAC registers.\n");
+		return ENODEV;
+	}
+
+	hp->tcvregs = sparc_alloc_io(sdev->reg_addrs[4].phys_addr, 0,
+				     sizeof(struct hmeal_tcvregs),
+				     "Happy Meal Tranceiver Regs",
+				     sdev->reg_addrs[4].which_io, 0);
+	if(!hp->tcvregs) {
+		printk("happymeal: Cannot map Happy Meal Tranceiver registers.\n");
+		return ENODEV;
+	}
+
+	hp->hm_revision = prom_getintdefault(sdev->prom_node, "hm-rev", 0xff);
+	if(hp->hm_revision == 0xff)
+		hp->hm_revision = 0xa0;
+
+	/* Now enable the feature flags we can. */
+	if(hp->hm_revision == 0x20 || hp->hm_revision == 0x21)
+		hp->happy_flags = HFLAG_20_21;
+	else if(hp->hm_revision != 0xa0)
+		hp->happy_flags = HFLAG_NOT_A0;
+
+	/* Get the supported DVMA burst sizes from our Happy SBUS. */
+	hp->happy_bursts = prom_getintdefault(hp->happy_sbus_dev->my_bus->prom_node,
+					      "burst-sizes", 0x00);
+
+	hp->happy_block = (struct hmeal_init_block *)
+		sparc_dvma_malloc(PAGE_SIZE, "Happy Meal Init Block");
+
+	if(sparc_cpu_model == sun4c)
+		hp->sun4c_buffers = (struct hmeal_buffers *)
+		    sparc_dvma_malloc(sizeof(struct hmeal_buffers), "Happy Meal Bufs");
+	else
+		hp->sun4c_buffers = 0;
+
+	/* Force check of the link first time we are brought up. */
+	hp->linkcheck = 0;
+
+	/* Force timer state to 'asleep' with count of zero. */
+	hp->timer_state = asleep;
+	hp->timer_ticks = 0;
+
+	/* Grrr, Happy Meal comes up by default not advertising
+	 * full duplex 100baseT capabilities, fix this.
+	 */
+	happy_meal_set_initial_advertisement(hp);
+
+	hp->dev = dev;
+	dev->open = &happy_meal_open;
+	dev->stop = &happy_meal_close;
+	if(sparc_cpu_model == sun4c)
+		dev->hard_start_xmit = &sun4c_happy_meal_start_xmit;
+	else
+		dev->hard_start_xmit = &happy_meal_start_xmit;
+	dev->get_stats = &happy_meal_get_stats;
+	dev->set_multicast_list = &happy_meal_set_multicast;
+
+	dev->irq = (unsigned char) sdev->irqs[0].pri;
+	dev->dma = 0;
+	ether_setup(dev);
+#ifdef MODULE
+	/* We are home free at this point, link us in to the happy
+	 * module device list.
+	 */
+	hp->next_module = root_happy_dev;
+	root_happy_dev = hp;
+#endif
+	return 0;
+}
+
+int happy_meal_probe(struct device *dev)
+{
+	struct linux_sbus *bus;
+	struct linux_sbus_device *sdev = 0;
+	static int called = 0;
+	int cards = 0, v;
+
+	if(called)
+		return ENODEV;
+	called++;
+
+	for_each_sbus(bus) {
+		for_each_sbusdev(sdev, bus) {
+			if(cards) dev = NULL;
+			if(!strcmp(sdev->prom_name, "SUNW,hme")) {
+				cards++;
+				if((v = happy_meal_ether_init(dev, sdev)))
+					return v;
+			}
+		}
+	}
+	if(!cards)
+		return ENODEV;
+	return 0;
+}
+
+#ifdef MODULE
+
+int
+init_module(void)
+{
+	root_happy_dev = NULL;
+	return happy_meal_probe(NULL);
+}
+
+void
+cleanup_module(void)
+{
+	struct happy_meal *sunshine;
+
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (root_happy_dev) {
+		sunshine = root_happy_dev->next_module;
+
+		unregister_netdev(root_happy_dev->dev);
+		kfree(root_happy_dev->dev);
+		root_happy_dev = sunshine;
+	}
+}
+
+#endif /* MODULE */
diff -u --recursive --new-file v2.1.15/linux/drivers/net/sunhme.h linux/drivers/net/sunhme.h
--- v2.1.15/linux/drivers/net/sunhme.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/sunhme.h	Fri Dec 13 11:37:32 1996
@@ -0,0 +1,582 @@
+/* sunhme.h: Definitions for Sparc HME/BigMac 10/100baseT ethernet driver.
+ *           Also known as the "Happy Meal".
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+#ifndef _SUNHME_H
+#define _SUNHME_H
+
+/* Happy Meal global registers. */
+struct hmeal_gregs {
+	volatile unsigned int sw_reset;      /* Software Reset  */
+	volatile unsigned int cfg;           /* Config Register */
+	volatile unsigned int _padding[62];  /* Unused          */
+	volatile unsigned int stat;          /* Status          */
+	volatile unsigned int imask;         /* Interrupt Mask  */
+};
+
+/* Global reset register. */
+#define GREG_RESET_ETX         0x01
+#define GREG_RESET_ERX         0x02
+#define GREG_RESET_ALL         0x03
+
+/* Global config register. */
+#define GREG_CFG_BURSTMSK      0x03
+#define GREG_CFG_BURST16       0x00
+#define GREG_CFG_BURST32       0x01
+#define GREG_CFG_BURST64       0x02
+#define GREG_CFG_64BIT         0x04
+#define GREG_CFG_PARITY        0x08
+#define GREG_CFG_RESV          0x10
+
+/* Global status register. */
+#define GREG_STAT_GOTFRAME     0x00000001 /* Received a frame                         */
+#define GREG_STAT_RCNTEXP      0x00000002 /* Receive frame counter expired            */
+#define GREG_STAT_ACNTEXP      0x00000004 /* Align-error counter expired              */
+#define GREG_STAT_CCNTEXP      0x00000008 /* CRC-error counter expired                */
+#define GREG_STAT_LCNTEXP      0x00000010 /* Length-error counter expired             */
+#define GREG_STAT_RFIFOVF      0x00000020 /* Receive FIFO overflow                    */
+#define GREG_STAT_CVCNTEXP     0x00000040 /* Code-violation counter expired           */
+#define GREG_STAT_STSTERR      0x00000080 /* Test error in XIF for SQE                */
+#define GREG_STAT_SENTFRAME    0x00000100 /* Transmitted a frame                      */
+#define GREG_STAT_TFIFO_UND    0x00000200 /* Transmit FIFO underrun                   */
+#define GREG_STAT_MAXPKTERR    0x00000400 /* Max-packet size error                    */
+#define GREG_STAT_NCNTEXP      0x00000800 /* Normal-collision counter expired         */
+#define GREG_STAT_ECNTEXP      0x00001000 /* Excess-collision counter expired         */
+#define GREG_STAT_LCCNTEXP     0x00002000 /* Late-collision counter expired           */
+#define GREG_STAT_FCNTEXP      0x00004000 /* First-collision counter expired          */
+#define GREG_STAT_DTIMEXP      0x00008000 /* Defer-timer expired                      */
+#define GREG_STAT_RXTOHOST     0x00010000 /* Moved from receive-FIFO to host memory   */
+#define GREG_STAT_NORXD        0x00020000 /* No more receive descriptors              */
+#define GREG_STAT_RXERR        0x00040000 /* Error during receive dma                 */
+#define GREG_STAT_RXLATERR     0x00080000 /* Late error during receive dma            */
+#define GREG_STAT_RXPERR       0x00100000 /* Parity error during receive dma          */
+#define GREG_STAT_RXTERR       0x00200000 /* Tag error during receive dma             */
+#define GREG_STAT_EOPERR       0x00400000 /* Transmit descriptor did not have EOP set */
+#define GREG_STAT_MIFIRQ       0x00800000 /* MIF is signaling an interrupt condition  */
+#define GREG_STAT_HOSTTOTX     0x01000000 /* Moved from host memory to transmit-FIFO  */
+#define GREG_STAT_TXALL        0x02000000 /* Transmitted all packets in the tx-fifo   */
+#define GREG_STAT_TXEACK       0x04000000 /* Error during transmit dma                */
+#define GREG_STAT_TXLERR       0x08000000 /* Late error during transmit dma           */
+#define GREG_STAT_TXPERR       0x10000000 /* Parity error during transmit dma         */
+#define GREG_STAT_TXTERR       0x20000000 /* Tag error during transmit dma            */
+#define GREG_STAT_SLVERR       0x40000000 /* PIO access got an error                  */
+#define GREG_STAT_SLVPERR      0x80000000 /* PIO access got a parity error            */
+
+/* All interesting error conditions. */
+#define GREG_STAT_ERRORS       0xfc7efefc
+
+/* Global interrupt mask register. */
+#define GREG_IMASK_GOTFRAME    0x00000001 /* Received a frame                         */
+#define GREG_IMASK_RCNTEXP     0x00000002 /* Receive frame counter expired            */
+#define GREG_IMASK_ACNTEXP     0x00000004 /* Align-error counter expired              */
+#define GREG_IMASK_CCNTEXP     0x00000008 /* CRC-error counter expired                */
+#define GREG_IMASK_LCNTEXP     0x00000010 /* Length-error counter expired             */
+#define GREG_IMASK_RFIFOVF     0x00000020 /* Receive FIFO overflow                    */
+#define GREG_IMASK_CVCNTEXP    0x00000040 /* Code-violation counter expired           */
+#define GREG_IMASK_STSTERR     0x00000080 /* Test error in XIF for SQE                */
+#define GREG_IMASK_SENTFRAME   0x00000100 /* Transmitted a frame                      */
+#define GREG_IMASK_TFIFO_UND   0x00000200 /* Transmit FIFO underrun                   */
+#define GREG_IMASK_MAXPKTERR   0x00000400 /* Max-packet size error                    */
+#define GREG_IMASK_NCNTEXP     0x00000800 /* Normal-collision counter expired         */
+#define GREG_IMASK_ECNTEXP     0x00001000 /* Excess-collision counter expired         */
+#define GREG_IMASK_LCCNTEXP    0x00002000 /* Late-collision counter expired           */
+#define GREG_IMASK_FCNTEXP     0x00004000 /* First-collision counter expired          */
+#define GREG_IMASK_DTIMEXP     0x00008000 /* Defer-timer expired                      */
+#define GREG_IMASK_RXTOHOST    0x00010000 /* Moved from receive-FIFO to host memory   */
+#define GREG_IMASK_NORXD       0x00020000 /* No more receive descriptors              */
+#define GREG_IMASK_RXERR       0x00040000 /* Error during receive dma                 */
+#define GREG_IMASK_RXLATERR    0x00080000 /* Late error during receive dma            */
+#define GREG_IMASK_RXPERR      0x00100000 /* Parity error during receive dma          */
+#define GREG_IMASK_RXTERR      0x00200000 /* Tag error during receive dma             */
+#define GREG_IMASK_EOPERR      0x00400000 /* Transmit descriptor did not have EOP set */
+#define GREG_IMASK_MIFIRQ      0x00800000 /* MIF is signaling an interrupt condition  */
+#define GREG_IMASK_HOSTTOTX    0x01000000 /* Moved from host memory to transmit-FIFO  */
+#define GREG_IMASK_TXALL       0x02000000 /* Transmitted all packets in the tx-fifo   */
+#define GREG_IMASK_TXEACK      0x04000000 /* Error during transmit dma                */
+#define GREG_IMASK_TXLERR      0x08000000 /* Late error during transmit dma           */
+#define GREG_IMASK_TXPERR      0x10000000 /* Parity error during transmit dma         */
+#define GREG_IMASK_TXTERR      0x20000000 /* Tag error during transmit dma            */
+#define GREG_IMASK_SLVERR      0x40000000 /* PIO access got an error                  */
+#define GREG_IMASK_SLVPERR     0x80000000 /* PIO access got a parity error            */
+
+/* Happy Meal external transmitter registers. */
+struct hmeal_etxregs {
+	volatile unsigned int tx_pnding;     /* Transmit pending/wakeup register */
+	volatile unsigned int cfg;           /* Transmit config register         */
+	volatile unsigned int tx_ring;       /* Transmit ring pointer            */
+	volatile unsigned int tx_bbase;      /* Transmit buffer base             */
+	volatile unsigned int tx_bdisp;      /* Transmit buffer displacement     */
+	volatile unsigned int tx_fifo_wptr;  /* FIFO write ptr                   */
+	volatile unsigned int tx_fifo_swptr; /* FIFO write ptr (shadow register) */
+	volatile unsigned int tx_fifo_rptr;  /* FIFO read ptr                    */
+	volatile unsigned int tx_fifo_srptr; /* FIFO read ptr (shadow register)  */
+	volatile unsigned int tx_fifo_pcnt;  /* FIFO packet counter              */
+	volatile unsigned int smachine;      /* Transmitter state machine        */
+	volatile unsigned int tx_rsize;      /* Ring descriptor size             */
+	volatile unsigned int tx_bptr;       /* Transmit data buffer ptr         */
+};
+
+/* ETX transmit pending register. */
+#define ETX_TP_DMAWAKEUP         0x00000001 /* Restart transmit dma             */
+
+/* ETX config register. */
+#define ETX_CFG_DMAENABLE        0x00000001 /* Enable transmit dma              */
+#define ETX_CFG_FIFOTHRESH       0x000003fe /* Transmit FIFO threshold          */
+#define ETX_CFG_IRQDAFTER        0x00000400 /* Interrupt after TX-FIFO drained  */
+#define ETX_CFG_IRQDBEFORE       0x00000000 /* Interrupt before TX-FIFO drained */
+
+#define ETX_RSIZE_SHIFT          4
+
+/* Happy Meal external receiver registers. */
+struct hmeal_erxregs {
+	volatile unsigned int cfg;           /* Receiver config register         */
+	volatile unsigned int rx_ring;       /* Receiver ring ptr                */
+	volatile unsigned int rx_bptr;       /* Receiver buffer ptr              */
+	volatile unsigned int rx_fifo_wptr;  /* FIFO write ptr                   */
+	volatile unsigned int rx_fifo_swptr; /* FIFO write ptr (shadow register) */
+	volatile unsigned int rx_fifo_rptr;  /* FIFO read ptr                    */
+	volatile unsigned int rx_fifo_srptr; /* FIFO read ptr (shadow register)  */
+	volatile unsigned int smachine;      /* Receiver state machine           */
+};
+
+/* ERX config register. */
+#define ERX_CFG_DMAENABLE    0x00000001 /* Enable receive DMA        */
+#define ERX_CFG_RESV1        0x00000006 /* Unused...                 */
+#define ERX_CFG_BYTEOFFSET   0x00000038 /* Receive first byte offset */
+#define ERX_CFG_RESV2        0x000001c0 /* Unused...                 */
+#define ERX_CFG_SIZE32       0x00000000 /* Receive ring size == 32   */
+#define ERX_CFG_SIZE64       0x00000200 /* Receive ring size == 64   */
+#define ERX_CFG_SIZE128      0x00000400 /* Receive ring size == 128  */
+#define ERX_CFG_SIZE256      0x00000600 /* Receive ring size == 256  */
+#define ERX_CFG_RESV3        0x0000f800 /* Unused...                 */
+#define ERX_CFG_CSUMSTART    0x007f0000 /* Offset of checksum start  */
+
+/* I'd like a Big Mac, small fries, small coke, and SparcLinux please. */
+struct hmeal_bigmacregs {
+	volatile unsigned int xif_cfg;          /* XIF config register                */
+	volatile unsigned int _unused[129];     /* Reserved...                        */
+	volatile unsigned int tx_swreset;       /* Transmitter software reset         */
+	volatile unsigned int tx_cfg;           /* Transmitter config register        */
+	volatile unsigned int ipkt_gap1;        /* Inter-packet gap 1                 */
+	volatile unsigned int ipkt_gap2;        /* Inter-packet gap 2                 */
+	volatile unsigned int attempt_limit;    /* Transmit attempt limit             */
+	volatile unsigned int stime;            /* Transmit slot time                 */
+	volatile unsigned int preamble_len;     /* Size of transmit preamble          */
+	volatile unsigned int preamble_pattern; /* Pattern for transmit preamble      */
+	volatile unsigned int tx_sframe_delim;  /* Transmit delimiter                 */
+	volatile unsigned int jsize;            /* Jam size                           */
+	volatile unsigned int tx_pkt_max;       /* Transmit max pkt size              */
+	volatile unsigned int tx_pkt_min;       /* Transmit min pkt size              */
+	volatile unsigned int peak_attempt;     /* Count of transmit peak attempts    */
+	volatile unsigned int dt_ctr;           /* Transmit defer timer               */
+	volatile unsigned int nc_ctr;           /* Transmit normal-collision counter  */
+	volatile unsigned int fc_ctr;           /* Transmit first-collision counter   */
+	volatile unsigned int ex_ctr;           /* Transmit excess-collision counter  */
+	volatile unsigned int lt_ctr;           /* Transmit late-collision counter    */
+	volatile unsigned int rand_seed;        /* Transmit random number seed        */
+	volatile unsigned int tx_smachine;      /* Transmit state machine             */
+	volatile unsigned int _unused2[44];     /* Reserved                           */
+	volatile unsigned int rx_swreset;       /* Receiver software reset            */
+	volatile unsigned int rx_cfg;           /* Receiver config register           */
+	volatile unsigned int rx_pkt_max;       /* Receive max pkt size               */
+	volatile unsigned int rx_pkt_min;       /* Receive min pkt size               */
+	volatile unsigned int mac_addr2;        /* Ether address register 2           */
+	volatile unsigned int mac_addr1;        /* Ether address register 1           */
+	volatile unsigned int mac_addr0;        /* Ether address register 0           */
+	volatile unsigned int fr_ctr;           /* Receive frame receive counter      */
+	volatile unsigned int gle_ctr;          /* Receive giant-length error counter */
+	volatile unsigned int unale_ctr;        /* Receive unaligned error counter    */
+	volatile unsigned int rcrce_ctr;        /* Receive CRC error counter          */
+	volatile unsigned int rx_smachine;      /* Receiver state machine             */
+	volatile unsigned int rx_cvalid;        /* Receiver code violation            */
+	volatile unsigned int _unused3;         /* Reserved...                        */
+	volatile unsigned int htable3;          /* Hash table 3                       */
+	volatile unsigned int htable2;          /* Hash table 2                       */
+	volatile unsigned int htable1;          /* Hash table 1                       */
+	volatile unsigned int htable0;          /* Hash table 0                       */
+	volatile unsigned int afilter2;         /* Address filter 2                   */
+	volatile unsigned int afilter1;         /* Address filter 1                   */
+	volatile unsigned int afilter0;         /* Address filter 0                   */
+	volatile unsigned int afilter_mask;     /* Address filter mask                */
+
+};
+
+/* BigMac XIF config register. */
+#define BIGMAC_XCFG_ODENABLE  0x00000001 /* Output driver enable         */
+#define BIGMAC_XCFG_XLBACK    0x00000002 /* Loopback-mode XIF enable     */
+#define BIGMAC_XCFG_MLBACK    0x00000004 /* Loopback-mode MII enable     */
+#define BIGMAC_XCFG_MIIDISAB  0x00000008 /* MII receive buffer disable   */
+#define BIGMAC_XCFG_SQENABLE  0x00000010 /* SQE test enable              */
+#define BIGMAC_XCFG_SQETWIN   0x000003e0 /* SQE time window              */
+#define BIGMAC_XCFG_LANCE     0x00000010 /* Lance mode enable            */
+#define BIGMAC_XCFG_LIPG0     0x000003e0 /* Lance mode IPG0              */
+
+/* BigMac transmit config register. */
+#define BIGMAC_TXCFG_ENABLE   0x00000001 /* Enable the transmitter       */
+#define BIGMAC_TXCFG_SMODE    0x00000020 /* Enable slow transmit mode    */
+#define BIGMAC_TXCFG_CIGN     0x00000040 /* Ignore transmit collisions   */
+#define BIGMAC_TXCFG_FCSOFF   0x00000080 /* Do not emit FCS              */
+#define BIGMAC_TXCFG_DBACKOFF 0x00000100 /* Disable backoff              */
+#define BIGMAC_TXCFG_FULLDPLX 0x00000200 /* Enable full-duplex           */
+#define BIGMAC_TXCFG_DGIVEUP  0x00000400 /* Don't give up on transmits   */
+
+/* BigMac receive config register. */
+#define BIGMAC_RXCFG_ENABLE   0x00000001 /* Enable the receiver             */
+#define BIGMAC_RXCFG_PSTRIP   0x00000020 /* Pad byte strip enable           */
+#define BIGMAC_RXCFG_PMISC    0x00000040 /* Enable promiscous mode          */
+#define BIGMAC_RXCFG_DERR     0x00000080 /* Disable error checking          */
+#define BIGMAC_RXCFG_DCRCS    0x00000100 /* Disable CRC stripping           */
+#define BIGMAC_RXCFG_ME       0x00000200 /* Receive packets addressed to me */
+#define BIGMAC_RXCFG_PGRP     0x00000400 /* Enable promisc group mode       */
+#define BIGMAC_RXCFG_HENABLE  0x00000800 /* Enable the hash filter          */
+#define BIGMAC_RXCFG_AENABLE  0x00001000 /* Enable the address filter       */
+
+/* These are the "Management Interface" (ie. MIF) registers of the transceiver. */
+struct hmeal_tcvregs {
+	volatile unsigned int bb_clock; /* Bit bang clock register          */
+	volatile unsigned int bb_data;  /* Bit bang data register           */
+	volatile unsigned int bb_oenab; /* Bit bang output enable           */
+	volatile unsigned int frame;    /* Frame control/data register      */
+	volatile unsigned int cfg;      /* MIF config register              */
+	volatile unsigned int int_mask; /* MIF interrupt mask               */
+	volatile unsigned int status;   /* MIF status                       */
+	volatile unsigned int smachine; /* MIF state machine                */
+};
+
+/* Frame commands. */
+#define FRAME_WRITE           0x50020000
+#define FRAME_READ            0x60020000
+
+/* Transceiver config register */
+#define TCV_CFG_PSELECT       0x00000001 /* Select PHY                      */
+#define TCV_CFG_PENABLE       0x00000002 /* Enable MIF polling              */
+#define TCV_CFG_BENABLE       0x00000004 /* Enable the "bit banger" oh baby */
+#define TCV_CFG_PREGADDR      0x000000f8 /* Address of poll register        */
+#define TCV_CFG_MDIO0         0x00000100 /* MDIO zero, data/attached        */
+#define TCV_CFG_MDIO1         0x00000200 /* MDIO one,  data/attached        */
+#define TCV_CFG_PDADDR        0x00007c00 /* Device PHY address polling      */
+
+/* Here are some PHY addresses. */
+#define TCV_PADDR_ETX         0          /* Internal transceiver            */
+#define TCV_PADDR_ITX         1          /* External transceiver            */
+
+/* Transceiver status register */
+#define TCV_STAT_BASIC        0xffff0000 /* The "basic" part                */
+#define TCV_STAT_NORMAL       0x0000ffff /* The "non-basic" part            */
+
+/* Inside the Happy Meal transceiver is the physical layer, they use an
+ * implementations for National Semiconductor, part number DP83840VCE.
+ * You can retrieve the data sheets and programming docs for this beast
+ * from http://www.national.com/
+ *
+ * The DP83840 is capable of both 10 and 100Mbps ethernet, in both
+ * half and full duplex mode.  It also supports auto negotiation.
+ *
+ * But.... THIS THING IS A PAIN IN THE ASS TO PROGRAM!
+ * Debugging eeprom burnt code is more fun than programming this chip!
+ */
+
+/* First, the DP83840 register numbers. */
+#define DP83840_BMCR            0x00        /* Basic mode control register */
+#define DP83840_BMSR            0x01        /* Basic mode status register  */
+#define DP83840_PHYSID1         0x02        /* PHYS ID 1                   */
+#define DP83840_PHYSID2         0x03        /* PHYS ID 2                   */
+#define DP83840_ADVERTISE       0x04        /* Advertisement control reg   */
+#define DP83840_LPA             0x05        /* Link partner ability reg    */
+#define DP83840_EXPANSION       0x06        /* Expansion register          */
+#define DP83840_DCOUNTER        0x12        /* Disconnect counter          */
+#define DP83840_FCSCOUNTER      0x13        /* False carrier counter       */
+#define DP83840_NWAYTEST        0x14        /* N-way auto-neg test reg     */
+#define DP83840_RERRCOUNTER     0x15        /* Receive error counter       */
+#define DP83840_SREVISION       0x16        /* Silicon revision            */
+#define DP83840_CSCONFIG        0x17        /* CS configuration            */
+#define DP83840_LBRERROR        0x18        /* Lpback, rx, bypass error    */
+#define DP83840_PHYADDR         0x19        /* PHY address                 */
+#define DP83840_RESERVED        0x1a        /* Unused...                   */
+#define DP83840_TPISTATUS       0x1b        /* TPI status for 10mbps       */
+#define DP83840_NCONFIG         0x1c        /* Network interface config    */
+
+/* Basic mode control register. */
+#define BMCR_RESV               0x007f  /* Unused...                   */
+#define BMCR_CTST               0x0080  /* Collision test              */
+#define BMCR_FULLDPLX           0x0100  /* Full duplex                 */
+#define BMCR_ANRESTART          0x0200  /* Auto negotiation restart    */
+#define BMCR_ISOLATE            0x0400  /* Disconnect DP83840 from MII */
+#define BMCR_PDOWN              0x0800  /* Powerdown the DP83840       */
+#define BMCR_ANENABLE           0x1000  /* Enable auto negotiation     */
+#define BMCR_SPEED100           0x2000  /* Select 100Mbps              */
+#define BMCR_LOOPBACK           0x4000  /* TXD loopback bits           */
+#define BMCR_RESET              0x8000  /* Reset the DP83840           */
+
+/* Basic mode status register. */
+#define BMSR_ERCAP              0x0001  /* Ext-reg capability          */
+#define BMSR_JCD                0x0002  /* Jabber detected             */
+#define BMSR_LSTATUS            0x0004  /* Link status                 */
+#define BMSR_ANEGCAPABLE        0x0008  /* Able to do auto-negotiation */
+#define BMSR_RFAULT             0x0010  /* Remote fault detected       */
+#define BMSR_ANEGCOMPLETE       0x0020  /* Auto-negotiation complete   */
+#define BMSR_RESV               0x07c0  /* Unused...                   */
+#define BMSR_10HALF             0x0800  /* Can do 10mbps, half-duplex  */
+#define BMSR_10FULL             0x1000  /* Can do 10mbps, full-duplex  */
+#define BMSR_100HALF            0x2000  /* Can do 100mbps, half-duplex */
+#define BMSR_100FULL            0x4000  /* Can do 100mbps, full-duplex */
+#define BMSR_100BASE4           0x8000  /* Can do 100mbps, 4k packets  */
+
+/* Advertisement control register. */
+#define ADVERTISE_SLCT          0x001f  /* Selector bits               */
+#define ADVERTISE_CSMA          0x0001  /* Only selector supported     */
+#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
+#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
+#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
+#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
+#define ADVERTISE_100BASE4      0x0200  /* Try for 100mbps 4k packets  */
+#define ADVERTISE_RESV          0x1c00  /* Unused...                   */
+#define ADVERTISE_RFAULT        0x2000  /* Say we can detect faults    */
+#define ADVERTISE_LPACK         0x4000  /* Ack link partners response  */
+#define ADVERTISE_NPAGE         0x8000  /* Next page bit               */
+
+#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
+                       ADVERTISE_100HALF | ADVERTISE_100FULL)
+
+/* Link partner ability register. */
+#define LPA_SLCT                0x001f  /* Same as advertise selector  */
+#define LPA_10HALF              0x0020  /* Can do 10mbps half-duplex   */
+#define LPA_10FULL              0x0040  /* Can do 10mbps full-duplex   */
+#define LPA_100HALF             0x0080  /* Can do 100mbps half-duplex  */
+#define LPA_100FULL             0x0100  /* Can do 100mbps full-duplex  */
+#define LPA_100BASE4            0x0100  /* Can do 100mbps 4k packets   */
+#define LPA_RESV                0x1c00  /* Unused...                   */
+#define LPA_RFAULT              0x2000  /* Link partner faulted        */
+#define LPA_LPACK               0x4000  /* Link partner acked us       */
+#define LPA_NPAGE               0x8000  /* Next page bit               */
+
+/* Expansion register for auto-negotiation. */
+#define EXPANSION_NWAY          0x0001  /* Can do N-way auto-nego      */
+#define EXPANSION_LCWP          0x0002  /* Got new RX page code word   */
+#define EXPANSION_ENABLENPAGE   0x0004  /* This enables npage words    */
+#define EXPANSION_NPCAPABLE     0x0008  /* Link partner supports npage */
+#define EXPANSION_MFAULTS       0x0010  /* Multiple faults detected    */
+#define EXPANSION_RESV          0xffe0  /* Unused...                   */
+
+/* N-way test register. */
+#define NWAYTEST_RESV1          0x00ff  /* Unused...                   */
+#define NWAYTEST_LOOPBACK       0x0100  /* Enable loopback for N-way   */
+#define NWAYTEST_RESV2          0xfe00  /* Unused...                   */
+
+/* The Carrier Sense config register. */
+#define CSCONFIG_RESV1          0x0001  /* Unused...                   */
+#define CSCONFIG_LED4           0x0002  /* Pin for full-dplx LED4      */
+#define CSCONFIG_LED1           0x0004  /* Pin for conn-status LED1    */
+#define CSCONFIG_RESV2          0x0008  /* Unused...                   */
+#define CSCONFIG_TXDISAB        0x0010  /* Turns off the transceiver   */
+#define CSCONFIG_DFBYPASS       0x0020  /* Bypass disconnect function  */
+#define CSCONFIG_GLFORCE        0x0040  /* Good link force for 100mbps */
+#define CSCONFIG_CLKTRISTATE    0x0080  /* Tristate 25m clock          */
+#define CSCONFIG_RESV3          0x0700  /* Unused...                   */
+#define CSCONFIG_ENCODE         0x0800  /* 1=MLT-3, 0=binary           */
+#define CSCONFIG_RENABLE        0x1000  /* Repeater mode enable        */
+#define CSCONFIG_TCDISABLE      0x2000  /* Disable timeout counter     */
+#define CSCONFIG_RESV4          0x4000  /* Unused...                   */
+#define CSCONFIG_NDISABLE       0x8000  /* Disable NRZI                */
+
+/* Loopback, receive, bypass error register. */
+#define LBRERROR_EBUFFER        0x0001  /* Show elasticity buf errors  */
+#define LBRERROR_PACKET         0x0002  /* Show packet errors          */
+#define LBRERROR_LINK           0x0004  /* Show link errors            */
+#define LBRERROR_END            0x0008  /* Show premature end errors   */
+#define LBRERROR_CODE           0x0010  /* Show code errors            */
+#define LBRERROR_RESV1          0x00e0  /* Unused...                   */
+#define LBRERROR_LBACK          0x0300  /* Remote and twister loopback */
+#define LBRERROR_10TX           0x0400  /* Transceiver loopback 10mbps */
+#define LBRERROR_ENDEC          0x0800  /* ENDEC loopback 10mbps       */
+#define LBRERROR_ALIGN          0x1000  /* Bypass symbol alignment     */
+#define LBRERROR_SCRAMBLER      0x2000  /* Bypass (de)scrambler        */
+#define LBRERROR_ENCODER        0x4000  /* Bypass 4B5B/5B4B encoders   */
+#define LBRERROR_BEBUF          0x8000  /* Bypass elasticity buffers   */
+
+/* Physical address register. */
+#define PHYADDR_ADDRESS         0x001f  /* The address itself          */
+#define PHYADDR_DISCONNECT      0x0020  /* Disconnect status           */
+#define PHYADDR_10MBPS          0x0040  /* 1=10mbps, 0=100mbps         */
+#define PHYADDR_RESV            0xff80  /* Unused...                   */
+
+/* TPI status register for 10mbps. */
+#define TPISTATUS_RESV1         0x01ff  /* Unused...                   */
+#define TPISTATUS_SERIAL        0x0200  /* Enable 10mbps serial mode   */
+#define TPISTATUS_RESV2         0xfc00  /* Unused...                   */
+
+/* Network interface config register. */
+#define NCONFIG_JENABLE         0x0001  /* Jabber enable               */
+#define NCONFIG_RESV1           0x0002  /* Unused...                   */
+#define NCONFIG_SQUELCH         0x0004  /* Use low squelch             */
+#define NCONFIG_UTP             0x0008  /* 1=UTP, 0=STP                */
+#define NCONFIG_HBEAT           0x0010  /* Heart-beat enable           */
+#define NCONFIG_LDISABLE        0x0020  /* Disable the link            */
+#define NCONFIG_RESV2           0xffc0  /* Unused...                   */
+
+/* Happy Meal descriptor rings and such.
+ * All descriptor rings must be aligned on a 2K boundry.
+ * All receive buffers must be 64 byte aligned.
+ */
+struct happy_meal_rxd {
+	unsigned int rx_flags;
+	unsigned int rx_addr;
+};
+
+#define RXFLAG_OWN         0x80000000 /* 1 = hardware, 0 = software */
+#define RXFLAG_OVERFLOW    0x40000000 /* 1 = buffer overflow        */
+#define RXFLAG_SIZE        0x3fff0000 /* Size of the buffer         */
+#define RXFLAG_CSUM        0x0000ffff /* HW computed checksum       */
+
+struct happy_meal_txd {
+	unsigned int tx_flags;
+	unsigned int tx_addr;
+};
+
+#define TXFLAG_OWN         0x80000000 /* 1 = hardware, 0 = software */
+#define TXFLAG_SOP         0x40000000 /* 1 = start of packet        */
+#define TXFLAG_EOP         0x20000000 /* 1 = end of packet          */
+#define TXFLAG_CSENABLE    0x10000000 /* 1 = enable hw-checksums    */
+#define TXFLAG_CSLOCATION  0x0ff00000 /* Where to stick the csum    */
+#define TXFLAG_CSBUFBEGIN  0x000fc000 /* Where to begin checksum    */
+#define TXFLAG_SIZE        0x00003fff /* Size of the packet         */
+
+#define TX_RING_SIZE       32         /* Must be >16 and <255, multiple of 16  */
+#define RX_RING_SIZE       32         /* see ERX_CFG_SIZE* for possible values */
+
+#define TX_RING_MAXSIZE    256
+#define RX_RING_MAXSIZE    256
+
+/* 34 byte offset for checksum computation.  This works because ip_input() will clear out
+ * the skb->csum and skb->ip_summed fields and recompute the csum if IP options are
+ * present in the header.  34 == (ethernet header len) + sizeof(struct iphdr)
+ */
+#define ERX_CFG_DEFAULT(off) (ERX_CFG_DMAENABLE|((off)<<3)|ERX_CFG_SIZE32|(0x22<<16))
+
+#define NEXT_RX(num)       (((num) + 1) & (RX_RING_SIZE - 1))
+#define NEXT_TX(num)       (((num) + 1) & (TX_RING_SIZE - 1))
+#define PREV_RX(num)       (((num) - 1) & (RX_RING_SIZE - 1))
+#define PREV_TX(num)       (((num) - 1) & (TX_RING_SIZE - 1))
+
+#define TX_BUFFS_AVAIL(hp)                                    \
+        (((hp)->tx_old <= (hp)->tx_new) ?                     \
+	  (hp)->tx_old + (TX_RING_SIZE - 1) - (hp)->tx_new :  \
+			    (hp)->tx_old - (hp)->tx_new - 1)
+
+#define RX_OFFSET          2
+#define RX_BUF_ALLOC_SIZE  (ETH_FRAME_LEN + RX_OFFSET + (64 * 3))
+
+#define RX_COPY_THRESHOLD  128
+
+struct hmeal_init_block {
+	struct happy_meal_rxd happy_meal_rxd[RX_RING_MAXSIZE];
+	struct happy_meal_txd happy_meal_txd[TX_RING_MAXSIZE];
+};
+
+#define SUN4C_PKT_BUF_SZ	1546
+#define SUN4C_RX_BUFF_SIZE	SUN4C_PKT_BUF_SZ
+#define SUN4C_TX_BUFF_SIZE	SUN4C_PKT_BUF_SZ
+
+struct hmeal_buffers {
+	char	tx_buf[TX_RING_SIZE][SUN4C_TX_BUFF_SIZE];
+	char	rx_buf[RX_RING_SIZE][SUN4C_RX_BUFF_SIZE];
+};
+
+/* Now software state stuff. */
+enum happy_transceiver {
+	external = 0,
+	internal = 1,
+	none     = 2,
+};
+
+/* Timer state engine. */
+enum happy_timer_state {
+	arbwait  = 0,  /* Waiting for auto negotiation to complete.          */
+	lupwait  = 1,  /* Auto-neg complete, awaiting link-up status.        */
+	ltrywait = 2,  /* Forcing try of all modes, from fastest to slowest. */
+	asleep   = 3,  /* Time inactive.                                     */
+};
+
+/* Happy happy, joy joy! */
+struct happy_meal {
+	struct hmeal_gregs       *gregs;          /* Happy meal global registers       */
+	struct hmeal_etxregs     *etxregs;        /* External transmitter regs         */
+	struct hmeal_erxregs     *erxregs;        /* External receiver regs            */
+	struct hmeal_bigmacregs  *bigmacregs;     /* I said NO SOLARIS with my bigmac! */
+	struct hmeal_tcvregs     *tcvregs;        /* MIF transceiver regs              */
+
+	struct hmeal_init_block  *happy_block;    /* RX and TX descriptors             */
+
+	struct sk_buff           *rx_skbs[RX_RING_SIZE];
+	struct sk_buff           *tx_skbs[TX_RING_SIZE];
+
+	int rx_new, tx_new, rx_old, tx_old;
+
+	struct hmeal_buffers     *sun4c_buffers;
+
+	unsigned int              happy_flags;    /* Driver state flags                */
+	enum happy_transceiver    tcvr_type;      /* Kind of transceiver in use        */
+	unsigned int              happy_bursts;   /* Get your mind out of the gutter   */
+	unsigned int              paddr;          /* PHY address for transceiver       */
+	unsigned short            hm_revision;    /* Happy meal revision               */
+	unsigned short            sw_bmcr;        /* SW copy of BMCR                   */
+	unsigned short            sw_bmsr;        /* SW copy of BMSR                   */
+	unsigned short            sw_physid1;     /* SW copy of PHYSID1                */
+	unsigned short            sw_physid2;     /* SW copy of PHYSID2                */
+	unsigned short            sw_advertise;   /* SW copy of ADVERTISE              */
+	unsigned short            sw_lpa;         /* SW copy of LPA                    */
+	unsigned short            sw_expansion;   /* SW copy of EXPANSION              */
+	unsigned int              auto_speed;     /* Auto-nego link speed              */
+        unsigned int              forced_speed;   /* Force mode link speed             */
+	unsigned int              poll_data;      /* MIF poll data                     */
+	unsigned int              poll_flag;      /* MIF poll flag                     */
+	unsigned int              linkcheck;      /* Have we checked the link yet?     */
+	unsigned int              lnkup;          /* Is the link up as far as we know? */
+	unsigned int              lnkdown;        /* Trying to force the link down?    */
+	unsigned int              lnkcnt;         /* Counter for link-up attempts.     */
+	struct timer_list         happy_timer;    /* To watch the link when coming up. */
+	enum happy_timer_state    timer_state;    /* State of the auto-neg timer.      */
+	unsigned int              timer_ticks;    /* Number of clicks at each state.   */
+
+	struct enet_statistics    enet_stats;     /* Statistical counters              */
+	struct linux_sbus_device *happy_sbus_dev; /* ;-)                               */
+	struct device            *dev;            /* Backpointer                       */
+	struct happy_meal        *next_module;
+};
+
+/* Here are the happy flags. */
+#define HFLAG_POLL                0x00000001      /* We are doing MIF polling          */
+#define HFLAG_FENABLE             0x00000002      /* The MII frame is enabled          */
+#define HFLAG_LANCE               0x00000004      /* We are using lance-mode           */
+#define HFLAG_RXENABLE            0x00000008      /* Receiver is enabled               */
+#define HFLAG_AUTO                0x00000010      /* Using auto-negotiation, 0 = force */
+#define HFLAG_FULL                0x00000020      /* Full duplex enable                */
+#define HFLAG_MACFULL             0x00000040      /* Using full duplex in the MAC      */
+#define HFLAG_POLLENABLE          0x00000080      /* Actually try MIF polling          */
+#define HFLAG_RXCV                0x00000100      /* XXX RXCV ENABLE                   */
+#define HFLAG_INIT                0x00000200      /* Init called at least once         */
+#define HFLAG_LINKUP              0x00000400      /* 1 = Link is up                    */
+
+#define HFLAG_20_21  (HFLAG_POLLENABLE | HFLAG_FENABLE)
+#define HFLAG_NOT_A0 (HFLAG_POLLENABLE | HFLAG_FENABLE | HFLAG_LANCE | HFLAG_RXCV)
+
+/* We use this to acquire receive skb's that we can DMA directly into. */
+#define ALIGNED_RX_SKB_ADDR(addr) \
+        ((((unsigned long)(addr) + (64 - 1)) & ~(64 - 1)) - (unsigned long)(addr))
+static inline struct sk_buff *happy_meal_alloc_skb(unsigned int length, int gfp_flags)
+{
+	struct sk_buff *skb;
+
+	skb = alloc_skb(length + 64, gfp_flags);
+	if(skb) {
+		int offset = ALIGNED_RX_SKB_ADDR(skb->data);
+
+		if(offset)
+			skb_reserve(skb, offset);
+	}
+	return skb;
+}
+
+#endif /* !(_SUNHME_H) */
diff -u --recursive --new-file v2.1.15/linux/drivers/net/sunlance.c linux/drivers/net/sunlance.c
--- v2.1.15/linux/drivers/net/sunlance.c	Sun Apr 21 12:41:57 1996
+++ linux/drivers/net/sunlance.c	Fri Dec 13 11:37:32 1996
@@ -1,25 +1,51 @@
 /* lance.c: Linux/Sparc/Lance driver */
 /*
-	Written 1995, 1996 by Miguel de Icaza
+	 Written 1995, 1996 by Miguel de Icaza
   Sources:
-	The Linux  depca driver
-	The Linux  lance driver.
-	The Linux  skeleton driver.
-        The NetBSD Sparc/Lance driver.
-	Theo de Raadt (deraadt@openbsd.org)
-	NCR92C990 Lan Controller manual
+	 The Linux  depca driver
+	 The Linux  lance driver.
+	 The Linux  skeleton driver.
+         The NetBSD Sparc/Lance driver.
+	 Theo de Raadt (deraadt@openbsd.org)
+	 NCR92C990 Lan Controller manual
 
 1.4:
-	Added support to run with a ledma on the Sun4m
+	 Added support to run with a ledma on the Sun4m
 1.5:
-        Added multiple card detection.
+         Added multiple card detection.
+
+	 4/17/96: Burst sizes and tpe selection on sun4m by Eddie C. Dost
+	          (ecd@skynet.be)
+
+	 5/15/96: auto carrier detection on sun4m by Eddie C. Dost
+	          (ecd@skynet.be)
+
+         5/17/96: lebuffer on scsi/ether cards now work David S. Miller
+		  (davem@caip.rutgers.edu)
+
+	 5/29/96: override option 'tpe-link-test?', if it is 'false', as
+		  this disables auto carrier detection on sun4m. Eddie C. Dost
+	          (ecd@skynet.be)
+1.7:
+	 6/26/96: Bug fix for multiple ledmas, miguel.
+1.8:
+         Stole multicast code from depca.c, fixed lance_tx.
+1.9:
+         Fixed the multicast code (Pedro Roque)
+
+	 8/28/96: Send fake packet in lance_open() if auto_select is true,
+		  so we can detect the carrier loss condition in time.
+		  Eddie C. Dost (ecd@skynet.be)
+
+	 9/15/96: Align rx_buf so that eth_copy_and_sum() won't cause an
+		  MNA trap during chksum_partial_copy(). (ecd@skynet.be)
+
+	11/17/96: Handle LE_C0_MERR in lance_interrupt(). (ecd@skynet.be)
 
-	4/17/97: Burst sizes and tpe selection on sun4m by Christian Dost
-	         (ecd@pool.informatik.rwth-aachen.de)
 */
 #undef DEBUG_DRIVER
 static char *version =
-	"sunlance.c:v1.6 19/Apr/96 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
+	"sunlance.c:v1.9 21/Aug/96 Miguel de Icaza (miguel@nuclecu.unam.mx)\n";
 
 static char *lancestr = "LANCE";
 static char *lancedma = "LANCE DMA";
@@ -49,6 +75,7 @@
 #include <asm/sbus.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
+#include <asm/auxio.h>		/* For tpe-link-test? setting */
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -60,6 +87,9 @@
 #define LANCE_LOG_RX_BUFFERS 4
 #endif
 
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
+
 #define LE_CSR0 0
 #define LE_CSR1 1
 #define LE_CSR2 2
@@ -162,8 +192,9 @@
 	struct lance_rx_desc brx_ring[RX_RING_SIZE];
 	struct lance_tx_desc btx_ring[TX_RING_SIZE];
     
-	char   rx_buf [RX_RING_SIZE][RX_BUFF_SIZE];
 	char   tx_buf [TX_RING_SIZE][TX_BUFF_SIZE];
+	char   pad[2];			/* align rx_buf for copy_and_sum(). */
+	char   rx_buf [RX_RING_SIZE][RX_BUFF_SIZE];
 };
 
 struct lance_private {
@@ -178,7 +209,9 @@
 	struct Linux_SBus_DMA *ledma; /* if set this points to ledma and arch=4m */
 
 	int tpe;		      /* cable-selection is TPE */
+	int auto_select;	      /* cable-selection by carrier */
 	int burst_sizes;	      /* ledma SBus burst sizes */
+	unsigned short busmaster_regval, pio_buffer;
 };
 
 #define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
@@ -196,6 +229,11 @@
 /* The Lance uses 24 bit addresses */
 /* On the Sun4c the DVMA will provide the remaining bytes for us */
 /* On the Sun4m we have to instruct the ledma to provide them    */
+/* Even worse, on scsi/ether SBUS cards, the init block and the
+ * transmit/receive buffers are addresses as offsets from absolute
+ * zero on the lebuffer PIO area. -davem
+ */
+
 #define LANCE_ADDR(x) ((int)(x) & ~0xff000000)
 
 /* Load the CSR registers */
@@ -205,13 +243,16 @@
 	volatile struct lance_init_block *ib = lp->init_block;
 	int leptr;
 
-	leptr = LANCE_ADDR (ib);
+	if(lp->pio_buffer)
+		leptr = 0;
+	else
+		leptr = LANCE_ADDR (ib);
 	ll->rap = LE_CSR1;
 	ll->rdp = (leptr & 0xFFFF);
 	ll->rap = LE_CSR2;
 	ll->rdp = leptr >> 16;
 	ll->rap = LE_CSR3;
-	ll->rdp = LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON;
+	ll->rdp = lp->busmaster_regval;
 
 	/* Point back to csr0 */
 	ll->rap = LE_CSR0;
@@ -225,9 +266,15 @@
 {
 	struct lance_private *lp = (struct lance_private *) dev->priv;
 	volatile struct lance_init_block *ib = lp->init_block;
+	volatile struct lance_init_block *aib; /* for LANCE_ADDR computations */
 	int leptr;
 	int i;
     
+	if(lp->pio_buffer)
+		aib = 0;
+	else
+		aib = ib;
+
 	/* Lock out other processes while setting up hardware */
 	dev->tbusy = 1;
 	lp->rx_new = lp->tx_new = 0;
@@ -250,7 +297,7 @@
     
 	/* Setup the Tx ring entries */
 	for (i = 0; i <= TX_RING_SIZE; i++) {
-		leptr = LANCE_ADDR(&ib->tx_buf[i][0]);
+		leptr = LANCE_ADDR(&aib->tx_buf[i][0]);
 		ib->btx_ring [i].tmd0      = leptr;
 		ib->btx_ring [i].tmd1_hadr = leptr >> 16;
 		ib->btx_ring [i].tmd1_bits = 0;
@@ -264,7 +311,7 @@
 	if (ZERO)
 		printk ("RX rings:\n");
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		leptr = LANCE_ADDR(&ib->rx_buf[i][0]);
+		leptr = LANCE_ADDR(&aib->rx_buf[i][0]);
 
 		ib->brx_ring [i].rmd0      = leptr;
 		ib->brx_ring [i].rmd1_hadr = leptr >> 16;
@@ -278,14 +325,14 @@
 	/* Setup the initialization block */
     
 	/* Setup rx descriptor pointer */
-	leptr = LANCE_ADDR(&ib->brx_ring);
+	leptr = LANCE_ADDR(&aib->brx_ring);
 	ib->rx_len = (LANCE_LOG_RX_BUFFERS << 13) | (leptr >> 16);
 	ib->rx_ptr = leptr;
 	if (ZERO)
 		printk ("RX ptr: %8.8x\n", leptr);
     
 	/* Setup tx descriptor pointer */
-	leptr = LANCE_ADDR(&ib->btx_ring);
+	leptr = LANCE_ADDR(&aib->btx_ring);
 	ib->tx_len = (LANCE_LOG_TX_BUFFERS << 13) | (leptr >> 16);
 	ib->tx_ptr = leptr;
 	if (ZERO)
@@ -305,8 +352,11 @@
 		struct sparc_dma_registers *dregs = lp->ledma->regs;
 		unsigned long creg;
 
-		while (dregs->cond_reg & DMA_FIFO_ISDRAIN) /* E-Cache draining */
-			barrier();
+		if (!(dregs->cond_reg & DMA_HNDL_ERROR)) {
+			/* E-Cache draining */
+			while (dregs->cond_reg & DMA_FIFO_ISDRAIN)
+				barrier();
+		}
 
 		creg = dregs->cond_reg;
 		if (lp->burst_sizes & DMA_BURST32)
@@ -353,9 +403,10 @@
 {
 	struct lance_private *lp = (struct lance_private *) dev->priv;
 	volatile struct lance_init_block *ib = lp->init_block;
-	volatile struct lance_regs *ll = lp->ll;
 	volatile struct lance_rx_desc *rd;
 	unsigned char bits;
+	int len;
+	struct sk_buff *skb;
 
 #ifdef TEST_HITS
 	printk ("[");
@@ -370,12 +421,9 @@
 	printk ("]");
 #endif
     
-	ll->rdp = LE_C0_RINT|LE_C0_INEA;
 	for (rd = &ib->brx_ring [lp->rx_new];
 	     !((bits = rd->rmd1_bits) & LE_R1_OWN);
 	     rd = &ib->brx_ring [lp->rx_new]) {
-		int pkt_len;
-		struct sk_buff *skb;
 
 		/* We got an incomplete frame? */
 		if ((bits & LE_R1_POK) != LE_R1_POK) {
@@ -383,16 +431,19 @@
 			lp->stats.rx_errors++;
 			continue;
 		} else if (bits & LE_R1_ERR) {
-			/* Count only the end frame as a tx error, not the beginning */
+			/* Count only the end frame as a rx error,
+			 * not the beginning
+			 */
 			if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
 			if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
 			if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
 			if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
 			if (bits & LE_R1_EOP) lp->stats.rx_errors++;
 		} else {
-			pkt_len = rd->mblength;
-			skb = dev_alloc_skb (pkt_len+2);
-			if (skb == NULL) {
+			len = (rd->mblength & 0xfff) - 4;
+			skb = dev_alloc_skb (len+2);
+
+			if (skb == 0) {
 				printk ("%s: Memory squeeze, deferring packet.\n",
 					dev->name);
 				lp->stats.rx_dropped++;
@@ -403,12 +454,12 @@
 			}
 	    
 			skb->dev = dev;
-			skb_reserve (skb, 2);               /* 16 byte align */
-			skb_put (skb, pkt_len);             /* make room */
+			skb_reserve (skb, 2);		/* 16 byte align */
+			skb_put (skb, len);		/* make room */
 			eth_copy_and_sum(skb,
 					 (unsigned char *)&(ib->rx_buf [lp->rx_new][0]),
-					 pkt_len, 0);
-			skb->protocol = eth_type_trans (skb,dev);
+					 len, 0);
+			skb->protocol = eth_type_trans (skb, dev);
 			netif_rx (skb);
 			lp->stats.rx_packets++;
 		}
@@ -430,23 +481,40 @@
 	int i, j;
 	int status;
 
-	/* csr0 is 2f3 */
-	ll->rdp = LE_C0_TINT | LE_C0_INEA;
-	/* csr0 is 73 */
 	j = lp->tx_old;
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		td = &ib->btx_ring [j];
+	for (i = j; i != lp->tx_new; i = j) {
+		td = &ib->btx_ring [i];
 
+		/* If we hit a packet not owned by us, stop */
+		if (td->tmd1_bits & LE_T1_OWN)
+			break;
+		
 		if (td->tmd1_bits & LE_T1_ERR) {
 			status = td->misc;
 	    
 			lp->stats.tx_errors++;
 			if (status & LE_T3_RTY)  lp->stats.tx_aborted_errors++;
-			if (status & LE_T3_CLOS) lp->stats.tx_carrier_errors++;
 			if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
 
-			/* buffer errors and underflows turn off the transmitter */
-			/* Restart the adapter */
+			if (status & LE_T3_CLOS) {
+				lp->stats.tx_carrier_errors++;
+				if (lp->auto_select) {
+					lp->tpe = 1 - lp->tpe;
+					printk("%s: Carrier Lost, trying %s\n",
+					       dev->name, lp->tpe?"TPE":"AUI");
+					/* Stop the lance */
+					ll->rap = LE_CSR0;
+					ll->rdp = LE_C0_STOP;
+					lance_init_ring (dev);
+					load_csrs (lp);
+					init_restart_lance (lp);
+					return 0;
+				}
+			}
+
+			/* Buffer errors and underflows turn off the
+			 * transmitter, restart the adapter.
+			 */
 			if (status & (LE_T3_BUF|LE_T3_UFL)) {
 				lp->stats.tx_fifo_errors++;
 
@@ -474,58 +542,37 @@
 			if (td->tmd1_bits & LE_T1_EMORE)
 				lp->stats.collisions += 2;
 
-			/* What to set here? */
-			if (td->tmd1_bits & LE_T1_EDEF)
-				/* EMPTY */ ;
-
 			lp->stats.tx_packets++;
 		}
 	
 		j = (j + 1) & TX_RING_MOD_MASK;
 	}
-	lp->tx_old = (lp->tx_old+1) & TX_RING_MOD_MASK;
-
-	ll->rdp = LE_C0_TINT | LE_C0_INEA;
+	lp->tx_old = j;
 	return 0;
 }
 
 static void lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
 {
-	struct device *dev;
-	struct lance_private *lp;
-	volatile struct lance_regs *ll;
+	struct device *dev = (struct device *)dev_id;
+	struct lance_private *lp = (struct lance_private *)dev->priv;
+	volatile struct lance_regs *ll = lp->ll;
 	int csr0;
     
-#ifdef OLD_STYLE_IRQ
-	dev = (struct device *) (irq2dev_map [irq]);
-#else
-	dev = (struct device *) dev_id;
-#endif
-
-	lp = (struct lance_private *) dev->priv;
-	ll = lp->ll;
-
-	if (lp->ledma) {
-		if (lp->ledma->regs->cond_reg & DMA_HNDL_ERROR) {
-			printk ("%s: should reset my ledma (dmacsr=%8.8x, csr=%4.4x\n",
-				dev->name, (unsigned int) lp->ledma->regs->cond_reg,
-				ll->rdp); 
-			printk ("send mail to miguel@nuclecu.unam.mx\n");
-		}
-	}
 	if (dev->interrupt)
 		printk ("%s: again", dev->name);
     
 	dev->interrupt = 1;
 
+	ll->rap = LE_CSR0;
 	csr0 = ll->rdp;
 
 	/* Acknowledge all the interrupt sources ASAP */
-	ll->rdp = csr0 & 0x004f;
+	ll->rdp = csr0 & (LE_C0_INTR | LE_C0_TINT | LE_C0_RINT);
     
 	if ((csr0 & LE_C0_ERR)) {
 		/* Clear the error condition */
-		ll->rdp = LE_C0_BABL|LE_C0_ERR|LE_C0_MISS|LE_C0_INEA;
+		ll->rdp = LE_C0_BABL | LE_C0_ERR | LE_C0_MISS |
+			  LE_C0_CERR | LE_C0_MERR;
 	}
     
 	if (csr0 & LE_C0_RINT)
@@ -538,9 +585,32 @@
 		dev->tbusy = 0;
 		mark_bh (NET_BH);
 	}
-	ll->rap = LE_CSR0;
-	ll->rdp = 0x7940;
 
+	if (csr0 & LE_C0_BABL)
+		lp->stats.tx_errors++;
+
+	if (csr0 & LE_C0_MISS)
+		lp->stats.rx_errors++;
+
+	if (csr0 & LE_C0_MERR) {
+		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",
+			dev->name, csr0, tst & 0xffffff);
+
+		ll->rdp = LE_C0_STOP;
+
+		if (lp->ledma)
+			lp->ledma->regs->cond_reg |= DMA_FIFO_INV;
+
+		lance_init_ring (dev);
+		load_csrs (lp);
+		init_restart_lance (lp);
+		dev->tbusy = 0;
+	}
+
+	ll->rdp = LE_C0_INEA;
 	dev->interrupt = 0;
 }
 
@@ -554,7 +624,7 @@
 
 	last_dev = dev;
 
-	if (request_irq (dev->irq, &lance_interrupt, 0, lancestr, (void *) dev)) {
+	if (request_irq (dev->irq, &lance_interrupt, SA_SHIRQ, lancestr, (void *) dev)) {
 		printk ("Lance: Can't get irq %d\n", dev->irq);
 		return -EAGAIN;
 	}
@@ -563,10 +633,6 @@
 	ll->rap = LE_CSR0;
 	ll->rdp = LE_C0_STOP;
 
-#ifdef OLD_STYLE_IRQ
-	irq2dev_map [dev->irq] = dev;
-#endif
-
 	/* On the 4m, setup the ledma to provide the upper bits for buffers */
 	if (lp->ledma)
 		lp->ledma->regs->dma_test = ((unsigned int) lp->init_block) & 0xff000000;
@@ -586,6 +652,34 @@
 		ip_get_mask (dev->pa_addr),
 		0, dev, dev->mtu, 0, 0);
 #endif
+	if (!status && lp->auto_select) {
+		/*
+		 * Build a fake network packet and send it to ourselfs.
+		 */
+		volatile struct lance_init_block *ib = lp->init_block;
+		volatile unsigned long flush;
+		unsigned char packet[ETH_ZLEN];
+		struct ethhdr *eth = (struct ethhdr *)packet;
+		int i, entry;
+
+		memset(packet, 0, ETH_ZLEN);
+		for (i = 0; i < 6; i++) {
+			eth->h_dest[i] = dev->dev_addr[i];
+			eth->h_source[i] = dev->dev_addr[i];
+		}
+
+		entry = lp->tx_new & TX_RING_MOD_MASK;
+		ib->btx_ring[entry].length = (-ETH_ZLEN) | 0xf000;
+		ib->btx_ring[entry].misc = 0;
+
+		memcpy((char *)&ib->tx_buf[entry][0], packet, ETH_ZLEN);
+		ib->btx_ring[entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
+		lp->tx_new = (lp->tx_new + 1) & TX_RING_MOD_MASK;
+
+		ll->rdp = LE_C0_INEA | LE_C0_TDMD;
+		flush = ll->rdp;
+	}
+
 	return status;
 }
 
@@ -601,10 +695,7 @@
 	ll->rap = LE_CSR0;
 	ll->rdp = LE_C0_STOP;
 
-	free_irq (dev->irq, NULL);
-#ifdef OLD_STYLE_IRQ
-	irq2dev_map [dev->irq] = NULL;
-#endif
+	free_irq (dev->irq, (void *) dev);
     
 	return 0;
 }
@@ -671,7 +762,7 @@
 	}
 
 	if (skb->len <= 0) {
-		printk ("skb len is %ld\n", skb->len);
+		printk ("skb len is %d\n", skb->len);
 		return 0;
 	}
 	/* Block a timer-based transmit from overlapping. */
@@ -739,22 +830,83 @@
 	return &lp->stats;
 }
 
+/* taken from the depca driver */
+static void lance_load_multicast (struct device *dev)
+{
+	struct lance_private *lp = (struct lance_private *) dev->priv;
+	volatile struct lance_init_block *ib = lp->init_block;
+	volatile u16 *mcast_table = (u16 *)&ib->filter;
+	struct dev_mc_list *dmi=dev->mc_list;
+	char *addrs;
+	int i, j, bit, byte;
+	u32 crc, poly = CRC_POLYNOMIAL_LE;
+	
+	/* set all multicast bits */
+	if (dev->flags & IFF_ALLMULTI){ 
+		ib->filter [0] = 0xffffffff;
+		ib->filter [1] = 0xffffffff;
+		return;
+	}
+	/* clear the multicast filter */
+	ib->filter [0] = 0;
+	ib->filter [1] = 0;
+
+	/* Add addresses */
+	for (i = 0; i < dev->mc_count; i++){
+		addrs = dmi->dmi_addr;
+		dmi   = dmi->next;
+
+		/* multicast address? */
+		if (!(*addrs & 1))
+			continue;
+		
+		crc = 0xffffffff;
+		for (byte = 0; byte < 6; byte++)
+			for (bit = *addrs++, j = 0; j < 8; j++, bit>>=1)
+			{
+				int test;
+
+				test = ((bit ^ crc) & 0x01);
+				crc >>= 1;
+
+				if (test)
+				{
+					crc = crc ^ poly;
+				}
+			}
+		
+		crc = crc >> 26;
+		mcast_table [crc >> 4] |= 1 << (crc & 0xf);
+	}
+	return;
+}
+
 static void lance_set_multicast (struct device *dev)
 {
-#ifdef NOT_YET
 	struct lance_private *lp = (struct lance_private *) dev->priv;
 	volatile struct lance_init_block *ib = lp->init_block;
 	volatile struct lance_regs *ll = lp->ll;
 
+	while (dev->tbusy)
+		schedule();
+	set_bit (0, (void *) &dev->tbusy);
+
+	while (lp->tx_old != lp->tx_new)
+		schedule();
+
 	ll->rap = LE_CSR0;
 	ll->rdp = LE_C0_STOP;
 	lance_init_ring (dev);
-	ib->mode |= LE_MO_PROM;
-	lance_init_ring (dev);
+
+	if (dev->flags & IFF_PROMISC) {
+		ib->mode |= LE_MO_PROM;
+	} else {
+		ib->mode &= ~LE_MO_PROM;
+		lance_load_multicast (dev);
+	}
 	load_csrs (lp);
 	init_restart_lance (lp);
 	dev->tbusy = 0;
-#endif
 }
 
 int sparc_lance_init (struct device *dev, struct linux_sbus_device *sdev,
@@ -786,11 +938,11 @@
 	 */
 	for (i = 0; i < 6; i++)
 		printk ("%2.2x%c",
-			dev->dev_addr [i] = idprom->id_eaddr [i], i == 5 ? ' ': ':');
+			dev->dev_addr[i] = idprom->id_ethaddr[i], i == 5 ? ' ': ':');
 	printk("\n");
 
 	/* Get the IO region */
-	prom_apply_sbus_ranges (&sdev->reg_addrs [0], sdev->num_registers);
+	prom_apply_sbus_ranges (sdev->my_bus, &sdev->reg_addrs [0], sdev->num_registers);
 	ll = sparc_alloc_io (sdev->reg_addrs [0].phys_addr, 0,
 			     sizeof (struct lance_regs), lancestr,
 			     sdev->reg_addrs[0].which_io, 0x0);
@@ -801,16 +953,21 @@
 	memset ((char *)dev->priv, 0, sizeof (struct lance_private));
 
 	if (lebuffer){
-		prom_apply_sbus_ranges (&sdev->reg_addrs [0], sdev->num_registers);
+		prom_apply_sbus_ranges (lebuffer->my_bus, &lebuffer->reg_addrs [0],
+					lebuffer->num_registers);
 		lp->init_block = (void *)
 			sparc_alloc_io (lebuffer->reg_addrs [0].phys_addr, 0,
 				sizeof (struct lance_init_block), "lebuffer", 
 				lebuffer->reg_addrs [0].which_io, 0);
+		lp->pio_buffer = 1;
 	} else {
 		lp->init_block = (void *)
 			sparc_dvma_malloc (sizeof (struct lance_init_block),
 				   lancedma);
+		lp->pio_buffer = 0;
 	}
+	lp->busmaster_regval = prom_getintdefault(sdev->prom_node, "busmaster-regval",
+						  (LE_C3_BSWP|LE_C3_ACON|LE_C3_BCON));
     
 	lp->ll = ll;
 	lp->name = lancestr;
@@ -818,7 +975,7 @@
 
 	lp->burst_sizes = 0;
 	if (lp->ledma) {
-		char cable_prop[4];
+		char prop[6];
 		unsigned int sbmask;
 
 		/* Find burst-size property for ledma */
@@ -831,12 +988,48 @@
 		lp->burst_sizes &= sbmask;
 
 		/* Get the cable-selection property */
+		memset(prop, 0, sizeof(prop));
 		prom_getstring(ledma->SBus_dev->prom_node, "cable-selection",
-			       cable_prop, sizeof(cable_prop));
-		if (!strcmp(cable_prop, "aui"))
+			       prop, sizeof(prop));
+		if (prop[0] == 0) {
+			int topnd, nd;
+
+			printk("%s: using auto-carrier-detection.\n",
+			       dev->name);
+
+			/* Is this found at /options .attributes in all
+			 * Prom versions? XXX
+			 */
+			topnd = prom_getchild(prom_root_node);
+
+			nd = prom_searchsiblings(topnd, "options");
+			if (!nd)
+				goto no_link_test;
+
+			if (!prom_node_has_property(nd, "tpe-link-test?"))
+				goto no_link_test;
+
+			memset(prop, 0, sizeof(prop));
+			prom_getstring(nd, "tpe-link-test?", prop,
+				       sizeof(prop));
+
+			if (strcmp(prop, "true")) {
+				printk("%s: warning: overriding option 'tpe-link-test?'\n",
+				       dev->name);
+				printk("%s: warning: mail any problems to ecd@skynet.be\n",
+				       dev->name);
+				set_auxio(AUXIO_LINK_TEST, 0);
+			}
+no_link_test:
+			lp->auto_select = 1;
 			lp->tpe = 0;
-		else
+		} else if (!strcmp(prop, "aui")) {
+			lp->auto_select = 0;
+			lp->tpe = 0;
+		} else {
+			lp->auto_select = 0;
 			lp->tpe = 1;
+		}
 
 		/* Reset ledma */
 		lp->ledma->regs->cond_reg |= DMA_RST_ENET;
@@ -881,30 +1074,33 @@
 	struct linux_sbus *bus;
 	struct linux_sbus_device *sdev = 0;
 	struct Linux_SBus_DMA *ledma = 0;
+	static int called = 0;
 	int cards = 0, v;
     
+	if(called)
+		return ENODEV;
+	called++;
 	for_each_sbus (bus) {
 		for_each_sbusdev (sdev, bus) {
 			if (cards) dev = NULL;
 			if (strcmp (sdev->prom_name, "le") == 0) {
 				cards++;
-				if ((v = sparc_lance_init(dev, sdev, ledma,0)))
+				if ((v = sparc_lance_init(dev, sdev, 0, 0)))
 					return v;
+				continue;
 			}
 			if (strcmp (sdev->prom_name, "ledma") == 0) {
 				cards++;
 				ledma = find_ledma (sdev);
-				sdev = sdev->child;
-				if ((v = sparc_lance_init(dev, sdev, ledma,0)))
+				if ((v = sparc_lance_init(dev, sdev->child, ledma, 0)))
 					return v;
-				break;
+				continue;
 			}
 			if (strcmp (sdev->prom_name, "lebuffer") == 0){
-				struct linux_sbus_device *le = sdev->child;
 				cards++;
-				if ((v = sparc_lance_init(dev, le, ledma,sdev)))
+				if ((v = sparc_lance_init(dev, sdev->child, 0, sdev)))
 					return v;
-				break;
+				continue;
 			}
 		} /* for each sbusdev */
 	} /* for each sbus */
diff -u --recursive --new-file v2.1.15/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c
--- v2.1.15/linux/drivers/net/sunqe.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/sunqe.c	Fri Dec 13 11:37:32 1996
@@ -0,0 +1,1210 @@
+/* sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
+ *          Once again I am out to prove that every ethernet
+ *          controller out there can be most efficiently programmed
+ *          if you make it look like a LANCE.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+static char *version =
+        "sunqe.c:v1.1 8/Nov/96 David S. Miller (davem@caipfs.rutgers.edu)\n";
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+#include <asm/byteorder.h>
+
+#include <asm/idprom.h>
+#include <asm/sbus.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/auxio.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "sunqe.h"
+
+#ifdef MODULE
+static struct sunqec *root_qec_dev = NULL;
+#endif
+
+#define QEC_RESET_TRIES 200
+
+static inline int qec_global_reset(struct qe_globreg *gregs)
+{
+	int tries = QEC_RESET_TRIES;
+
+	gregs->ctrl = GLOB_CTRL_RESET;
+	while(--tries) {
+		if(gregs->ctrl & GLOB_CTRL_RESET) {
+			udelay(20);
+			continue;
+		}
+		break;
+	}
+	if(tries)
+		return 0;
+	printk("QuadEther: AIEEE cannot reset the QEC!\n");
+	return -1;
+}
+
+#define MACE_RESET_RETRIES 200
+#define QE_RESET_RETRIES   200
+
+static inline int qe_stop(struct sunqe *qep)
+{
+	struct qe_creg *cregs = qep->qcregs;
+	struct qe_mregs *mregs = qep->mregs;
+	int tries;
+
+	/* Reset the MACE, then the QEC channel. */
+	mregs->bconfig = MREGS_BCONFIG_RESET;
+	tries = MACE_RESET_RETRIES;
+	while(--tries) {
+		if(mregs->bconfig & MREGS_BCONFIG_RESET) {
+			udelay(20);
+			continue;
+		}
+		break;
+	}
+	if(!tries) {
+		printk("QuadEther: AIEEE cannot reset the MACE!\n");
+		return -1;
+	}
+
+	cregs->ctrl = CREG_CTRL_RESET;
+	tries = QE_RESET_RETRIES;
+	while(--tries) {
+		if(cregs->ctrl & CREG_CTRL_RESET) {
+			udelay(20);
+			continue;
+		}
+		break;
+	}
+	if(!tries) {
+		printk("QuadEther: Cannot reset QE channel!\n");
+		return -1;
+	}
+	return 0;
+}
+
+static inline void qe_clean_rings(struct sunqe *qep)
+{
+	int i;
+
+	for(i = 0; i < RX_RING_SIZE; i++) {
+		if(qep->rx_skbs[i] != NULL) {
+			dev_kfree_skb(qep->rx_skbs[i], FREE_READ);
+			qep->rx_skbs[i] = NULL;
+		}
+	}
+
+	for(i = 0; i < TX_RING_SIZE; i++) {
+		if(qep->tx_skbs[i] != NULL) {
+			dev_kfree_skb(qep->tx_skbs[i], FREE_WRITE);
+			qep->tx_skbs[i] = NULL;
+		}
+	}
+}
+
+static void qe_init_rings(struct sunqe *qep, int from_irq)
+{
+	struct qe_init_block *qb = qep->qe_block;
+	struct device *dev = qep->dev;
+	int i, gfp_flags = GFP_KERNEL;
+
+	if(from_irq || intr_count)
+		gfp_flags = GFP_ATOMIC;
+
+	qep->rx_new = qep->rx_old = qep->tx_new = qep->tx_old = 0;
+
+	qe_clean_rings(qep);
+
+	for(i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb;
+
+		skb = qe_alloc_skb(RX_BUF_ALLOC_SIZE, gfp_flags);
+		if(!skb)
+			continue;
+
+		qep->rx_skbs[i] = skb;
+		skb->dev = dev;
+
+		skb_put(skb, ETH_FRAME_LEN);
+		skb_reserve(skb, 34);
+		qb->qe_rxd[i].rx_addr = (unsigned int) skb->data;
+		qb->qe_rxd[i].rx_flags =
+			(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
+	}
+
+	for(i = 0; i < TX_RING_SIZE; i++)
+		qb->qe_txd[i].tx_flags = qb->qe_txd[i].tx_addr = 0;
+}
+
+static void sun4c_qe_init_rings(struct sunqe *qep)
+{
+	struct qe_init_block *qb = qep->qe_block;
+	struct sunqe_buffers *qbufs = qep->sun4c_buffers;
+	int i;
+
+	qep->rx_new = qep->rx_old = qep->tx_new = qep->tx_old = 0;
+
+	memset(qbufs, 0, sizeof(struct sunqe_buffers));
+
+	for(i = 0; i < RX_RING_SIZE; i++)
+		qb->qe_rxd[i].rx_flags = qb->qe_rxd[i].rx_addr = 0;
+
+	for(i = 0; i < SUN4C_RX_RING_SIZE; i++) {
+		qb->qe_rxd[i].rx_addr = (unsigned int) &qbufs->rx_buf[i][0];
+		qb->qe_rxd[i].rx_flags =
+			(RXD_OWN | ((SUN4C_RX_BUFF_SIZE) & RXD_LENGTH));
+	}
+
+	for(i = 0; i < TX_RING_SIZE; i++)
+		qb->qe_txd[i].tx_flags = qb->qe_txd[i].tx_addr = 0;
+}
+
+static int qe_init(struct sunqe *qep, int from_irq)
+{
+	struct sunqec *qecp = qep->parent;
+	struct qe_creg *cregs = qep->qcregs;
+	struct qe_mregs *mregs = qep->mregs;
+	struct qe_globreg *gregs = qecp->gregs;
+	unsigned char *e = &qep->dev->dev_addr[0];
+	volatile unsigned char garbage;
+	int i;
+
+	/* Shut it up. */
+	if(qe_stop(qep))
+		return -EAGAIN;
+
+	/* Setup initial rx/tx init block pointers. */
+	cregs->rxds = (unsigned int) &qep->qe_block->qe_rxd[0];
+	cregs->txds = (unsigned int) &qep->qe_block->qe_txd[0];
+
+	/* Enable the various irq's. */
+	cregs->rimask = 0;
+	cregs->timask = 0;
+	cregs->qmask = 0;
+	cregs->mmask = CREG_MMASK_RXCOLL;
+
+	/* Setup the FIFO pointers into QEC local memory. */
+	cregs->rxwbufptr = cregs->rxrbufptr = qep->channel * gregs->msize;
+	cregs->txwbufptr = cregs->txrbufptr = cregs->rxrbufptr + gregs->rsize;
+
+	/* Clear the channel collision counter. */
+	cregs->ccnt = 0;
+
+	/* For 10baseT, inter frame space nor throttle seems to be necessary. */
+	cregs->pipg = 0;
+
+	/* Now dork with the AMD MACE. */
+	mregs->txfcntl = MREGS_TXFCNTL_AUTOPAD; /* Save us some tx work. */
+	mregs->rxfcntl = 0;
+
+	/* The QEC dma's the rx'd packets from local memory out to main memory,
+	 * and therefore it interrupts when the packet reception is "complete".
+	 * So don't listen for the MACE talking about it.
+	 */
+	mregs->imask = (MREGS_IMASK_COLL | MREGS_IMASK_RXIRQ);
+
+	mregs->bconfig = (MREGS_BCONFIG_BSWAP | MREGS_BCONFIG_64TS);
+	mregs->fconfig = (MREGS_FCONFIG_TXF16 | MREGS_FCONFIG_RXF32 |
+			  MREGS_FCONFIG_RFWU | MREGS_FCONFIG_TFWU);
+
+	/* Only usable interface on QuadEther is twisted pair. */
+	mregs->plsconfig = (MREGS_PLSCONFIG_TP);
+
+	/* Tell MACE we are changing the ether address. */
+	mregs->iaconfig = (MREGS_IACONFIG_ACHNGE | MREGS_IACONFIG_PARESET);
+	mregs->ethaddr = e[0];
+	mregs->ethaddr = e[1];
+	mregs->ethaddr = e[2];
+	mregs->ethaddr = e[3];
+	mregs->ethaddr = e[4];
+	mregs->ethaddr = e[5];
+
+	/* Clear out the address filter. */
+	mregs->iaconfig = (MREGS_IACONFIG_ACHNGE | MREGS_IACONFIG_LARESET);
+	for(i = 0; i < 8; i++) mregs->filter = 0;
+
+	/* Address changes are now complete. */
+	mregs->iaconfig = 0;
+
+	if(sparc_cpu_model == sun4c)
+		sun4c_qe_init_rings(qep);
+	else
+		qe_init_rings(qep, from_irq);
+
+	/* Wait a little bit for the link to come up... */
+	if(!(mregs->phyconfig & MREGS_PHYCONFIG_LTESTDIS)) {
+		udelay(5000);
+		if(!(mregs->phyconfig & MREGS_PHYCONFIG_LSTAT))
+			printk("%s: Warning, link state is down.\n", qep->dev->name);
+	}
+
+	/* Missed packet counter is cleared on a read. */
+	garbage = mregs->mpcnt;
+
+	/* Turn on the MACE receiver and transmitter. */
+	mregs->mconfig = (MREGS_MCONFIG_TXENAB | MREGS_MCONFIG_RXENAB);
+
+	/* QEC should now start to show interrupts. */
+	return 0;
+}
+
+/* Grrr, certain error conditions completely lock up the AMD MACE,
+ * so when we get these we _must_ reset the chip.
+ */
+static int qe_is_bolixed(struct sunqe *qep, unsigned int qe_status)
+{
+	struct device *dev = qep->dev;
+	int mace_hwbug_workaround = 0;
+
+	if(qe_status & CREG_STAT_EDEFER) {
+		printk("%s: Excessive transmit defers.\n", dev->name);
+		qep->enet_stats.tx_errors++;
+	}
+
+	if(qe_status & CREG_STAT_CLOSS) {
+		printk("%s: Carrier lost, link down?\n", dev->name);
+		qep->enet_stats.tx_errors++;
+		qep->enet_stats.tx_carrier_errors++;
+	}
+
+	if(qe_status & CREG_STAT_ERETRIES) {
+		printk("%s: Excessive transmit retries (more than 16).\n", dev->name);
+		qep->enet_stats.tx_errors++;
+		mace_hwbug_workaround = 1;
+	}
+
+	if(qe_status & CREG_STAT_LCOLL) {
+		printk("%s: Late transmit collision.\n", dev->name);
+		qep->enet_stats.tx_errors++;
+		qep->enet_stats.collisions++;
+		mace_hwbug_workaround = 1;
+	}
+
+	if(qe_status & CREG_STAT_FUFLOW) {
+		printk("%s: Transmit fifo underflow, driver bug.\n", dev->name);
+		qep->enet_stats.tx_errors++;
+		mace_hwbug_workaround = 1;
+	}
+
+	if(qe_status & CREG_STAT_JERROR) {
+		printk("%s: Jabber error.\n", dev->name);
+	}
+
+	if(qe_status & CREG_STAT_BERROR) {
+		printk("%s: Babble error.\n", dev->name);
+	}
+
+	if(qe_status & CREG_STAT_CCOFLOW) {
+		qep->enet_stats.tx_errors += 256;
+		qep->enet_stats.collisions += 256;
+	}
+
+	if(qe_status & CREG_STAT_TXDERROR) {
+		printk("%s: Transmit descriptor is bogus, driver bug.\n", dev->name);
+		qep->enet_stats.tx_errors++;
+		qep->enet_stats.tx_aborted_errors++;
+		mace_hwbug_workaround = 1;
+	}
+
+	if(qe_status & CREG_STAT_TXLERR) {
+		printk("%s: Transmit late error.\n", dev->name);
+		qep->enet_stats.tx_errors++;
+		mace_hwbug_workaround = 1;
+	}
+
+	if(qe_status & CREG_STAT_TXPERR) {
+		printk("%s: Transmit DMA parity error.\n", dev->name);
+		qep->enet_stats.tx_errors++;
+		qep->enet_stats.tx_aborted_errors++;
+		mace_hwbug_workaround = 1;
+	}
+
+	if(qe_status & CREG_STAT_TXSERR) {
+		printk("%s: Transmit DMA sbus error ack.\n", dev->name);
+		qep->enet_stats.tx_errors++;
+		qep->enet_stats.tx_aborted_errors++;
+		mace_hwbug_workaround = 1;
+	}
+
+	if(qe_status & CREG_STAT_RCCOFLOW) {
+		qep->enet_stats.rx_errors += 256;
+		qep->enet_stats.collisions += 256;
+	}
+
+	if(qe_status & CREG_STAT_RUOFLOW) {
+		qep->enet_stats.rx_errors += 256;
+		qep->enet_stats.rx_over_errors += 256;
+	}
+
+	if(qe_status & CREG_STAT_MCOFLOW) {
+		qep->enet_stats.rx_errors += 256;
+		qep->enet_stats.rx_missed_errors += 256;
+	}
+
+	if(qe_status & CREG_STAT_RXFOFLOW) {
+		printk("%s: Receive fifo overflow.\n", dev->name);
+		qep->enet_stats.rx_errors++;
+		qep->enet_stats.rx_over_errors++;
+	}
+
+	if(qe_status & CREG_STAT_RLCOLL) {
+		printk("%s: Late receive collision.\n", dev->name);
+		qep->enet_stats.rx_errors++;
+		qep->enet_stats.collisions++;
+	}
+
+	if(qe_status & CREG_STAT_FCOFLOW) {
+		qep->enet_stats.rx_errors += 256;
+		qep->enet_stats.rx_frame_errors += 256;
+	}
+
+	if(qe_status & CREG_STAT_CECOFLOW) {
+		qep->enet_stats.rx_errors += 256;
+		qep->enet_stats.rx_crc_errors += 256;
+	}
+
+	if(qe_status & CREG_STAT_RXDROP) {
+		printk("%s: Receive packet dropped.\n", dev->name);
+		qep->enet_stats.rx_errors++;
+		qep->enet_stats.rx_dropped++;
+		qep->enet_stats.rx_missed_errors++;
+	}
+
+	if(qe_status & CREG_STAT_RXSMALL) {
+		printk("%s: Receive buffer too small, driver bug.\n", dev->name);
+		qep->enet_stats.rx_errors++;
+		qep->enet_stats.rx_length_errors++;
+	}
+
+	if(qe_status & CREG_STAT_RXLERR) {
+		printk("%s: Receive late error.\n", dev->name);
+		qep->enet_stats.rx_errors++;
+		mace_hwbug_workaround = 1;
+	}
+
+	if(qe_status & CREG_STAT_RXPERR) {
+		printk("%s: Receive DMA parity error.\n", dev->name);
+		qep->enet_stats.rx_errors++;
+		qep->enet_stats.rx_missed_errors++;
+		mace_hwbug_workaround = 1;
+	}
+
+	if(qe_status & CREG_STAT_RXSERR) {
+		printk("%s: Receive DMA sbus error ack.\n", dev->name);
+		qep->enet_stats.rx_errors++;
+		qep->enet_stats.rx_missed_errors++;
+		mace_hwbug_workaround = 1;
+	}
+
+	if(mace_hwbug_workaround)
+		qe_init(qep, 1);
+	return mace_hwbug_workaround;
+}
+
+/* Per-QE transmit complete interrupt service routine. */
+static inline void qe_tx(struct sunqe *qep)
+{
+	struct qe_txd *txbase = &qep->qe_block->qe_txd[0];
+	struct qe_txd *this;
+	int elem = qep->tx_old;
+
+	while(elem != qep->tx_new) {
+		struct sk_buff *skb;
+
+		this = &txbase[elem];
+		if(this->tx_flags & TXD_OWN)
+			break;
+		skb = qep->tx_skbs[elem];
+		qep->tx_skbs[elem] = NULL;
+		dev_kfree_skb(skb, FREE_WRITE);
+
+		qep->enet_stats.tx_packets++;
+		elem = NEXT_TX(elem);
+	}
+	qep->tx_old = elem;
+}
+
+static inline void sun4c_qe_tx(struct sunqe *qep)
+{
+	struct qe_txd *txbase = &qep->qe_block->qe_txd[0];
+	struct qe_txd *this;
+	int elem = qep->tx_old;
+
+	while(elem != qep->tx_new) {
+		this = &txbase[elem];
+		if(this->tx_flags & TXD_OWN)
+			break;
+		qep->enet_stats.tx_packets++;
+		elem = NEXT_TX(elem);
+	}
+	qep->tx_old = elem;
+}
+
+/* Per-QE receive interrupt service routine.  Just like on the happy meal
+ * we receive directly into skb's with a small packet copy water mark.
+ */
+static inline void qe_rx(struct sunqe *qep)
+{
+	struct qe_rxd *rxbase = &qep->qe_block->qe_rxd[0];
+	struct qe_rxd *this;
+	int elem = qep->rx_new, drops = 0;
+
+	this = &rxbase[elem];
+	while(!(this->rx_flags & RXD_OWN)) {
+		struct sk_buff *skb;
+		unsigned int flags = this->rx_flags;
+		int len = (flags & RXD_LENGTH) - 4;  /* QE adds ether FCS size to len */
+
+		/* Check for errors. */
+		if(len < ETH_ZLEN) {
+			qep->enet_stats.rx_errors++;
+			qep->enet_stats.rx_length_errors++;
+
+	drop_it:
+			/* Return it to the QE. */
+			qep->enet_stats.rx_dropped++;
+			this->rx_addr = (unsigned int) qep->rx_skbs[elem]->data;
+			this->rx_flags =
+				(RXD_OWN | (RX_BUF_ALLOC_SIZE & RXD_LENGTH));
+			goto next;
+		}
+		skb = qep->rx_skbs[elem];
+		if(len > RX_COPY_THRESHOLD) {
+			struct sk_buff *new_skb;
+
+			/* Now refill the entry, if we can. */
+			new_skb = qe_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
+			if(!new_skb) {
+				drops++;
+				goto drop_it;
+			}
+
+			qep->rx_skbs[elem] = new_skb;
+			new_skb->dev = qep->dev;
+			skb_put(new_skb, ETH_FRAME_LEN);
+			skb_reserve(new_skb, 34);
+			rxbase[elem].rx_addr = (unsigned int) new_skb->data;
+			rxbase[elem].rx_flags =
+				(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
+
+			/* Trim the original skb for the netif. */
+			skb_trim(skb, len);
+		} else {
+			struct sk_buff *copy_skb = dev_alloc_skb(len + 2);
+
+			if(!copy_skb) {
+				drops++;
+				goto drop_it;
+			}
+
+			copy_skb->dev = qep->dev;
+			skb_reserve(copy_skb, 2);
+			skb_put(copy_skb, len);
+			eth_copy_and_sum(copy_skb, (unsigned char *)skb->data, len, 0);
+
+			/* Reuse original ring buffer. */
+			rxbase[elem].rx_addr = (unsigned int) skb->data;
+			rxbase[elem].rx_flags =
+				(RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
+
+			skb = copy_skb;
+		}
+
+		/* No checksums are done by this card ;-( */
+		skb->protocol = eth_type_trans(skb, qep->dev);
+		netif_rx(skb);
+		qep->enet_stats.rx_packets++;
+	next:
+		elem = NEXT_RX(elem);
+		this = &rxbase[elem];
+	}
+	qep->rx_new = elem;
+	if(drops)
+		printk("%s: Memory squeeze, deferring packet.\n", qep->dev->name);
+}
+
+static inline void sun4c_qe_rx(struct sunqe *qep)
+{
+	struct qe_rxd *rxbase = &qep->qe_block->qe_rxd[0];
+	struct qe_rxd *this;
+	struct sunqe_buffers *qbufs = qep->sun4c_buffers;
+	int elem = qep->rx_new, drops = 0;
+
+	this = &rxbase[elem];
+	while(!(this->rx_flags & RXD_OWN)) {
+		struct sk_buff *skb;
+		unsigned char *this_qbuf =
+			qbufs->rx_buf[elem & (SUN4C_RX_RING_SIZE - 1)];
+		struct qe_rxd *end_rxd =
+			&rxbase[(elem+SUN4C_RX_RING_SIZE)&(RX_RING_SIZE-1)];
+		unsigned int flags = this->rx_flags;
+		int len = (flags & RXD_LENGTH) - 4;  /* QE adds ether FCS size to len */
+
+		/* Check for errors. */
+		if(len < ETH_ZLEN) {
+			qep->enet_stats.rx_errors++;
+			qep->enet_stats.rx_length_errors++;
+			qep->enet_stats.rx_dropped++;
+		} else {
+			skb = dev_alloc_skb(len + 2);
+			if(skb == 0) {
+				drops++;
+				qep->enet_stats.rx_dropped++;
+			} else {
+				skb->dev = qep->dev;
+				skb_reserve(skb, 2);
+				skb_put(skb, len);
+				eth_copy_and_sum(skb, (unsigned char *)this_qbuf,
+						 len, 0);
+				skb->protocol = eth_type_trans(skb, qep->dev);
+				netif_rx(skb);
+				qep->enet_stats.rx_packets++;
+			}
+		}
+		end_rxd->rx_addr = (unsigned int) this_qbuf;
+		end_rxd->rx_flags = (RXD_OWN | (SUN4C_RX_BUFF_SIZE & RXD_LENGTH));
+		
+		elem = NEXT_RX(elem);
+		this = &rxbase[elem];
+	}
+	qep->rx_new = elem;
+	if(drops)
+		printk("%s: Memory squeeze, deferring packet.\n", qep->dev->name);
+}
+
+/* Interrupts for all QE's get filtered out via the QEC master controller,
+ * so we just run through each qe and check to see who is signaling
+ * and thus needs to be serviced.
+ */
+static void qec_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct sunqec *qecp = (struct sunqec *) dev_id;
+	unsigned int qec_status;
+	int channel = 0;
+
+	/* Latch the status now. */
+	qec_status = qecp->gregs->stat;
+	while(channel < 4) {
+		if(qec_status & 0xf) {
+			struct sunqe *qep = qecp->qes[channel];
+			struct device *dev = qep->dev;
+			unsigned int qe_status;
+
+			dev->interrupt = 1;
+
+			qe_status = qep->qcregs->stat;
+			if(qe_status & CREG_STAT_ERRORS)
+				if(qe_is_bolixed(qep, qe_status))
+					goto next;
+
+			if(qe_status & CREG_STAT_RXIRQ)
+				qe_rx(qep);
+
+			if(qe_status & CREG_STAT_TXIRQ)
+				qe_tx(qep);
+
+			if(dev->tbusy && (TX_BUFFS_AVAIL(qep) >= 0)) {
+				dev->tbusy = 0;
+				mark_bh(NET_BH);
+			}
+
+	next:
+			dev->interrupt = 0;
+		}
+		qec_status >>= 4;
+		channel++;
+	}
+}
+
+static void sun4c_qec_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct sunqec *qecp = (struct sunqec *) dev_id;
+	unsigned int qec_status;
+	int channel = 0;
+
+	/* Latch the status now. */
+	qec_status = qecp->gregs->stat;
+	while(channel < 4) {
+		if(qec_status & 0xf) {
+			struct sunqe *qep = qecp->qes[channel];
+			struct device *dev = qep->dev;
+			unsigned int qe_status;
+
+			dev->interrupt = 1;
+
+			qe_status = qep->qcregs->stat;
+			if(qe_status & CREG_STAT_ERRORS)
+				if(qe_is_bolixed(qep, qe_status))
+					goto next;
+
+			if(qe_status & CREG_STAT_RXIRQ)
+				sun4c_qe_rx(qep);
+
+			if(qe_status & CREG_STAT_TXIRQ)
+				sun4c_qe_tx(qep);
+
+			if(dev->tbusy && (SUN4C_TX_BUFFS_AVAIL(qep) >= 0)) {
+				dev->tbusy = 0;
+				mark_bh(NET_BH);
+			}
+
+	next:
+			dev->interrupt = 0;
+		}
+		qec_status >>= 4;
+		channel++;
+	}
+}
+
+static int qe_open(struct device *dev)
+{
+	struct sunqe *qep = (struct sunqe *) dev->priv;
+	int res;
+
+	res = qe_init(qep, 0);
+	if(!res) {
+		MOD_INC_USE_COUNT;
+	}
+	return res;
+}
+
+static int qe_close(struct device *dev)
+{
+	struct sunqe *qep = (struct sunqe *) dev->priv;
+
+	qe_stop(qep);
+	qe_clean_rings(qep);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/* Get a packet queued to go onto the wire. */
+static int qe_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct sunqe *qep = (struct sunqe *) dev->priv;
+	int len, entry;
+
+	if(dev->tbusy)
+		return 1;
+
+	if(skb == NULL || skb->len <= 0) {
+		printk("%s: skb is NULL\n", dev->name);
+		dev_tint(dev);
+		return 0;
+	}
+
+	if(set_bit(0, (void *) &dev->tbusy) != 0) {
+		printk("%s: Transmitter access conflict.\n", dev->name);
+		return 1;
+	}
+
+	if(!TX_BUFFS_AVAIL(qep))
+		return 1;
+
+	len = skb->len;
+	entry = qep->tx_new;
+
+	/* Avoid a race... */
+	qep->qe_block->qe_txd[entry].tx_flags = TXD_UPDATE;
+
+	qep->tx_skbs[entry] = skb;
+
+	qep->qe_block->qe_txd[entry].tx_addr = (unsigned long) skb->data;
+	qep->qe_block->qe_txd[entry].tx_flags =
+		(TXD_OWN | TXD_SOP | TXD_EOP | (len & TXD_LENGTH));
+	qep->tx_new = NEXT_TX(entry);
+
+	/* Get it going. */
+	qep->qcregs->ctrl = CREG_CTRL_TWAKEUP;
+
+	if(TX_BUFFS_AVAIL(qep))
+		dev->tbusy = 0;
+
+	return 0;
+}
+
+static int sun4c_qe_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+	struct sunqe *qep = (struct sunqe *) dev->priv;
+	struct sunqe_buffers *qbufs = qep->sun4c_buffers;
+	unsigned char *txbuf;
+	int len, entry;
+
+	if(dev->tbusy)
+		return 1;
+
+	if(skb == NULL || skb->len <= 0) {
+		printk("%s: skb is NULL\n", dev->name);
+		dev_tint(dev);
+		return 0;
+	}
+
+	if(set_bit(0, (void *) &dev->tbusy) != 0) {
+		printk("%s: Transmitter access conflict.\n", dev->name);
+		return 1;
+	}
+
+	if(!SUN4C_TX_BUFFS_AVAIL(qep))
+		return 1;
+
+	len = skb->len;
+	entry = qep->tx_new;
+
+	txbuf = &qbufs->tx_buf[entry & (SUN4C_TX_RING_SIZE - 1)][0];
+
+	/* Avoid a race... */
+	qep->qe_block->qe_txd[entry].tx_flags = TXD_UPDATE;
+
+	memcpy(txbuf, skb->data, len);
+
+	qep->qe_block->qe_txd[entry].tx_addr = (unsigned int) txbuf;
+	qep->qe_block->qe_txd[entry].tx_flags =
+		(TXD_OWN | TXD_SOP | TXD_EOP | (len & TXD_LENGTH));
+	qep->tx_new = NEXT_TX(entry);
+
+	/* Get it going. */
+	qep->qcregs->ctrl = CREG_CTRL_TWAKEUP;
+
+	dev_kfree_skb(skb, FREE_WRITE);
+
+	if(SUN4C_TX_BUFFS_AVAIL(qep))
+		dev->tbusy = 0;
+
+	return 0;
+}
+
+static struct enet_statistics *qe_get_stats(struct device *dev)
+{
+	struct sunqe *qep = (struct sunqe *) dev->priv;
+
+	return &qep->enet_stats;
+}
+
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL  /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
+
+static void qe_set_multicast(struct device *dev)
+{
+	struct sunqe *qep = (struct sunqe *) dev->priv;
+	struct dev_mc_list *dmi = dev->mc_list;
+	unsigned char new_mconfig = (MREGS_MCONFIG_TXENAB | MREGS_MCONFIG_RXENAB);
+	char *addrs;
+	int i, j, bit, byte;
+	u32 crc, poly = CRC_POLYNOMIAL_LE;
+
+	/* Lock out others. */
+	set_bit(0, (void *) &dev->tbusy);
+
+	if((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 64)) {
+		qep->mregs->iaconfig = MREGS_IACONFIG_ACHNGE | MREGS_IACONFIG_LARESET;
+		for(i = 0; i < 8; i++)
+			qep->mregs->filter = 0xff;
+		qep->mregs->iaconfig = 0;
+	} else if(dev->flags & IFF_PROMISC) {
+		new_mconfig |= MREGS_MCONFIG_PROMISC;
+	} else {
+		u16 hash_table[4];
+		unsigned char *hbytes = (unsigned char *) &hash_table[0];
+
+		for(i = 0; i < 4; i++)
+			hash_table[i] = 0;
+
+		for(i = 0; i < dev->mc_count; i++) {
+			addrs = dmi->dmi_addr;
+			dmi = dmi->next;
+
+			if(!(*addrs & 1))
+				continue;
+
+			crc = 0xffffffffU;
+			for(byte = 0; byte < 6; byte++) {
+				for(bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
+					int test;
+
+					test = ((bit ^ crc) & 0x01);
+					crc >>= 1;
+					if(test)
+						crc = crc ^ poly;
+				}
+			}
+			crc >>= 26;
+			hash_table[crc >> 4] |= 1 << (crc & 0xf);
+		}
+		/* Program the qe with the new filter value. */
+		qep->mregs->iaconfig = MREGS_IACONFIG_ACHNGE | MREGS_IACONFIG_LARESET;
+		for(i = 0; i < 8; i++)
+			qep->mregs->filter = *hbytes++;
+		qep->mregs->iaconfig = 0;
+	}
+
+	/* Any change of the logical address filter, the physical address,
+	 * or enabling/disabling promiscuous mode causes the MACE to disable
+	 * the receiver.  So we must re-enable them here or else the MACE
+	 * refuses to listen to anything on the network.  Sheesh, took
+	 * me a day or two to find this bug.
+	 */
+	qep->mregs->mconfig = new_mconfig;
+
+	/* Let us get going again. */
+	dev->tbusy = 0;
+}
+
+/* This is only called once at boot time for each card probed. */
+static inline void qec_init_once(struct sunqec *qecp, struct linux_sbus_device *qsdev)
+{
+	unsigned char bsizes = qecp->qec_bursts;
+
+	if(bsizes & DMA_BURST32)
+		qecp->gregs->ctrl = GLOB_CTRL_B32;
+	else
+		qecp->gregs->ctrl = GLOB_CTRL_B16;
+
+	/* Packetsize only used in 100baseT BigMAC configurations,
+	 * set it to zero just to be on the safe side.
+	 */
+	qecp->gregs->psize = 0;
+
+	/* Set the local memsize register, divided up to one piece per QE channel. */
+	qecp->gregs->msize = (qsdev->reg_addrs[1].reg_size >> 2);
+
+	/* Divide up the local QEC memory amongst the 4 QE receiver and
+	 * transmitter FIFOs.  Basically it is (total / 2 / num_channels).
+	 */
+	qecp->gregs->rsize = qecp->gregs->tsize =
+		(qsdev->reg_addrs[1].reg_size >> 2) >> 1;
+
+}
+
+/* Four QE's per QEC card. */
+static int qec_ether_init(struct device *dev, struct linux_sbus_device *sdev)
+{
+	static unsigned version_printed = 0;
+	struct device *qe_devs[4];
+	struct sunqe *qeps[4];
+	struct linux_sbus_device *qesdevs[4];
+	struct sunqec *qecp;
+	struct linux_prom_ranges qranges[8];
+	unsigned char bsizes, bsizes_more, num_qranges;
+	int i, j, res = ENOMEM;
+
+	dev = init_etherdev(0, sizeof(struct sunqe));
+	qe_devs[0] = dev;
+	qeps[0] = (struct sunqe *) dev->priv;
+	qeps[0]->channel = 0;
+	for(j = 0; j < 6; j++)
+		qe_devs[0]->dev_addr[j] = idprom->id_ethaddr[j];
+
+	if(version_printed++ == 0)
+		printk(version);
+
+	qe_devs[1] = qe_devs[2] = qe_devs[3] = NULL;
+	for(i = 1; i < 4; i++) {
+		qe_devs[i] = init_etherdev(0, sizeof(struct sunqe));
+		if(qe_devs[i] == NULL || qe_devs[i]->priv == NULL)
+			goto qec_free_devs;
+		qeps[i] = (struct sunqe *) qe_devs[i]->priv;
+		for(j = 0; j < 6; j++)
+			qe_devs[i]->dev_addr[j] = idprom->id_ethaddr[j];
+		qeps[i]->channel = i;
+	}
+	qecp = kmalloc(sizeof(struct sunqec), GFP_KERNEL);
+	if(qecp == NULL)
+		goto qec_free_devs;
+	qecp->qec_sbus_dev = sdev;
+
+	for(i = 0; i < 4; i++) {
+		qecp->qes[i] = qeps[i];
+		qeps[i]->dev = qe_devs[i];
+		qeps[i]->parent = qecp;
+	}
+
+	/* Link in channel 0. */
+	i = prom_getintdefault(sdev->child->prom_node, "channel#", -1);
+	if(i == -1) { res=ENODEV; goto qec_free_devs; }
+	qesdevs[i] = sdev->child;
+	qe_devs[i]->base_addr = (long) qesdevs[i];
+
+	/* Link in channel 1. */
+	i = prom_getintdefault(sdev->child->next->prom_node, "channel#", -1);
+	if(i == -1) { res=ENODEV; goto qec_free_devs; }
+	qesdevs[i] = sdev->child->next;
+	qe_devs[i]->base_addr = (long) qesdevs[i];
+
+	/* Link in channel 2. */
+	i = prom_getintdefault(sdev->child->next->next->prom_node, "channel#", -1);
+	if(i == -1) { res=ENODEV; goto qec_free_devs; }
+	qesdevs[i] = sdev->child->next->next;
+	qe_devs[i]->base_addr = (long) qesdevs[i];
+
+	/* Link in channel 3. */
+	i = prom_getintdefault(sdev->child->next->next->next->prom_node, "channel#", -1);
+	if(i == -1) { res=ENODEV; goto qec_free_devs; }
+	qesdevs[i] = sdev->child->next->next->next;
+	qe_devs[i]->base_addr = (long) qesdevs[i];
+
+	for(i = 0; i < 4; i++)
+		qeps[i]->qe_sbusdev = qesdevs[i];
+
+	/* This is a bit of fun, get QEC ranges. */
+	i = prom_getproperty(sdev->prom_node, "ranges",
+			     (char *) &qranges[0], sizeof(qranges));
+	num_qranges = (i / sizeof(struct linux_prom_ranges));
+
+	/* Now, apply all the ranges, QEC ranges then the SBUS ones for each QE. */
+	for(i = 0; i < 4; i++) {
+		for(j = 0; j < 2; j++) {
+			int k;
+
+			for(k = 0; k < num_qranges; k++)
+				if(qesdevs[i]->reg_addrs[j].which_io ==
+				   qranges[k].ot_child_space)
+					break;
+			if(k >= num_qranges)
+				printk("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;
+		}
+
+		prom_apply_sbus_ranges(qesdevs[i]->my_bus, &qesdevs[i]->reg_addrs[0], 2);
+	}
+
+	/* Now map in the registers, QEC globals first. */
+	prom_apply_sbus_ranges(sdev->my_bus, &sdev->reg_addrs[0], sdev->num_registers);
+	qecp->gregs = sparc_alloc_io(sdev->reg_addrs[0].phys_addr, 0,
+				     sizeof(struct qe_globreg),
+				     "QEC Global Registers",
+				     sdev->reg_addrs[0].which_io, 0);
+	if(!qecp->gregs) {
+		printk("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");
+		res = ENODEV;
+		goto qec_free_devs;
+	}
+
+	/* Reset the QEC. */
+	if(qec_global_reset(qecp->gregs)) {
+		res = ENODEV;
+		goto qec_free_devs;
+	}
+
+	/* Find and set the burst sizes for the QEC, since it does
+	 * the actual dma for all 4 channels.
+	 */
+	bsizes = prom_getintdefault(sdev->prom_node, "burst-sizes", 0xff);
+	bsizes &= 0xff;
+	bsizes_more = prom_getintdefault(sdev->my_bus->prom_node, "burst-sizes", 0xff);
+
+	if(bsizes_more != 0xff)
+		bsizes &= bsizes_more;
+	if(bsizes == 0xff || (bsizes & DMA_BURST16) == 0 ||
+	   (bsizes & DMA_BURST32)==0)
+		bsizes = (DMA_BURST32 - 1);
+
+	qecp->qec_bursts = bsizes;
+
+	/* Perform one time QEC initialization, we never touch the QEC
+	 * globals again after this.
+	 */
+	qec_init_once(qecp, sdev);
+
+	for(i = 0; i < 4; i++) {
+		/* Map in QEC per-channel control registers. */
+		qeps[i]->qcregs = sparc_alloc_io(qesdevs[i]->reg_addrs[0].phys_addr, 0,
+						 sizeof(struct qe_creg),
+						 "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);
+			res = ENODEV;
+			goto qec_free_devs;
+		}
+
+		/* Map in per-channel AMD MACE registers. */
+		qeps[i]->mregs = sparc_alloc_io(qesdevs[i]->reg_addrs[1].phys_addr, 0,
+						sizeof(struct qe_mregs),
+						"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);
+			res = ENODEV;
+			goto qec_free_devs;
+		}
+
+		qeps[i]->qe_block = (struct qe_init_block *)
+			sparc_dvma_malloc(PAGE_SIZE, "QE Init Block");
+
+		if(sparc_cpu_model == sun4c)
+			qeps[i]->sun4c_buffers = (struct sunqe_buffers *)
+				sparc_dvma_malloc(sizeof(struct sunqe_buffers),
+						  "QE RX/TX Buffers");
+		else
+			qeps[i]->sun4c_buffers = 0;
+
+		/* Stop this QE. */
+		qe_stop(qeps[i]);
+	}
+
+	for(i = 0; i < 4; i++) {
+		qe_devs[i]->open = qe_open;
+		qe_devs[i]->stop = qe_close;
+		if(sparc_cpu_model == sun4c)
+			qe_devs[i]->hard_start_xmit = sun4c_qe_start_xmit;
+		else
+			qe_devs[i]->hard_start_xmit = qe_start_xmit;
+		qe_devs[i]->get_stats = qe_get_stats;
+		qe_devs[i]->set_multicast_list = qe_set_multicast;
+		qe_devs[i]->irq = (unsigned char) sdev->irqs[0].pri;
+		qe_devs[i]->dma = 0;
+		ether_setup(qe_devs[i]);
+	}
+
+	/* QEC receives interrupts from each QE, then it send the actual
+	 * IRQ to the cpu itself.  Since QEC is the single point of
+	 * interrupt for all QE channels we register the IRQ handler
+	 * for it now.
+	 */
+	if(sparc_cpu_model == sun4c) {
+		if(request_irq(sdev->irqs[0].pri, &sun4c_qec_interrupt,
+			       SA_SHIRQ, "QuadEther", (void *) qecp)) {
+			printk("QuadEther: Can't register QEC master irq handler.\n");
+			res = EAGAIN;
+			goto qec_free_devs;
+		}
+	} else {
+		if(request_irq(sdev->irqs[0].pri, &qec_interrupt,
+			       SA_SHIRQ, "QuadEther", (void *) qecp)) {
+			printk("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);
+		for(j = 0; j < 6; j++)
+			printk ("%2.2x%c",
+				qe_devs[i]->dev_addr[j],
+				j == 5 ? ' ': ':');
+		printk("\n");
+	}
+
+#ifdef MODULE
+	/* We are home free at this point, link the qe's into
+	 * the master list for later module unloading.
+	 */
+	qecp->next_module = root_qec_dev;
+	root_qec_dev = qecp;
+#endif
+
+	return 0;
+
+qec_free_devs:
+	for(i = 0; i < 4; i++) {
+		if(qe_devs[i]) {
+			if(qe_devs[i]->priv)
+				kfree(qe_devs[i]->priv);
+			kfree(qe_devs[i]);
+		}
+	}
+	return res;
+}
+
+int qec_probe(struct device *dev)
+{
+	struct linux_sbus *bus;
+	struct linux_sbus_device *sdev = 0;
+	static int called = 0;
+	int cards = 0, v;
+
+	if(called)
+		return ENODEV;
+	called++;
+
+	for_each_sbus(bus) {
+		for_each_sbusdev(sdev, bus) {
+			if(cards) dev = NULL;
+
+			/* QEC can be parent of either QuadEthernet or BigMAC
+			 * children.
+			 */
+			if(!strcmp(sdev->prom_name, "qec") && sdev->child &&
+			   !strcmp(sdev->child->prom_name, "qe") &&
+			   sdev->child->next &&
+			   !strcmp(sdev->child->next->prom_name, "qe") &&
+			   sdev->child->next->next &&
+			   !strcmp(sdev->child->next->next->prom_name, "qe") &&
+			   sdev->child->next->next->next &&
+			   !strcmp(sdev->child->next->next->next->prom_name, "qe")) {
+				cards++;
+				if((v = qec_ether_init(dev, sdev)))
+					return v;
+			}
+		}
+	}
+	if(!cards)
+		return ENODEV;
+	return 0;
+}
+
+#ifdef MODULE
+
+int
+init_module(void)
+{
+	root_qec_dev = NULL;
+	return qec_probe(NULL);
+}
+
+void
+cleanup_module(void)
+{
+	struct sunqec *next_qec;
+	int i;
+
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (root_qec_dev) {
+		next_qec = root_qec_dev->next_module;
+
+		/* Release all four QE channels, then the QEC itself. */
+		for(i = 0; i < 4; i++) {
+			unregister_netdev(root_qec_dev->qes[i]->dev);
+			kfree(root_qec_dev->qes[i]);
+		}
+		free_irq(root_qec_dev->qec_sbus_dev->irqs[0].pri, (void *)root_qec_dev);
+		kfree(root_qec_dev);
+		root_qec_dev = next_qec;
+	}
+}
+
+#endif /* MODULE */
diff -u --recursive --new-file v2.1.15/linux/drivers/net/sunqe.h linux/drivers/net/sunqe.h
--- v2.1.15/linux/drivers/net/sunqe.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/net/sunqe.h	Fri Dec 13 11:37:32 1996
@@ -0,0 +1,387 @@
+/* sunqe.h: Definitions for the Sun QuadEthernet driver.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SUNQE_H
+#define _SUNQE_H
+
+/* QEC global registers. */
+struct qe_globreg {
+	volatile unsigned int ctrl;      /* Control                  */
+	volatile unsigned int stat;      /* Status                   */
+	volatile unsigned int psize;     /* Packet Size              */
+	volatile unsigned int msize;     /* Local-mem size (64K)     */
+	volatile unsigned int rsize;     /* Receive partition size   */
+	volatile unsigned int tsize;     /* Transmit partition size  */
+};
+
+#define GLOB_CTRL_MMODE       0x40000000 /* MACE qec mode            */
+#define GLOB_CTRL_BMODE       0x10000000 /* BigMAC qec mode          */
+#define GLOB_CTRL_EPAR        0x00000020 /* Enable parity            */
+#define GLOB_CTRL_ACNTRL      0x00000018 /* SBUS arbitration control */
+#define GLOB_CTRL_B64         0x00000004 /* 64 byte dvma bursts      */
+#define GLOB_CTRL_B32         0x00000002 /* 32 byte dvma bursts      */
+#define GLOB_CTRL_B16         0x00000000 /* 16 byte dvma bursts      */
+#define GLOB_CTRL_RESET       0x00000001 /* Reset the QEC            */
+
+#define GLOB_STAT_TX          0x00000008 /* BigMAC Transmit IRQ      */
+#define GLOB_STAT_RX          0x00000004 /* BigMAC Receive IRQ       */
+#define GLOB_STAT_BM          0x00000002 /* BigMAC Global IRQ        */
+#define GLOB_STAT_ER          0x00000001 /* BigMAC Error IRQ         */
+
+#define GLOB_PSIZE_2048       0x00       /* 2k packet size           */
+#define GLOB_PSIZE_4096       0x01       /* 4k packet size           */
+#define GLOB_PSIZE_6144       0x10       /* 6k packet size           */
+#define GLOB_PSIZE_8192       0x11       /* 8k packet size           */
+
+/* In MACE mode, there are four qe channels.  Each channel has it's own
+ * status bits in the QEC status register.  This macro picks out the
+ * ones you want.
+ */
+#define GLOB_STAT_PER_QE(status, channel) (((status) >> ((channel) * 4)) & 0xf)
+
+/* The following registers are for per-qe channel information/status. */
+struct qe_creg {
+	volatile unsigned int ctrl;       /* Control                   */
+	volatile unsigned int stat;       /* Status                    */
+	volatile unsigned int rxds;       /* RX descriptor ring ptr    */
+	volatile unsigned int txds;       /* TX descriptor ring ptr    */
+	volatile unsigned int rimask;     /* RX Interrupt Mask         */
+	volatile unsigned int timask;     /* TX Interrupt Mask         */
+	volatile unsigned int qmask;      /* QEC Error Interrupt Mask  */
+	volatile unsigned int mmask;      /* MACE Error Interrupt Mask */
+	volatile unsigned int rxwbufptr;  /* Local memory rx write ptr */
+	volatile unsigned int rxrbufptr;  /* Local memory rx read ptr  */
+	volatile unsigned int txwbufptr;  /* Local memory tx write ptr */
+	volatile unsigned int txrbufptr;  /* Local memory tx read ptr  */
+	volatile unsigned int ccnt;       /* Collision Counter         */
+	volatile unsigned int pipg;       /* Inter-Frame Gap           */
+};
+
+#define CREG_CTRL_RXOFF       0x00000004  /* Disable this qe's receiver*/
+#define CREG_CTRL_RESET       0x00000002  /* Reset this qe channel     */
+#define CREG_CTRL_TWAKEUP     0x00000001  /* Transmitter Wakeup, 'go'. */
+
+#define CREG_STAT_EDEFER      0x10000000  /* Excessive Defers          */
+#define CREG_STAT_CLOSS       0x08000000  /* Carrier Loss              */
+#define CREG_STAT_ERETRIES    0x04000000  /* More than 16 retries      */
+#define CREG_STAT_LCOLL       0x02000000  /* Late TX Collision         */
+#define CREG_STAT_FUFLOW      0x01000000  /* FIFO Underflow            */
+#define CREG_STAT_JERROR      0x00800000  /* Jabber Error              */
+#define CREG_STAT_BERROR      0x00400000  /* Babble Error              */
+#define CREG_STAT_TXIRQ       0x00200000  /* Transmit Interrupt        */
+#define CREG_STAT_CCOFLOW     0x00100000  /* TX Coll-counter Overflow  */
+#define CREG_STAT_TXDERROR    0x00080000  /* TX Descriptor is bogus    */
+#define CREG_STAT_TXLERR      0x00040000  /* Late Transmit Error       */
+#define CREG_STAT_TXPERR      0x00020000  /* Transmit Parity Error     */
+#define CREG_STAT_TXSERR      0x00010000  /* Transmit SBUS error ack   */
+#define CREG_STAT_RCCOFLOW    0x00001000  /* RX Coll-counter Overflow  */
+#define CREG_STAT_RUOFLOW     0x00000800  /* Runt Counter Overflow     */
+#define CREG_STAT_MCOFLOW     0x00000400  /* Missed Counter Overflow   */
+#define CREG_STAT_RXFOFLOW    0x00000200  /* RX FIFO Overflow          */
+#define CREG_STAT_RLCOLL      0x00000100  /* RX Late Collision         */
+#define CREG_STAT_FCOFLOW     0x00000080  /* Frame Counter Overflow    */
+#define CREG_STAT_CECOFLOW    0x00000040  /* CRC Error-counter Overflow*/
+#define CREG_STAT_RXIRQ       0x00000020  /* Receive Interrupt         */
+#define CREG_STAT_RXDROP      0x00000010  /* Dropped a RX'd packet     */
+#define CREG_STAT_RXSMALL     0x00000008  /* Receive buffer too small  */
+#define CREG_STAT_RXLERR      0x00000004  /* Receive Late Error        */
+#define CREG_STAT_RXPERR      0x00000002  /* Receive Parity Error      */
+#define CREG_STAT_RXSERR      0x00000001  /* Receive SBUS Error ACK    */
+
+#define CREG_STAT_ERRORS      (CREG_STAT_EDEFER|CREG_STAT_CLOSS|CREG_STAT_ERETRIES|     \
+			       CREG_STAT_LCOLL|CREG_STAT_FUFLOW|CREG_STAT_JERROR|       \
+			       CREG_STAT_BERROR|CREG_STAT_CCOFLOW|CREG_STAT_TXDERROR|   \
+			       CREG_STAT_TXLERR|CREG_STAT_TXPERR|CREG_STAT_TXSERR|      \
+			       CREG_STAT_RCCOFLOW|CREG_STAT_RUOFLOW|CREG_STAT_MCOFLOW| \
+			       CREG_STAT_RXFOFLOW|CREG_STAT_RLCOLL|CREG_STAT_FCOFLOW|   \
+			       CREG_STAT_CECOFLOW|CREG_STAT_RXDROP|CREG_STAT_RXSMALL|   \
+			       CREG_STAT_RXLERR|CREG_STAT_RXPERR|CREG_STAT_RXSERR)
+
+#define CREG_QMASK_COFLOW     0x00100000  /* CollCntr overflow         */
+#define CREG_QMASK_TXDERROR   0x00080000  /* TXD error                 */
+#define CREG_QMASK_TXLERR     0x00040000  /* TX late error             */
+#define CREG_QMASK_TXPERR     0x00020000  /* TX parity error           */
+#define CREG_QMASK_TXSERR     0x00010000  /* TX sbus error ack         */
+#define CREG_QMASK_RXDROP     0x00000010  /* RX drop                   */
+#define CREG_QMASK_RXBERROR   0x00000008  /* RX buffer error           */
+#define CREG_QMASK_RXLEERR    0x00000004  /* RX late error             */
+#define CREG_QMASK_RXPERR     0x00000002  /* RX parity error           */
+#define CREG_QMASK_RXSERR     0x00000001  /* RX sbus error ack         */
+
+#define CREG_MMASK_EDEFER     0x10000000  /* Excess defer              */
+#define CREG_MMASK_CLOSS      0x08000000  /* Carrier loss              */
+#define CREG_MMASK_ERETRY     0x04000000  /* Excess retry              */
+#define CREG_MMASK_LCOLL      0x02000000  /* Late collision error      */
+#define CREG_MMASK_UFLOW      0x01000000  /* Underflow                 */
+#define CREG_MMASK_JABBER     0x00800000  /* Jabber error              */
+#define CREG_MMASK_BABBLE     0x00400000  /* Babble error              */
+#define CREG_MMASK_OFLOW      0x00000800  /* Overflow                  */
+#define CREG_MMASK_RXCOLL     0x00000400  /* RX Coll-Cntr overflow     */
+#define CREG_MMASK_RPKT       0x00000200  /* Runt pkt overflow         */
+#define CREG_MMASK_MPKT       0x00000100  /* Missed pkt overflow       */
+
+#define CREG_PIPG_TENAB       0x00000020  /* Enable Throttle           */
+#define CREG_PIPG_MMODE       0x00000010  /* Manual Mode               */
+#define CREG_PIPG_WMASK       0x0000000f  /* SBUS Wait Mask            */
+
+/* Per-channel AMD 79C940 MACE registers. */
+struct qe_mregs {
+	volatile unsigned char rxfifo;   /* Receive FIFO                   */
+	volatile unsigned char txfifo;   /* Transmit FIFO                  */
+	volatile unsigned char txfcntl;  /* Transmit Frame Control         */
+	volatile unsigned char txfstat;  /* Transmit Frame Status          */
+	volatile unsigned char txrcnt;   /* Transmit Retry Count           */
+	volatile unsigned char rxfcntl;  /* Receive Frame Control          */
+	volatile unsigned char rxfstat;  /* Receive Frame Status           */
+	volatile unsigned char ffcnt;    /* FIFO Frame Count               */
+	volatile unsigned char ireg;     /* Interrupt Register             */
+	volatile unsigned char imask;    /* Interrupt Mask                 */
+	volatile unsigned char poll;     /* POLL Register                  */
+	volatile unsigned char bconfig;  /* BIU Config                     */
+	volatile unsigned char fconfig;  /* FIFO Config                    */
+	volatile unsigned char mconfig;  /* MAC Config                     */
+	volatile unsigned char plsconfig;/* PLS Config                     */
+	volatile unsigned char phyconfig;/* PHY Config                     */
+	volatile unsigned char chipid1;  /* Chip-ID, low bits              */
+	volatile unsigned char chipid2;  /* Chip-ID, high bits             */
+	volatile unsigned char iaconfig; /* Internal Address Config        */
+	volatile unsigned char _unused0; /* Reserved...                    */
+	volatile unsigned char filter;   /* Logical Address Filter         */
+	volatile unsigned char ethaddr;  /* Our Ethernet Address           */
+	volatile unsigned char _unused1; /* Reserved...                    */
+	volatile unsigned char _unused2; /* Reserved...                    */
+	volatile unsigned char mpcnt;    /* Missed Packet Count            */
+	volatile unsigned char _unused3; /* Reserved...                    */
+	volatile unsigned char rpcnt;    /* Runt Packet Count              */
+	volatile unsigned char rccnt;    /* RX Collision Count             */
+	volatile unsigned char _unused4; /* Reserved...                    */
+	volatile unsigned char utest;    /* User Test                      */
+	volatile unsigned char rtest1;   /* Reserved Test 1                */
+	volatile unsigned char rtest2;   /* Reserved Test 2                */
+};
+
+#define MREGS_TXFCNTL_DRETRY        0x80 /* Retry disable                  */
+#define MREGS_TXFCNTL_DFCS          0x08 /* Disable TX FCS                 */
+#define MREGS_TXFCNTL_AUTOPAD       0x01 /* TX auto pad                    */
+
+#define MREGS_TXFSTAT_VALID         0x80 /* TX valid                       */
+#define MREGS_TXFSTAT_UNDERFLOW     0x40 /* TX underflow                   */
+#define MREGS_TXFSTAT_LCOLL         0x20 /* TX late collision              */
+#define MREGS_TXFSTAT_MRETRY        0x10 /* TX > 1 retries                 */
+#define MREGS_TXFSTAT_ORETRY        0x08 /* TX 1 retry                     */
+#define MREGS_TXFSTAT_PDEFER        0x04 /* TX pkt deferred                */
+#define MREGS_TXFSTAT_CLOSS         0x02 /* TX carrier lost                */
+#define MREGS_TXFSTAT_RERROR        0x01 /* TX retry error                 */
+
+#define MREGS_TXRCNT_EDEFER         0x80 /* TX Excess defers               */
+#define MREGS_TXRCNT_CMASK          0x0f /* TX retry count                 */
+
+#define MREGS_RXFCNTL_LOWLAT        0x08 /* RX low latency                 */
+#define MREGS_RXFCNTL_AREJECT       0x04 /* RX addr match rej              */
+#define MREGS_RXFCNTL_AUTOSTRIP     0x01 /* RX auto strip                  */
+
+#define MREGS_RXFSTAT_OVERFLOW      0x80 /* RX overflow                    */
+#define MREGS_RXFSTAT_LCOLL         0x40 /* RX late collision              */
+#define MREGS_RXFSTAT_FERROR        0x20 /* RX framing error               */
+#define MREGS_RXFSTAT_FCSERROR      0x10 /* RX FCS error                   */
+#define MREGS_RXFSTAT_RBCNT         0x0f /* RX msg byte count              */
+
+#define MREGS_FFCNT_RX              0xf0 /* RX FIFO frame cnt              */
+#define MREGS_FFCNT_TX              0x0f /* TX FIFO frame cnt              */
+
+#define MREGS_IREG_JABBER           0x80 /* IRQ Jabber error               */
+#define MREGS_IREG_BABBLE           0x40 /* IRQ Babble error               */
+#define MREGS_IREG_COLL             0x20 /* IRQ Collision error            */
+#define MREGS_IREG_RCCO             0x10 /* IRQ Collision cnt overflow     */
+#define MREGS_IREG_RPKTCO           0x08 /* IRQ Runt packet count overflow */
+#define MREGS_IREG_MPKTCO           0x04 /* IRQ missed packet cnt overflow */
+#define MREGS_IREG_RXIRQ            0x02 /* IRQ RX'd a packet              */
+#define MREGS_IREG_TXIRQ            0x01 /* IRQ TX'd a packet              */
+
+#define MREGS_IMASK_BABBLE          0x40 /* IMASK Babble errors            */
+#define MREGS_IMASK_COLL            0x20 /* IMASK Collision errors         */
+#define MREGS_IMASK_MPKTCO          0x04 /* IMASK Missed pkt cnt overflow  */
+#define MREGS_IMASK_RXIRQ           0x02 /* IMASK RX interrupts            */
+#define MREGS_IMASK_TXIRQ           0x01 /* IMASK TX interrupts            */
+
+#define MREGS_POLL_TXVALID          0x80 /* TX is valid                    */
+#define MREGS_POLL_TDTR             0x40 /* TX data transfer request       */
+#define MREGS_POLL_RDTR             0x20 /* RX data transfer request       */
+
+#define MREGS_BCONFIG_BSWAP         0x40 /* Byte Swap                      */
+#define MREGS_BCONFIG_4TS           0x00 /* 4byte transmit start point     */
+#define MREGS_BCONFIG_16TS          0x10 /* 16byte transmit start point    */
+#define MREGS_BCONFIG_64TS          0x20 /* 64byte transmit start point    */
+#define MREGS_BCONFIG_112TS         0x30 /* 112byte transmit start point   */
+#define MREGS_BCONFIG_RESET         0x01 /* SW-Reset the MACE              */
+
+#define MREGS_FCONFIG_TXF8          0x00 /* TX fifo 8 write cycles         */
+#define MREGS_FCONFIG_TXF32         0x80 /* TX fifo 32 write cycles        */
+#define MREGS_FCONFIG_TXF16         0x40 /* TX fifo 16 write cycles        */
+#define MREGS_FCONFIG_RXF64         0x20 /* RX fifo 64 write cycles        */
+#define MREGS_FCONFIG_RXF32         0x10 /* RX fifo 32 write cycles        */
+#define MREGS_FCONFIG_RXF16         0x00 /* RX fifo 16 write cycles        */
+#define MREGS_FCONFIG_TFWU          0x08 /* TX fifo watermark update       */
+#define MREGS_FCONFIG_RFWU          0x04 /* RX fifo watermark update       */
+#define MREGS_FCONFIG_TBENAB        0x02 /* TX burst enable                */
+#define MREGS_FCONFIG_RBENAB        0x01 /* RX burst enable                */
+
+#define MREGS_MCONFIG_PROMISC       0x80 /* Promiscuous mode enable        */
+#define MREGS_MCONFIG_TPDDISAB      0x40 /* TX 2part deferral enable       */
+#define MREGS_MCONFIG_MBAENAB       0x20 /* Modified backoff enable        */
+#define MREGS_MCONFIG_RPADISAB      0x08 /* RX physical addr disable       */
+#define MREGS_MCONFIG_RBDISAB       0x04 /* RX broadcast disable           */
+#define MREGS_MCONFIG_TXENAB        0x02 /* Enable transmitter             */
+#define MREGS_MCONFIG_RXENAB        0x01 /* Enable receiver                */
+
+#define MREGS_PLSCONFIG_TXMS        0x08 /* TX mode select                 */
+#define MREGS_PLSCONFIG_GPSI        0x06 /* Use GPSI connector             */
+#define MREGS_PLSCONFIG_DAI         0x04 /* Use DAI connector              */
+#define MREGS_PLSCONFIG_TP          0x02 /* Use TwistedPair connector      */
+#define MREGS_PLSCONFIG_AUI         0x00 /* Use AUI connector              */
+#define MREGS_PLSCONFIG_IOENAB      0x01 /* PLS I/O enable                 */
+
+#define MREGS_PHYCONFIG_LSTAT       0x80 /* Link status                    */
+#define MREGS_PHYCONFIG_LTESTDIS    0x40 /* Disable link test logic        */
+#define MREGS_PHYCONFIG_RXPOLARITY  0x20 /* RX polarity                    */
+#define MREGS_PHYCONFIG_APCDISAB    0x10 /* AutoPolarityCorrect disab      */
+#define MREGS_PHYCONFIG_LTENAB      0x08 /* Select low threshold           */
+#define MREGS_PHYCONFIG_AUTO        0x04 /* Connector port auto-sel        */
+#define MREGS_PHYCONFIG_RWU         0x02 /* Remote WakeUp                  */
+#define MREGS_PHYCONFIG_AW          0x01 /* Auto Wakeup                    */
+
+#define MREGS_IACONFIG_ACHNGE       0x80 /* Do address change              */
+#define MREGS_IACONFIG_PARESET      0x04 /* Physical address reset         */
+#define MREGS_IACONFIG_LARESET      0x02 /* Logical address reset          */
+
+#define MREGS_UTEST_RTRENAB         0x80 /* Enable resv test register      */
+#define MREGS_UTEST_RTRDISAB        0x40 /* Disab resv test register       */
+#define MREGS_UTEST_RPACCEPT        0x20 /* Accept runt packets            */
+#define MREGS_UTEST_FCOLL           0x10 /* Force collision status         */
+#define MREGS_UTEST_FCSENAB         0x08 /* Enable FCS on RX               */
+#define MREGS_UTEST_INTLOOPM        0x06 /* Intern lpback w/MENDEC         */
+#define MREGS_UTEST_INTLOOP         0x04 /* Intern lpback                  */
+#define MREGS_UTEST_EXTLOOP         0x02 /* Extern lpback                  */
+#define MREGS_UTEST_NOLOOP          0x00 /* No loopback                    */
+
+struct qe_rxd {
+	unsigned int rx_flags;
+	unsigned int rx_addr;
+};
+
+#define RXD_OWN      0x80000000 /* Ownership.      */
+#define RXD_UPDATE   0x10000000 /* Being Updated?  */
+#define RXD_LENGTH   0x000007ff /* Packet Length.  */
+
+struct qe_txd {
+	unsigned int tx_flags;
+	unsigned int tx_addr;
+};
+
+#define TXD_OWN      0x80000000 /* Ownership.      */
+#define TXD_SOP      0x40000000 /* Start Of Packet */
+#define TXD_EOP      0x20000000 /* End Of Packet   */
+#define TXD_UPDATE   0x10000000 /* Being Updated?  */
+#define TXD_LENGTH   0x000007ff /* Packet Length.  */
+
+#define TX_RING_MAXSIZE   256
+#define RX_RING_MAXSIZE   256
+
+#define TX_RING_SIZE      256
+#define RX_RING_SIZE      256
+
+#define NEXT_RX(num)       (((num) + 1) & (RX_RING_SIZE - 1))
+#define NEXT_TX(num)       (((num) + 1) & (TX_RING_SIZE - 1))
+#define PREV_RX(num)       (((num) - 1) & (RX_RING_SIZE - 1))
+#define PREV_TX(num)       (((num) - 1) & (TX_RING_SIZE - 1))
+
+#define TX_BUFFS_AVAIL(qp)                                    \
+        (((qp)->tx_old <= (qp)->tx_new) ?                     \
+	  (qp)->tx_old + (TX_RING_SIZE - 1) - (qp)->tx_new :  \
+			    (qp)->tx_old - (qp)->tx_new - 1)
+
+
+#define SUN4C_TX_BUFFS_AVAIL(qp)                                    \
+        (((qp)->tx_old <= (qp)->tx_new) ?                           \
+	  (qp)->tx_old + (SUN4C_TX_RING_SIZE - 1) - (qp)->tx_new :  \
+	  (qp)->tx_old - (qp)->tx_new - (TX_RING_SIZE - SUN4C_TX_RING_SIZE))
+
+
+#define RX_COPY_THRESHOLD  128
+#define RX_BUF_ALLOC_SIZE  (ETH_FRAME_LEN + (64 * 3))
+
+struct qe_init_block {
+	struct qe_rxd qe_rxd[RX_RING_MAXSIZE];
+	struct qe_txd qe_txd[TX_RING_MAXSIZE];
+};
+
+struct sunqe;
+
+struct sunqec {
+	struct qe_globreg         *gregs;             /* QEC Global Registers         */
+
+	struct sunqe              *qes[4];
+	unsigned int               qec_bursts;
+	struct linux_sbus_device  *qec_sbus_dev;
+	struct sunqec             *next_module;
+};
+
+#define SUN4C_PKT_BUF_SZ	1544
+#define SUN4C_RX_BUFF_SIZE	SUN4C_PKT_BUF_SZ
+#define SUN4C_TX_BUFF_SIZE	SUN4C_PKT_BUF_SZ
+
+#define SUN4C_RX_RING_SIZE	16
+#define SUN4C_TX_RING_SIZE	16
+
+struct sunqe_buffers {
+	char	tx_buf[SUN4C_TX_RING_SIZE][SUN4C_TX_BUFF_SIZE];
+	char	pad[2];		/* Align rx_buf for copy_and_sum(). */
+	char	rx_buf[SUN4C_RX_RING_SIZE][SUN4C_RX_BUFF_SIZE];
+};
+
+#define SUN4C_NEXT_RX(num)	(((num) + 1) & (SUN4C_RX_RING_SIZE - 1))
+#define SUN4C_NEXT_TX(num)	(((num) + 1) & (SUN4C_TX_RING_SIZE - 1))
+#define SUN4C_PREV_RX(num)	(((num) - 1) & (SUN4C_RX_RING_SIZE - 1))
+#define SUN4C_PREV_TX(num)	(((num) - 1) & (SUN4C_TX_RING_SIZE - 1))
+
+struct sunqe {
+	struct qe_creg            *qcregs;           /* QEC per-channel Registers      */
+	struct qe_mregs           *mregs;            /* Per-channel MACE Registers     */
+	struct qe_init_block      *qe_block;         /* RX and TX descriptors          */
+
+	struct sk_buff            *rx_skbs[RX_RING_SIZE];
+	struct sk_buff            *tx_skbs[TX_RING_SIZE];
+
+	int                        rx_new, tx_new, rx_old, tx_old;
+
+	struct sunqe_buffers      *sun4c_buffers;
+
+	struct sunqec             *parent;
+
+	struct enet_statistics     enet_stats;   /* Statistical counters               */
+	struct linux_sbus_device  *qe_sbusdev;   /* QE's SBUS device struct            */
+	struct device             *dev;          /* QE's netdevice struct              */
+	int                        channel;      /* Who am I?                          */
+};
+
+/* We use this to acquire receive skb's that we can DMA directly into. */
+#define ALIGNED_RX_SKB_ADDR(addr) \
+        ((((unsigned long)(addr) + (64 - 1)) & ~(64 - 1)) - (unsigned long)(addr))
+
+static inline struct sk_buff *qe_alloc_skb(unsigned int length, int gfp_flags)
+{
+	struct sk_buff *skb;
+
+	skb = alloc_skb(length + 64, gfp_flags);
+	if(skb) {
+		int offset = ALIGNED_RX_SKB_ADDR(skb->data);
+
+		if(offset)
+			skb_reserve(skb, offset);
+	}
+	return skb;
+}
+
+#endif /* !(_SUNQE_H) */
diff -u --recursive --new-file v2.1.15/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.1.15/linux/drivers/pci/pci.c	Thu Dec 12 19:37:07 1996
+++ linux/drivers/pci/pci.c	Wed Dec 18 11:48:52 1996
@@ -149,6 +149,7 @@
 	DEVICE( 3COM,		3COM_3C595TX,	"3C595 100bTX"),
 	DEVICE( 3COM,		3COM_3C595T4,	"3C595 100bT4"),
 	DEVICE( 3COM,		3COM_3C595MII,	"3C595 100b-MII"),
+	DEVICE( 3COM,		3COM_3C900TPO,	"3C900 10bTPO"),
 	DEVICE( AL,		AL_M1445,	"M1445"),
 	DEVICE( AL,		AL_M1449,	"M1449"),
 	DEVICE( AL,		AL_M1451,	"M1451"),
@@ -208,6 +209,11 @@
 	DEVICE( CYCLADES,	CYCLOM_Y_Hi,	"Cyclom-Y above 1Mbyte"),
 	DEVICE( CYCLADES,	CYCLOM_Z_Lo,	"Cyclom-Z below 1Mbyte"),
 	DEVICE( CYCLADES,	CYCLOM_Z_Hi,	"Cyclom-Z above 1Mbyte"),
+	DEVICE( OPTIBASE,	OPTIBASE_FORGE,	"MPEG Forge"),
+	DEVICE( OPTIBASE,	OPTIBASE_FUSION,"MPEG Fusion"),
+	DEVICE( OPTIBASE,	OPTIBASE_VPLEX,	"VideoPlex"),
+	DEVICE( OPTIBASE,	OPTIBASE_VPLEXCC,"VideoPlex CC"),
+	DEVICE( OPTIBASE,	OPTIBASE_VQUEST,"VideoQuest"),
 	DEVICE( SYMPHONY,	SYMPHONY_101,	"82C101"),
 	DEVICE( TEKRAM,		TEKRAM_DC290,	"DC-290"),
 	DEVICE( 3DLABS,		3DLABS_300SX,	"GLINT 300SX"),
@@ -523,6 +529,7 @@
 	      case PCI_VENDOR_ID_COMPEX:	return "Compex";
 	      case PCI_VENDOR_ID_RP:		return "Comtrol";
 	      case PCI_VENDOR_ID_CYCLADES:	return "Cyclades";
+	      case PCI_VENDOR_ID_OPTIBASE:	return "Optibase";
 	      case PCI_VENDOR_ID_SYMPHONY:	return "Symphony";
 	      case PCI_VENDOR_ID_TEKRAM:	return "Tekram";
 	      case PCI_VENDOR_ID_3DLABS:	return "3Dlabs";
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/Makefile linux/drivers/sbus/Makefile
--- v2.1.15/linux/drivers/sbus/Makefile	Thu Apr 25 13:27:42 1996
+++ linux/drivers/sbus/Makefile	Fri Dec 13 11:37:32 1996
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 SUB_DIRS     :=
-MOD_SUB_DIRS := $(SUB_DIRS)
+MOD_SUB_DIRS := $(SUB_DIRS) char
 ALL_SUB_DIRS := $(SUB_DIRS) char
 
 L_OBJS   := sbus.o dvma.o
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/Config.in linux/drivers/sbus/char/Config.in
--- v2.1.15/linux/drivers/sbus/char/Config.in	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/Config.in	Fri Dec 13 11:37:32 1996
@@ -0,0 +1,50 @@
+comment 'SBUS Frame Buffer support'
+bool 'Sun FB drivers appear in PROCFS' SUN_FBS_IN_PROCFS
+bool 'Load All Supported Drivers' CONFIG_SUN_FB_DISPLAY
+
+if [ "$CONFIG_SUN_FB_DISPLAY" = "n" ]; then
+	bool 'cgsix support' SUN_FB_CGSIX
+	bool 'tcx support' SUN_FB_TCX
+	bool 'cgthree support' SUN_FB_CGTHREE
+	bool 'cgfourteen support' SUN_FB_CGFOURTEEN
+	bool 'bwtwo support' SUN_FB_BWTWO
+	bool 'leo/zx support' SUN_FB_LEO
+	bool 'weitek P9X00 support' TADPOLE_FB_WEITEK
+	bool 'Fast 8 bit 1152x900  mode' SUN_FB_FAST_ONE
+	bool 'Fast mono  1152x900  mode' SUN_FB_FAST_TWO
+	bool 'Fast 8 bit 1280x1024 mode' SUN_FB_FAST_MONO
+	if [ "$TADPOLE_FB_WEITEK" = "n" ]; then
+		bool 'Generic AutoResolution mode' SUN_FB_GENERIC
+		fbs=$SUN_FB_CGSIX
+		fbs=$fbs$SUN_FB_TCX
+		fbs=$fbs$SUN_FB_CGTHREE
+		fbs=$fbs$SUN_FB_BWTWO
+		fbs=$fbs$SUN_FB_CGFOURTEEN
+		fbs=$fbs$SUN_FB_LEO
+		fbs=$fbs$TADPOLE_FB_WEITEK
+		fbs=$fbs$SUN_FB_GENERIC
+		if [ "$fbs" = "nnnnnnnn" ]; then
+			echo "Warning: You have excluded ALL FB Support"
+			echo "Notice:  Enabling Generic AutoResolution"
+			define_bool SUN_FB_GENERIC y
+		fi
+	else
+		define_bool SUN_FB_GENERIC y
+	fi
+else
+	define_bool SUN_FB_CGSIX y
+	define_bool SUN_FB_TCX y
+	define_bool SUN_FB_CGTHREE y
+	define_bool SUN_FB_CGFOURTEEN y
+	define_bool SUN_FB_BWTWO y
+	define_bool SUN_FB_LEO y
+	define_bool TADPOLE_FB_WEITEK y
+	define_bool SUN_FB_FAST_ONE y
+	define_bool SUN_FB_FAST_TWO y
+	define_bool SUN_FB_FAST_MONO y
+	define_bool SUN_FB_GENERIC y
+fi
+
+comment 'Misc Linux/SPARC drivers'
+tristate '/dev/openprom device support' CONFIG_SUN_OPENPROMIO
+tristate 'Mostek real time clock support' CONFIG_SUN_MOSTEK_RTC
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/Makefile linux/drivers/sbus/char/Makefile
--- v2.1.15/linux/drivers/sbus/char/Makefile	Thu Apr 25 13:27:42 1996
+++ linux/drivers/sbus/char/Makefile	Fri Dec 13 11:37:32 1996
@@ -7,7 +7,63 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
+# Dave Redman Frame Buffer tuning support.
+# OK this is kind of ugly but it does allow drivers to be added fairly
+# easily. and you can even choose what sort of support you want.
+ifdef SUN_FB_CGSIX
+ FB_OBJS +=	cgsix.o
+endif
+ifdef SUN_FB_CGTHREE
+ FB_OBJS +=	cgthree.o
+endif
+ifdef SUN_FB_TCX
+  FB_OBJS +=	tcx.o
+endif
+ifdef SUN_FB_BWTWO
+ FB_OBJS +=	bwtwo.o
+endif
+ifdef SUN_FB_LEO
+ FB_OBJS +=	leo.o
+endif
+ifdef SUN_FB_CGFOURTEEN
+ FB_OBJS +=	cgfourteen.o
+endif
+ifdef TADPOLE_FB_WEITEK
+ FB_OBJS +=	weitek.o
+endif
+#ifdef SUN_FB_FAST_ONE
+# FB_OBJS +=	sun_8bit_fast1.o
+#endif
+#ifdef SUN_FB_FAST_TWO
+# FB_OBJS +=	sun_8bit_fast2.o
+#endif
+#ifdef SUN_FB_FAST_MONO
+# FB_OBJS +=	sun_mono_fast1.o
+#endif
+#ifdef SUN_FB_GENERIC
+# FB_OBJS +=	sun_8bit_generic.o
+#endif
+
 O_TARGET := sunchar.o
-O_OBJS   := suncons.o sunkbd.o sunkeymap.o sunmouse.o sunserial.o
+O_OBJ    := ${FB_OBJS} suncons.o  sunfb.o
+O_OBJS   := ${O_OBJ} sunkbd.o sunkeymap.o sunmouse.o sunserial.o
+M_OBJS   :=
+
+ifeq ($(CONFIG_SUN_OPENPROMIO),y)
+O_OBJS += openprom.o
+else
+  ifeq ($(CONFIG_SUN_OPENPROMIO),m)
+  M_OBJS += openprom.o
+  endif
+endif
+
+ifeq ($(CONFIG_SUN_MOSTEK_RTC),y)
+O_OBJS += rtc.o
+else
+  ifeq ($(CONFIG_SUN_MOSTEK_RTC),m)
+  M_OBJS += rtc.o
+  endif
+endif
 
 include $(TOPDIR)/Rules.make
+
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/bwtwo.c linux/drivers/sbus/char/bwtwo.c
--- v2.1.15/linux/drivers/sbus/char/bwtwo.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/bwtwo.c	Fri Dec 13 11:37:32 1996
@@ -0,0 +1,108 @@
+/* $Id: bwtwo.c,v 1.8 1996/11/23 19:54:05 ecd Exp $
+ * bwtwo.c: bwtwo console driver
+ *
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ */
+
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/fbio.h>
+#include <asm/pgtable.h>
+
+#include "../../char/vt_kern.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+#include "fb.h"
+#include "cg_common.h"
+
+/* OBio addresses for the bwtwo registers */
+#define BWTWO_REGISTER_OFFSET 0x400000
+
+struct bwtwo_regs {
+	__volatile__ struct bt_regs	bt;
+	__volatile__ __u8		control;
+	__volatile__ __u8		status;
+	__volatile__ __u8		cursor_start;
+	__volatile__ __u8		cursor_end;
+	__volatile__ __u8		vcontrol[12];
+};
+
+/* Control Register Constants */
+#define BWTWO_CTL_ENABLE_INTS   0x80
+#define BWTWO_CTL_ENABLE_VIDEO  0x40
+#define BWTWO_CTL_ENABLE_TIMING 0x20
+#define BWTWO_CTL_ENABLE_CURCMP 0x10
+#define BWTWO_CTL_XTAL_MASK     0x0C
+#define BWTWO_CTL_DIVISOR_MASK  0x03
+
+/* Status Register Constants */
+#define BWTWO_STAT_PENDING_INT  0x80
+#define BWTWO_STAT_MSENSE_MASK  0x70
+#define BWTWO_STAT_ID_MASK      0x0f
+
+
+static int
+bwtwo_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
+	    long base, fbinfo_t *fb)
+{
+	uint size, map_offset, r;
+	int map_size;
+	
+	map_size = size = vma->vm_end - vma->vm_start;
+	
+	if (vma->vm_offset & ~PAGE_MASK)
+		return -ENXIO;
+
+	/* To stop the swapper from even considering these pages */
+	vma->vm_flags |= FB_MMAP_VM_FLAGS;
+
+	/* This routine should also map the register if asked for,
+	 * but we don't do that yet.
+	 */
+	map_offset = get_phys ((uint) fb->base);
+	r = io_remap_page_range (vma->vm_start, map_offset, map_size,
+				 vma->vm_page_prot, fb->space);
+	if (r) return -EAGAIN;
+	vma->vm_inode = inode;
+	inode->i_count++;
+	return 0;
+}
+
+static void
+bwtwo_blank (fbinfo_t *fb)
+{
+	fb->info.bwtwo.regs->control &= ~BWTWO_CTL_ENABLE_VIDEO;
+}
+
+static void
+bwtwo_unblank (fbinfo_t *fb)
+{
+	fb->info.bwtwo.regs->control |= BWTWO_CTL_ENABLE_VIDEO;
+}
+
+__initfunc(void bwtwo_setup (fbinfo_t *fb, int slot, uint bwtwo, int bw2_io))
+{
+	printk ("bwtwo%d at 0x%8.8x\n", slot, bwtwo);
+	fb->type.fb_cmsize = 0;
+	fb->mmap = bwtwo_mmap;
+	fb->loadcmap = 0;
+	fb->ioctl = 0;
+	fb->reset = 0;
+	fb->blank = bwtwo_blank;
+	fb->unblank = bwtwo_unblank;
+	fb->info.bwtwo.regs = sparc_alloc_io ((void *)bwtwo +
+		BWTWO_REGISTER_OFFSET, 0, sizeof (struct bwtwo_regs),
+		"bwtwo_regs", bw2_io, 0);
+	if(!fb->base)
+		fb->base = (unsigned long) sparc_alloc_io((void *)bwtwo, 0,
+		  ((fb->type.fb_depth*fb->type.fb_height*fb->type.fb_width)/8),
+		  "bwtwo_fbase", bw2_io, 0);
+
+	if (slot && sun_prom_console_id != slot)
+		bwtwo_blank (fb);
+}
+
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/cg_common.h linux/drivers/sbus/char/cg_common.h
--- v2.1.15/linux/drivers/sbus/char/cg_common.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/cg_common.h	Fri Dec 13 11:37:32 1996
@@ -0,0 +1,28 @@
+/* sun_cg_common.h
+ * contains the definitions of the structures that various sun
+ * frame buffer can use to do console driver stuff.
+ * 
+ * This is not in sun_framebuffer.h because you may not want cgXX
+ * support so you wont require this.
+ *
+ */
+
+#define BT_D4M3(x) ((((x) >> 2) << 1) + ((x) >> 2))     /* (x / 4) * 3 */
+#define BT_D4M4(x) ((x) & ~3)                           /* (x / 4) * 4 */
+
+#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2))      /* (x/4)*3 */
+#define D4M4(x) ((x)&~0x3)                      /* (x/4)*4 */
+
+struct bt_regs {
+    volatile unsigned int addr;		  /* address register */
+    volatile unsigned int color_map;	  /* color map */
+    volatile unsigned int control;	  /* control register */
+    volatile unsigned int cursor;	  /* cursor map register */
+};
+
+/* The cg3 driver, obio space addresses for mapping the cg3 stuff */
+/* We put these constants here, because the cg14 driver initially will emulate a cg3 */
+#define CG3_REGS 0x400000
+#define CG3_RAM	 0x800000
+
+
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/cgfourteen.c linux/drivers/sbus/char/cgfourteen.c
--- v2.1.15/linux/drivers/sbus/char/cgfourteen.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/cgfourteen.c	Fri Dec 13 11:37:32 1996
@@ -0,0 +1,471 @@
+/* $Id: cgfourteen.c,v 1.16 1996/11/22 11:57:06 ecd Exp $
+ * cgfourteen.c: Sun SparcStation console support.
+ *
+ * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * TODO:
+ *
+ * Add the ioctls for CLUT manipulation.
+ * Map only the amount requested, not a constant amount.
+ * XBGR mapping.
+ * Add the interrupt handler.
+*/
+
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/fbio.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+
+#include "../../char/vt_kern.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+#include "fb.h"
+
+#define CG14_MCR_INTENABLE_SHIFT	7
+#define CG14_MCR_INTENABLE_MASK		0x80
+#define CG14_MCR_VIDENABLE_SHIFT	6
+#define CG14_MCR_VIDENABLE_MASK		0x40
+#define CG14_MCR_PIXMODE_SHIFT		4
+#define CG14_MCR_PIXMODE_MASK		0x30
+#define CG14_MCR_TMR_SHIFT		2
+#define CG14_MCR_TMR_MASK		0x0c
+#define CG14_MCR_TMENABLE_SHIFT		1
+#define CG14_MCR_TMENABLE_MASK		0x02
+#define CG14_MCR_RESET_SHIFT		0
+#define CG14_MCR_RESET_MASK		0x01
+#define CG14_REV_REVISION_SHIFT		4
+#define CG14_REV_REVISION_MASK		0xf0
+#define CG14_REV_IMPL_SHIFT		0
+#define CG14_REV_IMPL_MASK		0x0f
+#define CG14_VBR_FRAMEBASE_SHIFT	12
+#define CG14_VBR_FRAMEBASE_MASK		0x00fff000
+#define CG14_VMCR1_SETUP_SHIFT		0
+#define CG14_VMCR1_SETUP_MASK		0x000001ff
+#define CG14_VMCR1_VCONFIG_SHIFT	9
+#define CG14_VMCR1_VCONFIG_MASK		0x00000e00
+#define CG14_VMCR2_REFRESH_SHIFT	0
+#define CG14_VMCR2_REFRESH_MASK		0x00000001
+#define CG14_VMCR2_TESTROWCNT_SHIFT	1
+#define CG14_VMCR2_TESTROWCNT_MASK	0x00000002
+#define CG14_VMCR2_FBCONFIG_SHIFT	2
+#define CG14_VMCR2_FBCONFIG_MASK	0x0000000c
+#define CG14_VCR_REFRESHREQ_SHIFT	0
+#define CG14_VCR_REFRESHREQ_MASK	0x000003ff
+#define CG14_VCR1_REFRESHENA_SHIFT	10
+#define CG14_VCR1_REFRESHENA_MASK	0x00000400
+#define CG14_VCA_CAD_SHIFT		0
+#define CG14_VCA_CAD_MASK		0x000003ff
+#define CG14_VCA_VERS_SHIFT		10
+#define CG14_VCA_VERS_MASK		0x00000c00
+#define CG14_VCA_RAMSPEED_SHIFT		12
+#define CG14_VCA_RAMSPEED_MASK		0x00001000
+#define CG14_VCA_8MB_SHIFT		13
+#define CG14_VCA_8MB_MASK		0x00002000
+
+#define CG14_MCR_PIXMODE_8		0
+#define CG14_MCR_PIXMODE_16		2
+#define CG14_MCR_PIXMODE_32		3
+
+struct cg14_regs{
+	volatile u8 mcr;	/* Master Control Reg */
+	volatile u8 ppr;	/* Packed Pixel Reg */
+	volatile u8 tms[2];	/* Test Mode Status Regs */
+	volatile u8 msr;	/* Master Status Reg */
+	volatile u8 fsr;	/* Fault Status Reg */
+	volatile u8 rev;	/* Revision & Impl */
+	volatile u8 ccr;	/* Clock Control Reg */
+	volatile u32 tmr;	/* Test Mode Read Back */
+	volatile u8 mod;	/* Monitor Operation Data Reg */
+	volatile u8 acr;	/* Aux Control */
+	u8 xxx0[6];
+	volatile u16 hct;	/* Hor Counter */
+	volatile u16 vct;	/* Vert Counter */
+	volatile u16 hbs;	/* Hor Blank Start */
+	volatile u16 hbc;	/* Hor Blank Clear */
+	volatile u16 hss;	/* Hor Sync Start */
+	volatile u16 hsc;	/* Hor Sync Clear */
+	volatile u16 csc;	/* Composite Sync Clear */
+	volatile u16 vbs;	/* Vert Blank Start */
+	volatile u16 vbc;	/* Vert Blank Clear */
+	volatile u16 vss;	/* Vert Sync Start */
+	volatile u16 vsc;	/* Vert Sync Clear */
+	volatile u16 xcs;
+	volatile u16 xcc;
+	volatile u16 fsa;	/* Fault Status Address */
+	volatile u16 adr;	/* Address Registers */
+	u8 xxx1[0xce];
+	volatile u8 pcg[0x100]; /* Pixel Clock Generator */
+	volatile u32 vbr;	/* Frame Base Row */
+	volatile u32 vmcr;	/* VBC Master Control */
+	volatile u32 vcr;	/* VBC refresh */
+	volatile u32 vca;	/* VBC Config */
+};
+
+#define CG14_CCR_ENABLE	0x04
+#define CG14_CCR_SELECT 0x02	/* HW/Full screen */
+
+struct cg14_cursor {
+	volatile u32 cpl0[32];	/* Enable plane 0 */
+	volatile u32 cpl1[32];  /* Color selection plane */
+	volatile u8 ccr;	/* Cursor Control Reg */
+	u8 xxx0[3];
+	volatile u16 cursx;	/* Cursor x,y position */
+	volatile u16 cursy;	/* Cursor x,y position */
+	volatile u32 color0;
+	volatile u32 color1;
+	u32 xxx1[0x1bc];
+	volatile u32 cpl0i[32];	/* Enable plane 0 autoinc */
+	volatile u32 cpl1i[32]; /* Color selection autoinc */
+};
+
+struct cg14_dac {
+	volatile u8 addr;	/* Address Register */
+	u8 xxx0[255];
+	volatile u8 glut;	/* Gamma table */
+	u8 xxx1[255];
+	volatile u8 select;	/* Register Select */
+	u8 xxx2[255];
+	volatile u8 mode;	/* Mode Register */
+};
+
+struct cg14_xlut{
+	volatile u8 x_xlut [256];
+	volatile u8 x_xlutd [256];
+	u8 xxx0[0x600];
+	volatile u8 x_xlut_inc [256];
+	volatile u8 x_xlutd_inc [256];
+};
+
+/* Color look up table (clut) */
+/* Each one of these arrays hold the color lookup table (for 256
+ * colors) for each MDI page (I assume then there should be 4 MDI
+ * pages, I still wonder what they are.  I have seen NeXTStep split
+ * the screen in four parts, while operating in 24 bits mode.  Each
+ * integer holds 4 values: alpha value (transparency channel, thanks
+ * go to John Stone (johns@umr.edu) from OpenBSD), red, green and blue
+ *
+ * I currently use the clut instead of the Xlut
+ */
+struct cg14_clut {
+	unsigned int c_clut [256];
+	unsigned int c_clutd [256];    /* i wonder what the 'd' is for */
+	unsigned int c_clut_inc [256];
+	unsigned int c_clutd_inc [256];
+};
+
+static int
+cg14_mmap (struct inode *inode, struct file *file,
+	   struct vm_area_struct *vma, long base, fbinfo_t *fb)
+{
+	uint size, page, r, map_size;
+	uint map_offset = 0;
+	uint ram_size = fb->info.cg14.ramsize;
+
+	printk ("RAMSIZE=%d\n", ram_size);
+	size = vma->vm_end - vma->vm_start;
+        if (vma->vm_offset & ~PAGE_MASK)
+                return -ENXIO;
+
+	/* To stop the swapper from even considering these pages */
+	vma->vm_flags |= FB_MMAP_VM_FLAGS; 
+	
+	/* Each page, see which map applies */
+	for (page = 0; page < size; ){
+		switch (vma->vm_offset+page){
+		case CG3_MMAP_OFFSET-0x7000:
+		        printk ("Wee!  They are mapping the register, report this to miguel@gnu.ai.mit.edu\n");
+			printk ("Mapping fb->info.regs!\n");
+			map_size = 0x7000;
+			map_offset = get_phys ((uint) fb->info.cg14.regs);
+			break;
+			
+		case CG3_MMAP_OFFSET:
+			map_size = size-page;
+			map_offset = get_phys ((uint) fb->base);
+			break;
+
+		case MDI_PLANAR_X16_MAP:
+			map_size = ram_size/2;
+			map_offset = get_phys ((uint) fb->base) | 0x2000000;
+			break;
+			
+		case MDI_PLANAR_C16_MAP:
+			map_size = ram_size/2;
+			map_offset = get_phys ((uint) fb->base) | 0x2800000;
+			break;
+			
+		case MDI_CHUNKY_XBGR_MAP:
+			map_size = 0;
+			printk ("Woo Woo: XBGR not there yet\n");
+			break;
+			
+		case MDI_CHUNKY_BGR_MAP:
+			map_size = ram_size;
+			map_offset = get_phys ((uint) fb->base) | 0x1000000;
+			break;
+			
+		case MDI_PLANAR_X32_MAP:
+			map_size = ram_size/4;
+			map_offset = get_phys ((uint) fb->base) | 0x3000000;
+			break;
+		case MDI_PLANAR_B32_MAP:
+			map_size = ram_size/4;
+			map_offset = get_phys ((uint) fb->base) | 0x3400000;
+			break;
+		case MDI_PLANAR_G32_MAP:
+			map_size = ram_size/4;
+			map_offset = get_phys ((uint) fb->base) | 0x3800000;
+			break;
+		case MDI_PLANAR_R32_MAP:
+			map_size = ram_size/4;
+			map_offset = get_phys ((uint) fb->base) | 0x3c00000;
+			break;
+
+		case MDI_CURSOR_MAP:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint) fb->info.cg14.cursor_regs);
+			break;
+			
+		case CG14_REGS:
+		        printk ("Wee!  They are mapping the register, report this to miguel@gnu.ai.mit.edu\n");
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint) fb->info.cg14.regs);
+			break;
+			
+		case CG14_XLUT:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint) fb->info.cg14.regs+0x3000);
+			break;
+			
+		case CG14_CLUT1:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint) fb->info.cg14.regs+0x4000);
+			break;
+			
+		case CG14_CLUT2:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint) fb->info.cg14.regs+0x5000);
+			break;
+			
+		default:
+			map_size = 0;
+			break;
+		}
+		if (!map_size){
+			page += PAGE_SIZE;
+			continue;
+		}
+		if (page + map_size > size)
+			map_size = size - page;
+		r = io_remap_page_range (vma->vm_start+page,
+					 map_offset,
+					 map_size, vma->vm_page_prot,
+					 fb->space);
+		if (r) return -EAGAIN;
+		page += map_size;
+	}
+        vma->vm_inode = inode;
+        inode->i_count++;
+        return 0;
+}
+
+static void
+cg14_cmap (fbinfo_t *fb, int index, int count)
+{
+	struct cg14_clut *clut = fb->info.cg14.clut;
+	int i;
+	
+	for (i = index; count--; i++){
+		clut->c_clut [i] = 
+			(fb->color_map CM(i,2) << 16) |
+			(fb->color_map CM(i,1) << 8) |
+			(fb->color_map CM(i,0));
+	}
+}
+
+static void
+cg14_setcursormap (fbinfo_t *fb, unsigned char *red,
+                                 unsigned char *green,
+                                 unsigned char *blue)
+{
+        struct cg14_cursor *cur = fb->info.cg14.cursor_regs;
+
+	cur->color0 = ((red[0]) | (green[0] << 8) | (blue[0] << 16));
+	cur->color1 = ((red[1]) | (green[1] << 8) | (blue[1] << 16));
+}
+
+/* Load cursor information */
+static void
+cg14_setcursor (fbinfo_t *fb)
+{
+        struct cg_cursor *c = &fb->cursor;
+	struct cg14_cursor *cur = fb->info.cg14.cursor_regs;
+
+        if (c->enable)
+		cur->ccr |= CG14_CCR_ENABLE;
+        cur->cursx = ((c->cpos.fbx - c->chot.fbx) & 0xfff);
+        cur->cursy = ((c->cpos.fby - c->chot.fby) & 0xfff);
+}
+
+/* Set cursor shape */
+static void
+cg14_setcurshape (fbinfo_t *fb)
+{
+        struct cg14_cursor *cur = fb->info.cg14.cursor_regs;
+        int i;
+
+        for (i = 0; i < 32; i++){
+                cur->cpl0 [i] = fb->cursor.bits[0][i];
+                cur->cpl1 [i] = fb->cursor.bits[1][i];
+        }
+}
+
+/* These ones are for putting the video card on 16/32 bpp */
+static int
+cg14_ioctl (struct inode *inode, struct file *file, unsigned cmd, unsigned long arg, fbinfo_t *fb)
+{
+	switch (cmd){
+	case MDI_RESET: {
+		volatile unsigned char *control = &(fb->info.cg14.regs->mcr);
+		*control = (*control & ~CG14_MCR_PIXMODE_MASK);
+	}
+	break;
+
+	case MDI_GET_CFGINFO: {
+		int error;
+		struct mdi_cfginfo *mdii;
+		
+		error = verify_area (VERIFY_WRITE, (void *) arg,
+				     sizeof (struct mdi_cfginfo));
+		if (error)
+			return error;
+
+		mdii = (struct mdi_cfginfo *) arg;
+#if 0
+		__put_user_ret(2, &mdii->mdi_ncluts, -EFAULT);
+		switch (fb->info.cg14.regs->rev & CG14_REV_IMPL_MASK){
+		case 0:
+		case 2:
+		    break;
+		    
+		case 1:
+		case 3:
+		    __put_user_ret(3, &mdii->mdi_ncluts, -EFAULT);
+		    break;
+		default:
+		    printk ("Unknown implementation number\n");
+		}
+#endif
+		__put_user_ret(FBTYPE_MDICOLOR, &mdii->mdi_type, -EFAULT);
+		__put_user_ret(fb->type.fb_height, &mdii->mdi_height, -EFAULT);
+		__put_user_ret(fb->type.fb_width, &mdii->mdi_width, -EFAULT);
+		__put_user_ret(fb->info.cg14.video_mode, &mdii->mdi_mode, -EFAULT);
+		__put_user_ret(72, &mdii->mdi_pixfreq, -EFAULT); /* FIXME */
+		__put_user_ret(fb->info.cg14.ramsize, &mdii->mdi_size, -EFAULT);
+	}
+	break;
+
+	case MDI_SET_PIXELMODE: {
+		int newmode;
+		volatile u8 *control;
+		
+		get_user_ret(newmode, (int *)arg, -EFAULT);
+		control = &(fb->info.cg14.regs->mcr);
+		switch (newmode){
+		case MDI_32_PIX:
+			*control = (*control & ~CG14_MCR_PIXMODE_MASK) |
+				(CG14_MCR_PIXMODE_32 << CG14_MCR_PIXMODE_SHIFT);
+			break;
+		case MDI_16_PIX:
+			*control = (*control & ~CG14_MCR_PIXMODE_MASK) | 0x20;
+			break;
+		case MDI_8_PIX:
+			*control = (*control & ~CG14_MCR_PIXMODE_MASK);
+			break;
+
+		default:
+			return -ENOSYS;
+		}
+		fb->info.cg14.video_mode = newmode;
+	}
+	break;
+	
+	} /* switch */
+	return 0;
+}
+
+static void
+cg14_switch_from_graph (void)
+{
+	fbinfo_t *fb = &(fbinfo [0]);
+	struct cg14_info *cg14info = (struct cg14_info *) &fb->info.cg14;
+
+	/* Set the 8-bpp mode */
+	if (fb->open && fb->mmaped){
+		volatile char *mcr = (char *)(&cg14info->regs->mcr);
+
+		fb->info.cg14.video_mode = 8;
+		*mcr = (*mcr & ~(CG14_MCR_PIXMODE_MASK));
+	}
+}
+
+void
+cg14_reset (fbinfo_t *fb)
+{
+	volatile char *mcr = &(fb->info.cg14.regs->mcr);
+
+	*mcr = (*mcr & ~(CG14_MCR_PIXMODE_MASK));
+}
+
+__initfunc(void cg14_setup (fbinfo_t *fb, int slot, int con_node, uint cg14, int cg14_io))
+{
+	struct cg14_info *cg14info;
+	uint bases [2];
+	uint cg14regs = 0;
+	struct cg14_regs *regs = 0;
+
+	if (!cg14) {
+		prom_getproperty (con_node, "address", (char *) &bases[0], 8);
+		cg14 = bases[1];
+		cg14regs = bases[0];
+		fb->base = cg14;
+		fb->info.cg14.regs = (struct cg14_regs *) cg14regs;
+		regs = (struct cg14_regs *) cg14regs;
+	}
+	
+	if (!cg14regs){
+		printk ("The PROM does not have mapped the frame buffer or the registers\n"
+			"Mr. Penguin can't use that");
+		prom_halt ();
+	}
+	
+	fb->type.fb_cmsize = 256;
+	fb->mmap =  cg14_mmap;
+	fb->loadcmap = cg14_cmap;
+	fb->setcursor = cg14_setcursor;
+	fb->setcursormap = cg14_setcursormap;
+	fb->setcurshape = cg14_setcurshape;
+	fb->ioctl = cg14_ioctl;
+	fb->switch_from_graph = cg14_switch_from_graph;
+	fb->postsetup = sun_cg_postsetup;
+	fb->reset = cg14_reset;
+	fb->blank = 0;
+	fb->unblank = 0;
+	fb->info.cg14.video_mode = 8;
+	fb->emulations [1] = FBTYPE_SUN3COLOR;
+	fb->type.fb_depth = 24;
+	cg14info = (struct cg14_info *) &fb->info.cg14;
+	cg14info->clut = (void *) (cg14regs + CG14_CLUT1);
+	cg14info->cursor_regs = (void *) (cg14regs + CG14_CURSORREGS);
+
+	/* If the bit is turned on, the card has 8 mb of ram, otherwise just 4 */
+	cg14info->ramsize = (regs->vca & CG14_VCA_8MB_MASK ? 8 : 4) * 1024 * 1024;
+	printk ("cgfourteen%d at 0x%8.8x with %d megs of RAM rev=%d, impl=%d\n",
+		slot, cg14, cg14info->ramsize/(1024*1024), regs->rev >> 4, regs->rev & 0xf);
+}
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/cgsix.c linux/drivers/sbus/char/cgsix.c
--- v2.1.15/linux/drivers/sbus/char/cgsix.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/cgsix.c	Fri Dec 13 15:59:44 1996
@@ -0,0 +1,636 @@
+/* $Id: cgsix.c,v 1.18 1996/11/13 05:10:19 davem Exp $
+ * cgsix.c: cgsix frame buffer driver
+ *
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ */
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/fbio.h>
+#include <asm/pgtable.h>
+
+#include "../../char/vt_kern.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+#include "fb.h"
+#include "cg_common.h"
+
+/* Offset of interesting structures in the OBIO space */
+/*
+ * Brooktree is the video dac and is funny to program on the cg6.
+ * (it's even funnier on the cg3)
+ * The FBC could be the the frame buffer control
+ * The FHC could is the frame buffer hardware control.
+ */
+#define CG6_ROM_OFFSET       0x0
+#define CG6_BROOKTREE_OFFSET 0x200000
+#define CG6_DHC_OFFSET       0x240000
+#define CG6_ALT_OFFSET       0x280000
+#define CG6_FHC_OFFSET       0x300000
+#define CG6_THC_OFFSET       0x301000
+#define CG6_FBC_OFFSET       0x700000
+#define CG6_TEC_OFFSET       0x701000
+#define CG6_RAM_OFFSET       0x800000
+
+/* FHC definitions */
+#define CG6_FHC_FBID_SHIFT           24
+#define CG6_FHC_FBID_MASK            255
+#define CG6_FHC_REV_SHIFT            20
+#define CG6_FHC_REV_MASK             15
+#define CG6_FHC_FROP_DISABLE         (1 << 19)
+#define CG6_FHC_ROW_DISABLE          (1 << 18)
+#define CG6_FHC_SRC_DISABLE          (1 << 17)
+#define CG6_FHC_DST_DISABLE          (1 << 16)
+#define CG6_FHC_RESET                (1 << 15)
+#define CG6_FHC_LITTLE_ENDIAN        (1 << 13)
+#define CG6_FHC_RES_MASK             (3 << 11)
+#define CG6_FHC_1024                 (0 << 11)
+#define CG6_FHC_1152                 (1 << 11)
+#define CG6_FHC_1280                 (2 << 11)
+#define CG6_FHC_1600                 (3 << 11)
+#define CG6_FHC_CPU_MASK             (3 << 9)
+#define CG6_FHC_CPU_SPARC            (0 << 9)
+#define CG6_FHC_CPU_68020            (1 << 9)
+#define CG6_FHC_CPU_386              (2 << 9)
+#define CG6_FHC_TEST		     (1 << 8)
+#define CG6_FHC_TEST_X_SHIFT	     4
+#define CG6_FHC_TEST_X_MASK	     15
+#define CG6_FHC_TEST_Y_SHIFT	     0
+#define CG6_FHC_TEST_Y_MASK	     15
+
+/* FBC mode definitions */
+#define CG6_FBC_BLIT_IGNORE		0x00000000
+#define CG6_FBC_BLIT_NOSRC		0x00100000
+#define CG6_FBC_BLIT_SRC		0x00200000
+#define CG6_FBC_BLIT_ILLEGAL		0x00300000
+#define CG6_FBC_BLIT_MASK		0x00300000
+
+#define CG6_FBC_VBLANK			0x00080000
+
+#define CG6_FBC_MODE_IGNORE		0x00000000
+#define CG6_FBC_MODE_COLOR8		0x00020000
+#define CG6_FBC_MODE_COLOR1		0x00040000
+#define CG6_FBC_MODE_HRMONO		0x00060000
+#define CG6_FBC_MODE_MASK		0x00060000
+
+#define CG6_FBC_DRAW_IGNORE		0x00000000
+#define CG6_FBC_DRAW_RENDER		0x00008000
+#define CG6_FBC_DRAW_PICK		0x00010000
+#define CG6_FBC_DRAW_ILLEGAL		0x00018000
+#define CG6_FBC_DRAW_MASK		0x00018000
+
+#define CG6_FBC_BWRITE0_IGNORE		0x00000000
+#define CG6_FBC_BWRITE0_ENABLE		0x00002000
+#define CG6_FBC_BWRITE0_DISABLE		0x00004000
+#define CG6_FBC_BWRITE0_ILLEGAL		0x00006000
+#define CG6_FBC_BWRITE0_MASK		0x00006000
+
+#define CG6_FBC_BWRITE1_IGNORE		0x00000000
+#define CG6_FBC_BWRITE1_ENABLE		0x00000800
+#define CG6_FBC_BWRITE1_DISABLE		0x00001000
+#define CG6_FBC_BWRITE1_ILLEGAL		0x00001800
+#define CG6_FBC_BWRITE1_MASK		0x00001800
+
+#define CG6_FBC_BREAD_IGNORE		0x00000000
+#define CG6_FBC_BREAD_0			0x00000200
+#define CG6_FBC_BREAD_1			0x00000400
+#define CG6_FBC_BREAD_ILLEGAL		0x00000600
+#define CG6_FBC_BREAD_MASK		0x00000600
+
+#define CG6_FBC_BDISP_IGNORE		0x00000000
+#define CG6_FBC_BDISP_0			0x00000080
+#define CG6_FBC_BDISP_1			0x00000100
+#define CG6_FBC_BDISP_ILLEGAL		0x00000180
+#define CG6_FBC_BDISP_MASK		0x00000180
+
+#define CG6_FBC_INDEX_MOD		0x00000040
+#define CG6_FBC_INDEX_MASK		0x00000030
+
+/* THC definitions */
+#define CG6_THC_MISC_REV_SHIFT       16
+#define CG6_THC_MISC_REV_MASK        15
+#define CG6_THC_MISC_RESET           (1 << 12)
+#define CG6_THC_MISC_VIDEO           (1 << 10)
+#define CG6_THC_MISC_SYNC            (1 << 9)
+#define CG6_THC_MISC_VSYNC           (1 << 8)
+#define CG6_THC_MISC_SYNC_ENAB       (1 << 7)
+#define CG6_THC_MISC_CURS_RES        (1 << 6)
+#define CG6_THC_MISC_INT_ENAB        (1 << 5)
+#define CG6_THC_MISC_INT             (1 << 4)
+#define CG6_THC_MISC_INIT            0x9f
+
+/* The contents are unknown */
+struct cg6_tec {
+	volatile int tec_matrix;
+	volatile int tec_clip;
+	volatile int tec_vdc;
+};
+
+struct cg6_thc {
+        uint thc_pad0[512];
+	volatile uint thc_hs;		/* hsync timing */
+	volatile uint thc_hsdvs;
+	volatile uint thc_hd;
+	volatile uint thc_vs;		/* vsync timing */
+	volatile uint thc_vd;
+	volatile uint thc_refresh;
+	volatile uint thc_misc;
+	uint thc_pad1[56];
+	volatile uint thc_cursxy;	/* cursor x,y position (16 bits each) */
+	volatile uint thc_cursmask[32];	/* cursor mask bits */
+	volatile uint thc_cursbits[32];	/* what to show where mask enabled */
+};
+
+struct cg6_fbc {
+	u32		xxx0[1];
+	volatile u32	mode;
+	volatile u32	clip;
+	u32		xxx1[1];	    
+	volatile u32	s;
+	volatile u32	draw;
+	volatile u32	blit;
+	volatile u32	font;
+	u32		xxx2[24];
+	volatile u32	x0, y0, z0, color0;
+	volatile u32	x1, y1, z1, color1;
+	volatile u32	x2, y2, z2, color2;
+	volatile u32	x3, y3, z3, color3;
+	volatile u32	offx, offy;
+	u32		xxx3[2];
+	volatile u32	incx, incy;
+	u32		xxx4[2];
+	volatile u32	clipminx, clipminy;
+	u32		xxx5[2];
+	volatile u32	clipmaxx, clipmaxy;
+	u32		xxx6[2];
+	volatile u32	fg;
+	volatile u32	bg;
+	volatile u32	alu;
+	volatile u32	pm;
+	volatile u32	pixelm;
+	u32		xxx7[2];
+	volatile u32	patalign;
+	volatile u32	pattern[8];
+	u32		xxx8[432];
+	volatile u32	apointx, apointy, apointz;
+	u32		xxx9[1];
+	volatile u32	rpointx, rpointy, rpointz;
+	u32		xxx10[5];
+	volatile u32	pointr, pointg, pointb, pointa;
+	volatile u32	alinex, aliney, alinez;
+	u32		xxx11[1];
+	volatile u32	rlinex, rliney, rlinez;
+	u32		xxx12[5];
+	volatile u32	liner, lineg, lineb, linea;
+	volatile u32	atrix, atriy, atriz;
+	u32		xxx13[1];
+	volatile u32	rtrix, rtriy, rtriz;
+	u32		xxx14[5];
+	volatile u32	trir, trig, trib, tria;
+	volatile u32	aquadx, aquady, aquadz;
+	u32		xxx15[1];
+	volatile u32	rquadx, rquady, rquadz;
+	u32		xxx16[5];
+	volatile u32	quadr, quadg, quadb, quada;
+	volatile u32	arectx, arecty, arectz;
+	u32		xxx17[1];
+	volatile u32	rrectx, rrecty, rrectz;
+	u32		xxx18[5];
+	volatile u32	rectr, rectg, rectb, recta;
+};
+
+static void
+cg6_restore_palette (fbinfo_t *fbinfo)
+{
+	volatile struct bt_regs *bt;
+
+	bt = fbinfo->info.cg6.bt;
+	bt->addr = 0;
+	bt->color_map = 0xffffffff;
+	bt->color_map = 0xffffffff;
+	bt->color_map = 0xffffffff;
+}
+
+static void cg6_blitc(unsigned short, int, int);
+static void cg6_setw(int, int, unsigned short, int);
+static void cg6_cpyw(int, int, unsigned short *, int);
+static void cg6_fill(int, int, int *);
+
+/* Ugh: X wants to mmap a bunch of cute stuff at the same time :-( */
+/* So, we just mmap the things that are being asked for */
+static int
+cg6_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
+	  long base, fbinfo_t *fb)
+{
+	uint size, page, r, map_size;
+	uint map_offset = 0;
+	
+	size = vma->vm_end - vma->vm_start;
+        if (vma->vm_offset & ~PAGE_MASK)
+                return -ENXIO;
+
+	/* To stop the swapper from even considering these pages */
+	vma->vm_flags |= FB_MMAP_VM_FLAGS;
+	
+	/* Each page, see which map applies */
+	for (page = 0; page < size; ){
+		switch (vma->vm_offset+page){
+		case CG6_TEC:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.cg6.tec);
+			break;
+		case CG6_FBC:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.cg6.fbc);
+			break;
+		case CG6_FHC:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.cg6.fhc);
+			break;
+		case CG6_THC:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.cg6.thc);
+			break;
+		case CG6_BTREGS:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.cg6.bt);
+			break;
+			
+		case CG6_DHC:
+			map_size = PAGE_SIZE * 40;
+			map_offset = get_phys ((uint)fb->info.cg6.dhc);
+			break;
+			
+		case CG6_ROM:
+			map_size = PAGE_SIZE * 16;
+			map_offset = get_phys ((uint)fb->info.cg6.rom);
+			break;
+
+		case CG6_RAM:
+			map_size = size-page;
+			map_offset = get_phys ((uint) fb->base);
+			if (map_size < fb->type.fb_size)
+				map_size = fb->type.fb_size;
+			break;
+		default:
+			map_size = 0;
+			break;
+		}
+		if (!map_size){
+			page += PAGE_SIZE;
+			continue;
+		}
+		if (page + map_size > size)
+			map_size = size - page;
+		r = io_remap_page_range (vma->vm_start+page,
+					 map_offset,
+					 map_size, vma->vm_page_prot,
+					 fb->space);
+		if (r) return -EAGAIN;
+		page += map_size;
+	}
+        vma->vm_inode = inode;
+        inode->i_count++;
+        return 0;
+}
+
+static void
+cg6_loadcmap (fbinfo_t *fb, int index, int count)
+{
+	struct bt_regs *bt = fb->info.cg6.bt;
+	int i;
+	
+	bt->addr = index << 24;
+	for (i = index; count--; i++){
+		bt->color_map = fb->color_map CM(i,0) << 24;
+		bt->color_map = fb->color_map CM(i,1) << 24;
+		bt->color_map = fb->color_map CM(i,2) << 24;
+	}
+}
+
+static void
+cg6_setcursormap (fbinfo_t *fb, unsigned char *red,
+				 unsigned char *green,
+				 unsigned char *blue)
+{
+	struct bt_regs *bt = fb->info.cg6.bt;
+	
+	bt->addr = 1 << 24;
+	bt->cursor = red[0] << 24;
+	bt->cursor = green[0] << 24;
+	bt->cursor = blue[0] << 24;
+	bt->addr = 3 << 24;
+	bt->cursor = red[1] << 24;
+	bt->cursor = green[1] << 24;
+	bt->cursor = blue[1] << 24;
+}
+
+/* Load cursor information */
+static void
+cg6_setcursor (fbinfo_t *fb)
+{
+	uint v;
+	struct cg_cursor *c = &fb->cursor;
+
+	if (c->enable){
+		v = ((c->cpos.fbx - c->chot.fbx) << 16)
+		   |((c->cpos.fby - c->chot.fby) & 0xffff);
+	} else {
+		/* Magic constant to turn off the cursor */
+		v = ((65536-32) << 16) | (65536-32);
+	}
+	fb->info.cg6.thc->thc_cursxy = v;
+}
+
+/* Set cursor shape */
+static void
+cg6_setcurshape (fbinfo_t *fb)
+{
+	struct cg6_thc *thc = fb->info.cg6.thc;
+	int i;
+
+        for (i = 0; i < 32; i++){
+                thc->thc_cursmask [i] = fb->cursor.bits[0][i];
+                thc->thc_cursbits [i] = fb->cursor.bits[1][i];
+        }
+}
+
+static void
+cg6_blank (fbinfo_t *fb)
+{
+	fb->info.cg6.thc->thc_misc &= ~CG6_THC_MISC_VIDEO;
+}
+
+static void
+cg6_unblank (fbinfo_t *fb)
+{
+	fb->info.cg6.thc->thc_misc |= CG6_THC_MISC_VIDEO;
+}
+
+void
+cg6_reset (fbinfo_t *fb)
+{
+	struct cg6_info *cg6 = &(fb->info.cg6);
+	unsigned int rev, conf;
+
+	if (fb->setcursor)
+		sun_hw_hide_cursor ();
+	/* Turn off stuff in the Transform Engine. */
+	cg6->tec->tec_matrix = 0;
+	cg6->tec->tec_clip = 0;
+	cg6->tec->tec_vdc = 0;
+
+	/* Take care of bugs in old revisions. */
+	rev = (*(cg6->fhc) >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK;
+	if (rev < 5) {
+		conf = (*(cg6->fhc) & CG6_FHC_RES_MASK) |
+			CG6_FHC_CPU_68020 | CG6_FHC_TEST |
+			(11 << CG6_FHC_TEST_X_SHIFT) |
+			(11 << CG6_FHC_TEST_Y_SHIFT);
+		if (rev < 2)
+			conf |= CG6_FHC_DST_DISABLE;
+		*(cg6->fhc) = conf;
+	}
+
+	/* Set things in the FBC. */
+	cg6->fbc->mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK |
+			    CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK |
+			    CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK |
+			    CG6_FBC_BDISP_MASK);
+	cg6->fbc->mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 |
+			   CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE |
+			   CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 |
+			   CG6_FBC_BDISP_0);
+	cg6->fbc->clip = 0;
+	cg6->fbc->offx = 0;
+	cg6->fbc->offy = 0;
+	cg6->fbc->clipminx = 0;
+	cg6->fbc->clipminy = 0;
+	cg6->fbc->clipmaxx = fb->type.fb_width - 1;
+	cg6->fbc->clipmaxy = fb->type.fb_height - 1;
+	/* Enable cursor in Brooktree DAC. */
+	cg6->bt->addr = 0x06 << 24;
+	cg6->bt->control |= 0x03 << 24;
+}
+
+__initfunc(void cg6_setup (fbinfo_t *fb, int slot, uint cg6, int cg6_io))
+{
+	struct cg6_info *cg6info;
+	unsigned int rev, cpu, conf;
+
+	printk ("cgsix%d at 0x%8.8x ", slot, (uint) cg6);
+	
+	/* Fill in parameters we left out */
+	fb->type.fb_cmsize = 256;
+	fb->mmap = cg6_mmap;
+	fb->loadcmap = cg6_loadcmap;
+	fb->reset = cg6_reset;
+	fb->blank = cg6_blank;
+	fb->unblank = cg6_unblank;
+	fb->setcursor = cg6_setcursor;
+	fb->setcursormap = cg6_setcursormap;
+	fb->setcurshape = cg6_setcurshape;
+	fb->postsetup = sun_cg_postsetup;
+	fb->blitc = cg6_blitc;
+	fb->setw = cg6_setw;
+	fb->cpyw = cg6_cpyw;
+	
+	cg6info = (struct cg6_info *) &fb->info.cg6;
+
+	/* Map the hardware registers */
+	cg6info->bt = sparc_alloc_io ((void *) cg6+CG6_BROOKTREE_OFFSET, 0,
+		 sizeof (struct bt_regs), "cgsix_dac", cg6_io, 0);
+	cg6info->fhc = sparc_alloc_io ((void *) cg6+CG6_FHC_OFFSET, 0,
+		 sizeof (int), "cgsix_fhc", cg6_io, 0);
+	cg6info->thc = sparc_alloc_io ((void *) cg6+CG6_THC_OFFSET, 0,
+		 sizeof (struct cg6_thc), "cgsix_thc", cg6_io, 0);
+	cg6info->tec = sparc_alloc_io ((void *) cg6+CG6_TEC_OFFSET, 0,
+		 sizeof (struct cg6_tec), "cgsix_tec", cg6_io, 0);
+	cg6info->dhc = sparc_alloc_io ((void *) cg6+CG6_DHC_OFFSET, 0,
+		 0x40000, "cgsix_dhc", cg6_io, 0);
+	cg6info->fbc = sparc_alloc_io ((void *) cg6+CG6_FBC_OFFSET, 0,
+		 0x1000, "cgsix_fbc", cg6_io, 0);
+	cg6info->rom = sparc_alloc_io ((void *) cg6+CG6_ROM_OFFSET, 0,
+		 0x10000, "cgsix_rom", cg6_io, 0);
+	if (!fb->base){
+		fb->base = (uint) sparc_alloc_io ((void *) cg6+CG6_RAM_OFFSET, 0,
+                    fb->type.fb_size, "cgsix_ram", cg6_io, 0);
+	}
+	if (slot == sun_prom_console_id)
+		fb_restore_palette = cg6_restore_palette;
+
+	/* Initialize Brooktree DAC */
+	cg6info->bt->addr = 0x04 << 24;		/* color planes */
+	cg6info->bt->control = 0xff << 24;
+	cg6info->bt->addr = 0x05 << 24;
+	cg6info->bt->control = 0x00 << 24;
+	cg6info->bt->addr = 0x06 << 24;		/* overlay plane */
+	cg6info->bt->control = 0x73 << 24;
+	cg6info->bt->addr = 0x07 << 24;
+	cg6info->bt->control = 0x00 << 24;
+
+	printk("TEC Rev %x ",
+		(cg6info->thc->thc_misc >> CG6_THC_MISC_REV_SHIFT) &
+		CG6_THC_MISC_REV_MASK);
+
+	/* Get FHC Revision */
+	conf = *(cg6info->fhc);
+
+	cpu = conf & CG6_FHC_CPU_MASK;
+	printk("CPU ");
+	if (cpu == CG6_FHC_CPU_SPARC)
+		printk("sparc ");
+	else if (cpu == CG6_FHC_CPU_68020)
+		printk("68020 ");
+	else
+		printk("386 ");
+
+	rev = conf >> CG6_FHC_REV_SHIFT & CG6_FHC_REV_MASK;
+	printk("Rev %x\n", rev);
+
+	if (slot && sun_prom_console_id == slot) return;
+	
+	/* Reset the cg6 */
+	cg6_reset(fb);
+	
+	if (!slot)
+	/* Enable Video */
+		cg6_unblank(fb);
+	else
+		cg6_blank(fb);
+}
+
+extern unsigned char vga_font[];
+
+#define GX_BLITC_START(attr) \
+	{ \
+		register struct cg6_fbc *gx = fbinfo[0].info.cg6.fbc; \
+		register uint i; \
+		do { \
+			i = gx->s; \
+		} while (i & 0x10000000); \
+		gx->fg = attr & 0xf; \
+		gx->bg = (attr>>4); \
+		gx->mode = 0x140000; \
+		gx->alu = 0xe880fc30; \
+		gx->pixelm = ~(0); \
+		gx->s = 0; \
+		gx->clip = 0; \
+		gx->pm = 0xff;
+#define GX_BLITC_BODY4(count,x,y,start,action) \
+		while (count >= 4) { \
+			count -= 4; \
+		    	gx->incx = 0; \
+		    	gx->incy = 1; \
+		    	gx->x0 = x; \
+		    	gx->x1 = (x += 32) - 1; \
+		    	gx->y0 = y; \
+		    	start; \
+		    	for (i = 0; i < CHAR_HEIGHT; i++) { \
+		    		action; \
+		    	} \
+		}
+#define GX_BLITC_BODY1(x,y,action) \
+		    	gx->incx = 0; \
+		    	gx->incy = 1; \
+		    	gx->x0 = x; \
+		    	gx->x1 = (x += 8) - 1; \
+		    	gx->y0 = y; \
+		    	for (i = 0; i < CHAR_HEIGHT; i++) { \
+		    		action; \
+		    	}
+#define GX_BLITC_END \
+	}
+	
+static void cg6_blitc(unsigned short charattr, int xoff, int yoff)
+{
+	unsigned char attrib = charattr >> 8;
+	unsigned char *p = &vga_font[((unsigned char)charattr) << 4];
+	GX_BLITC_START(attrib)
+	GX_BLITC_BODY1(xoff, yoff, gx->font=((*p++) << 24))
+	GX_BLITC_END
+}
+
+static void cg6_setw(int xoff, int yoff, unsigned short c, int count)
+{
+	unsigned char attrib = c >> 8;
+	unsigned char *p = &vga_font[((unsigned char)c) << 4];
+	register unsigned char *q;
+	register uint l;
+	GX_BLITC_START(attrib)
+	if (count >= 4) {
+		GX_BLITC_BODY4(count, xoff, yoff, q = p, 
+			l = *q++;
+			l |= l << 8;
+			l |= l << 16;
+			gx->font=l)
+	}
+	while (count) {
+		count--;
+		q = p;
+		GX_BLITC_BODY1(xoff, yoff, gx->font=((*q++) << 24));
+	}
+	GX_BLITC_END
+}
+
+static void cg6_cpyw(int xoff, int yoff, unsigned short *p, int count)
+{
+	unsigned char attrib = *p >> 8;
+	unsigned char *p1, *p2, *p3, *p4;
+	GX_BLITC_START(attrib)
+	if (count >= 4) {
+		GX_BLITC_BODY4(count, xoff, yoff, 
+			p1 = &vga_font[((unsigned char)*p++) << 4];
+			p2 = &vga_font[((unsigned char)*p++) << 4];
+			p3 = &vga_font[((unsigned char)*p++) << 4];
+			p4 = &vga_font[((unsigned char)*p++) << 4], 
+			gx->font=((uint)*p4++) | ((((uint)*p3++) | ((((uint)*p2++) | (((uint)*p1++) << 8)) << 8)) << 8))
+	}
+	while (count) {
+		count--;
+		p1 = &vga_font[((unsigned char)*p++) << 4];
+		GX_BLITC_BODY1(xoff, yoff, gx->font=((*p1++) << 24));
+	}
+	GX_BLITC_END
+}
+
+#define GX_FILL_START(attr) \
+	{ \
+		register struct cg6_fbc *gx = fbinfo[0].info.cg6.fbc; \
+		register uint i; \
+		do { \
+			i = gx->s; \
+		} while (i & 0x10000000); \
+		gx->fg = attr & 0xf; \
+		gx->bg = 0; \
+		gx->pixelm = ~(0); \
+		gx->s = 0; \
+		gx->alu = 0xea80ff00; \
+		gx->pm = ~(0); \
+		gx->clip = 0;
+#define GX_FILL_END \
+	}
+	
+static void cg6_fill(int attrib, int count, int *boxes)
+{
+	register int r;
+	
+	attrib = 5;
+	GX_FILL_START(attrib)
+	while (count-- > 0) {
+		gx->arecty = boxes[1];
+		gx->arectx = boxes[0];
+		gx->arecty = boxes[3];
+		gx->arecty = boxes[2];
+		boxes += 4;
+		do {
+			r = gx->draw;
+		} while (r < 0 && (r & 0x20000000) );
+	}
+	GX_FILL_END
+}
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/cgthree.c linux/drivers/sbus/char/cgthree.c
--- v2.1.15/linux/drivers/sbus/char/cgthree.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/cgthree.c	Fri Dec 13 11:37:32 1996
@@ -0,0 +1,138 @@
+/* $Id: cgthree.c,v 1.9 1996/11/13 05:10:21 davem Exp $
+ * cgtree.c: cg3 frame buffer driver
+ *
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * Support for cgRDI added, Nov/96, jj.
+ */
+
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/fbio.h>
+#include <asm/pgtable.h>
+
+#include "../../char/vt_kern.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+#include "fb.h"
+#include "cg_common.h"
+
+/* The cg3 palette is loaded with 4 color values at each time  */
+/* so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on */
+static void
+cg3_loadcmap (fbinfo_t *fb, int index, int count)
+{
+	struct bt_regs *bt = fb->info.cg3.bt;
+	int *i, steps;
+
+	i = (((int *)fb->color_map) + D4M3(index));
+	steps = D4M3(index+count-1) - D4M3(index)+3;
+#if 0	
+	if (fb->info.cg3.cgrdi) {
+		*(volatile u8 *)bt->addr = (u8)(D4M4(index));
+	} else
+#endif	
+	bt->addr = D4M4(index);
+	while (steps--)
+		bt->color_map = *i++;
+}
+
+/* The cg3 is presumed to emulate a cg4, I guess older programs will want that
+ * addresses above 0x4000000 are for cg3, below that it's cg4 emulation.
+ */
+static int
+cg3_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
+	  long base, fbinfo_t *fb)
+{
+	uint  size, page, r, map_size;
+	uint map_offset = 0;
+	
+	size = vma->vm_end - vma->vm_start;
+        if (vma->vm_offset & ~PAGE_MASK)
+                return -ENXIO;
+
+	/* To stop the swapper from even considering these pages */
+	vma->vm_flags |= FB_MMAP_VM_FLAGS; 
+	
+	/* Each page, see which map applies */
+	for (page = 0; page < size; ){
+		switch (vma->vm_offset+page){
+		case CG3_MMAP_OFFSET:
+			map_size = size-page;
+			map_offset = get_phys ((uint) fb->base);
+			if (map_size > fb->type.fb_size)
+				map_size = fb->type.fb_size;
+			break;
+		default:
+			map_size = 0;
+			break;
+		}
+		if (!map_size){
+			page += PAGE_SIZE;
+			continue;
+		}
+		if (page + map_size > size)
+			map_size = size - page;
+		r = io_remap_page_range (vma->vm_start+page,
+					 map_offset,
+					 map_size, vma->vm_page_prot,
+					 fb->space);
+		if (r) return -EAGAIN;
+		page += map_size;
+	}
+        vma->vm_inode = inode;
+        inode->i_count++;
+        return 0;
+}
+
+__initfunc(void cg3_setup (fbinfo_t *fb, int slot, uint cg3, int cg3_io, struct linux_sbus_device *sbdp))
+{
+	struct cg3_info *cg3info = (struct cg3_info *) &fb->info.cg3;
+
+	if (strstr (sbdp->prom_name, "cgRDI")) {
+		char buffer[40];
+		char *p;
+		int w, h;
+		
+		prom_getstring (sbdp->prom_node, "params", buffer, sizeof(buffer));
+		if (*buffer) {
+			w = simple_strtoul (buffer, &p, 10);
+			if (w && *p == 'x') {
+				h = simple_strtoul (p + 1, &p, 10);
+				if (h && *p == '-') {
+					fb->type.fb_width = w;
+					fb->type.fb_height = h;
+				}
+			}
+		}
+		printk ("cgRDI%d at 0x%8.8x\n", slot, cg3);
+		cg3info->cgrdi = 1;
+	} else {
+		printk ("cgthree%d at 0x%8.8x\n", slot, cg3);
+		cg3info->cgrdi = 0;
+	}
+	
+	/* Fill in parameters we left out */
+	fb->type.fb_cmsize = 256;
+	fb->mmap = cg3_mmap;
+	fb->loadcmap = cg3_loadcmap;
+	fb->postsetup = sun_cg_postsetup;
+	fb->ioctl = 0; /* no special ioctls */
+	fb->reset = 0;
+
+	/* Map the card registers */
+	cg3info->bt = sparc_alloc_io ((void *) cg3+CG3_REGS, 0,
+		 sizeof (struct bt_regs),"cg3_bt", cg3_io, 0);
+	/* cgRDI actually has 32 bytes of regs, but I don't understand
+	   those bitfields yet (guess it is some interrupt stuff etc. */
+	
+	if (!fb->base){
+		fb->base=(uint) sparc_alloc_io ((void*) cg3+CG3_RAM, 0,
+				    fb->type.fb_size, "cg3_ram", cg3_io, 0);
+	}
+}
+
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/fb.h linux/drivers/sbus/char/fb.h
--- v2.1.15/linux/drivers/sbus/char/fb.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/fb.h	Fri Dec 13 11:37:32 1996
@@ -0,0 +1,202 @@
+/* $Id: fb.h,v 1.19 1996/11/13 05:10:23 davem Exp $
+ * fb.h: contains the definitions of the structures that various sun
+ *       frame buffer can use to do console driver stuff.
+ *
+ * (C) 1996 Dave Redman     (djhr@tadpole.co.uk)
+ * (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * (C) 1996 David Miller    (davem@rutgers.edu)
+ * (C) 1996 Peter Zaitcev   (zaitcev@lab.ipmce.su)
+ * (C) 1996 Eddie C. Dost   (ecd@skynet.be)
+ * (C) 1996 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
+ */
+
+#ifndef __SPARC_FB_H_
+#define __SPARC_FB_H_
+
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+
+#define FRAME_BUFFERS    8
+#define CHAR_WIDTH	 8
+#define CHAR_HEIGHT	 16
+
+/* Change this if we run into problems if the kernel want's to free or
+ * use our frame buffer pages, never seen it though.
+ */
+#define FB_MMAP_VM_FLAGS (VM_SHM| VM_LOCKED)
+
+#undef color
+
+/* cursor status, kernel tracked copy */
+struct cg_cursor {
+        short   enable;	        /* cursor is enabled */
+        struct  fbcurpos cpos;	/* position */
+        struct  fbcurpos chot;	/* hot-spot */
+        struct  fbcurpos size;	/* size of mask & image fields */
+        struct	fbcurpos hwsize; /* hw max size */
+        int     bits[2][32];	/* space for mask & image bits */
+	char    color [6];	/* cursor colors */
+};
+
+struct cg6_info {
+	struct bt_regs *bt;	/* color control */
+	struct cg6_fbc *fbc;
+	unsigned int   *fhc;
+	struct cg6_tec *tec;
+	struct cg6_thc *thc;
+	void           *dhc;
+	unsigned char  *rom;
+};
+
+struct tcx_info {
+	struct bt_regs *bt;	/* color control */
+	struct tcx_tec *tec;
+	struct tcx_thc *thc;
+	void *tcx_cplane;
+	int tcx_sizes[13];
+	long tcx_offsets[13];
+	int lowdepth;
+};
+
+struct leo_info {
+	struct leo_cursor *cursor;
+	struct leo_lc_ss0_krn *lc_ss0_krn;
+	struct leo_lc_ss0_usr *lc_ss0_usr;
+	struct leo_lc_ss1_krn *lc_ss1_krn;
+	struct leo_lc_ss1_usr *lc_ss1_usr;
+	struct leo_ld_ss0 *ld_ss0;
+	struct leo_ld_ss1 *ld_ss1;
+	struct leo_ld_gbl *ld_gbl;
+	struct leo_lx_krn *lx_krn;
+	u32	*cluts[3];
+	u8	*xlut;
+	unsigned long offset;
+};
+
+struct bwtwo_info {
+        struct bwtwo_regs *regs;
+};
+
+struct cg3_info {
+	struct bt_regs *bt;	/* brooktree (color) registers */
+	int cgrdi;		/* 1 if this is a cgRDI */
+};
+
+struct cg14_info {
+    struct cg14_regs   *regs;
+    struct cg14_cursor *cursor_regs;
+    struct cg14_dac    *dac;
+    struct cg14_xlut   *xlut;
+    struct cg14_clut   *clut;
+    int    ramsize;
+    int    video_mode;
+};
+
+typedef union
+{
+	unsigned int	bt[8];
+	unsigned char	ibm[8];
+} dacptr;
+    
+struct weitek_info
+{
+	int		p9000;		/* p9000? or p9100 */
+	dacptr		*dac;		/* dac structures */
+	unsigned int	fbsize;		/* size of frame buffer */
+};
+
+/* Array holding the information for the frame buffers */
+typedef struct fbinfo {
+	union {
+		struct bwtwo_info bwtwo;
+		struct cg3_info   cg3;
+		struct cg6_info   cg6;
+		struct cg14_info  cg14;
+		struct tcx_info   tcx;
+		struct leo_info	  leo;
+	} info;		        /* per frame information */
+	int    space;           /* I/O space this card resides in */
+	int    blanked;		/* true if video blanked */
+	int    open;		/* is this fb open? */
+	int    mmaped;		/* has this fb been mmapped? */
+	int    vtconsole;	/* virtual console where it is opened */
+	long   base;		/* frame buffer base    */
+	struct fbtype type;	/* frame buffer type    */
+	int    real_type;	/* real frame buffer FBTYPE* */
+	int    emulations[4];   /* possible emulations (-1 N/A) */
+	int    prom_node;	/* node of the device in prom tree */
+	int    base_depth;	/* depth of fb->base piece */
+	struct cg_cursor cursor;	/* kernel state of hw cursor */
+	int    (*mmap)(struct inode *, struct file *, struct vm_area_struct *,
+		       long fb_base, struct fbinfo *);
+	void   (*loadcmap)(struct fbinfo *fb, int index, int count);
+	void   (*blank)(struct fbinfo *fb);
+	void   (*unblank)(struct fbinfo *fb);
+	int    (*ioctl)(struct inode *, struct file *, uint, unsigned long,
+			struct fbinfo *);
+	void   (*reset)(struct fbinfo *fb);
+	void   (*switch_from_graph)(void);
+	void   (*setcursor)(struct fbinfo *);
+	void   (*setcurshape)(struct fbinfo *);
+	void   (*setcursormap)(struct fbinfo *, unsigned char *, 
+			unsigned char *, unsigned char *);
+	unsigned long (*postsetup)(struct fbinfo *, unsigned long);
+	void	(*blitc)(unsigned short, int, int);
+	void	(*setw)(int, int, unsigned short, int);
+	void	(*cpyw)(int, int, unsigned short *, int);
+	void	(*fill)(int, int, int *);
+	unsigned char *color_map;
+	struct openpromfs_dev proc_entry;
+} fbinfo_t;
+
+#define CM(i, j) [3*(i)+(j)]
+
+extern fbinfo_t *fbinfo;
+extern int fbinfos;
+
+struct {
+	char *name;		/* prom name */
+	int  width, height;	/* prefered w,h match */
+	void (*fbtype)(fbinfo_t *); /* generic device type */
+	/* device specific init routine  */
+	unsigned long (*fbinit)(fbinfo_t *fbinfo, unsigned int addr);
+} fb_entry;
+
+extern int fb_init(void);
+
+extern void (*fb_restore_palette)(fbinfo_t *fbinfo);
+extern void (*fb_hide_cursor)(int cursor_pos);
+extern void (*fb_set_cursor)(int oldpos,  int idx);
+extern void (*fb_clear_screen)( void );
+extern void (*fb_blitc)(unsigned char *, int, unsigned int *, unsigned int);
+extern void (*fb_font_init)(unsigned char *font);
+/* All framebuffers are likely to require this info */
+
+/* Screen dimensions and color depth. */
+extern int con_depth, con_width;
+extern int con_height, con_linebytes;
+extern int ints_per_line;
+
+/* used in the mmap routines */
+extern unsigned int get_phys (unsigned int addr);
+extern int get_iospace (unsigned int addr);
+extern void render_screen(void);
+
+extern void sun_hw_hide_cursor(void);
+extern void sun_hw_set_cursor(int, int);
+extern int sun_hw_scursor(struct fbcursor *,fbinfo_t *);
+extern int sun_hw_cursor_shown;
+extern int sun_prom_console_id;
+
+extern unsigned long sun_cg_postsetup(fbinfo_t *, unsigned long);
+
+#define FB_DEV(x) (MINOR(x) / 32)
+
+extern void cg3_setup (fbinfo_t *, int, uint, int, struct linux_sbus_device *);
+extern void cg6_setup (fbinfo_t *, int, uint, int);
+extern void cg14_setup (fbinfo_t *, int, int, uint, int);
+extern void bwtwo_setup (fbinfo_t *, int, uint, int);
+extern void leo_setup (fbinfo_t *, int, uint, int);
+extern void tcx_setup (fbinfo_t *, int, int, uint, struct linux_sbus_device *);
+
+#endif __SPARC_FB_H_
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/leo.c linux/drivers/sbus/char/leo.c
--- v2.1.15/linux/drivers/sbus/char/leo.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/leo.c	Fri Dec 13 11:37:32 1996
@@ -0,0 +1,698 @@
+/* $Id: leo.c,v 1.9 1996/11/27 20:09:59 jj Exp $
+ * leo.c: SUNW,leo 24/8bit frame buffer driver
+ *
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+ 
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/fbio.h>
+#include <asm/pgtable.h>
+#include <asm/delay.h>
+#include <asm/uaccess.h>
+
+#include "../../char/vt_kern.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+#include "fb.h"
+#include "cg_common.h"
+
+#define LEO_OFF_LC_SS0_KRN	0x00200000
+#define LEO_OFF_LC_SS0_USR	0x00201000
+#define LEO_OFF_LC_SS1_KRN	0x01200000
+#define LEO_OFF_LC_SS1_USR	0x01201000
+#define LEO_OFF_LD_SS0		0x00400000
+#define LEO_OFF_LD_SS1		0x01400000
+#define LEO_OFF_LD_GBL		0x00401000
+#define LEO_OFF_LX_KRN		0x00600000
+#define LEO_OFF_LX_CURSOR	0x00601000
+#define LEO_OFF_SS0		0x00800000
+#define LEO_OFF_SS1		0x01800000
+#define LEO_OFF_UNK		0x00602000
+#define LEO_OFF_UNK2		0x00000000
+
+#define LEO_CUR_ENABLE		0x00000080
+#define LEO_CUR_UPDATE		0x00000030
+#define LEO_CUR_PROGRESS	0x00000006
+#define LEO_CUR_UPDATECMAP	0x00000003
+
+#define LEO_CUR_TYPE_MASK	0x00000000
+#define LEO_CUR_TYPE_IMAGE	0x00000020
+#define LEO_CUR_TYPE_CMAP	0x00000050
+
+struct leo_cursor {
+	u8		xxx0[16];
+	volatile u32	cur_type;
+	volatile u32	cur_misc;
+	volatile u32	cur_cursxy;
+	volatile u32	cur_data;
+};
+
+#define LEO_KRN_TYPE_CLUT0	0x00001000
+#define LEO_KRN_TYPE_CLUT1	0x00001001
+#define LEO_KRN_TYPE_CLUT2	0x00001002
+#define LEO_KRN_TYPE_WID	0x00001003
+#define LEO_KRN_TYPE_UNK	0x00001006
+#define LEO_KRN_TYPE_VIDEO	0x00002003
+#define LEO_KRN_TYPE_CLUTDATA	0x00004000
+#define LEO_KRN_CSR_ENABLE	0x00000008
+#define LEO_KRN_CSR_PROGRESS	0x00000004
+#define LEO_KRN_CSR_UNK		0x00000002
+#define LEO_KRN_CSR_UNK2	0x00000001
+
+struct leo_lx_krn {
+	volatile u32	krn_type;
+	volatile u32	krn_csr;
+	volatile u32	krn_value;
+};
+
+struct leo_lc_ss0_krn {
+	volatile u32 	misc;
+	u8		xxx0[0x800-4];
+	volatile u32	rev;
+};
+
+struct leo_lc_ss0_usr {
+	volatile u32	csr;
+	volatile u32	attrs;
+	volatile u32 	fontc;
+	volatile u32	fontc2;
+	volatile u32	extent;
+	volatile u32	src;
+	u32		xxx1[1];
+	volatile u32	copy;
+	volatile u32	fill;
+};
+
+struct leo_lc_ss1_krn {
+	u8	unknown;
+};
+
+struct leo_lc_ss1_usr {
+	u8	unknown;
+};
+
+struct leo_ld_ss0 {
+	u8		xxx0[0xe00];
+	u32		xxx1[2];
+	volatile u32	unk;
+	u32		xxx2[1];
+	volatile u32	unk2;
+	volatile u32	unk3;
+	u32		xxx3[2];
+	volatile u32	fg;
+	volatile u32	bg;
+	u8		xxx4[0x05c];
+	volatile u32	planemask;
+	volatile u32	rop;
+};
+
+#define LEO_SS1_MISC_ENABLE	0x00000001
+#define LEO_SS1_MISC_STEREO	0x00000002
+struct leo_ld_ss1 {
+	u8		xxx0[0xef4];
+	volatile u32	ss1_misc;
+};
+
+struct leo_ld_gbl {
+	u8	unknown;
+};
+
+static void leo_blitc(unsigned short, int, int);
+static void leo_setw(int, int, unsigned short, int);
+static void leo_cpyw(int, int, unsigned short *, int);
+static void leo_fill(int, int, int *);
+
+static void
+leo_restore_palette (fbinfo_t *fb)
+{
+	fb->info.leo.ld_ss1->ss1_misc &= ~(LEO_SS1_MISC_ENABLE);
+}
+
+/* Ugh: X wants to mmap a bunch of cute stuff at the same time :-( */
+/* So, we just mmap the things that are being asked for */
+static int
+leo_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
+	  long base, fbinfo_t *fb)
+{
+	uint size, page, r, map_size = 0;
+	uint map_offset = 0;
+			     
+	size = vma->vm_end - vma->vm_start;
+        if (vma->vm_offset & ~PAGE_MASK)
+                return -ENXIO;
+
+	/* To stop the swapper from even considering these pages */
+	vma->vm_flags |= FB_MMAP_VM_FLAGS;
+	
+	/* Each page, see which map applies */
+	for (page = 0; page < size; ){
+		switch (vma->vm_offset+page){
+		case LEO_SS0_MAP:
+			map_size = 0x800000;
+			map_offset = get_phys ((uint)fb->base);
+			break;
+		case LEO_LC_SS0_USR_MAP:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.leo.lc_ss0_usr);
+			break;
+		case LEO_LD_SS0_MAP:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.leo.ld_ss0);
+			break;
+		case LEO_LX_CURSOR_MAP:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.leo.cursor);
+			break;
+		case LEO_SS1_MAP:	
+			map_size = 0x800000;
+			map_offset = fb->info.leo.offset + LEO_OFF_SS1;
+			break;
+		case LEO_LC_SS1_USR_MAP:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.leo.lc_ss1_usr);
+			break;
+		case LEO_LD_SS1_MAP:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.leo.ld_ss1);
+			break;
+		case LEO_UNK_MAP:	
+			map_size = PAGE_SIZE;
+			map_offset = fb->info.leo.offset + LEO_OFF_UNK;
+			break;
+		case LEO_LX_KRN_MAP:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.leo.lx_krn);
+			break;
+		case LEO_LC_SS0_KRN_MAP:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.leo.lc_ss0_krn);
+			break;
+		case LEO_LC_SS1_KRN_MAP:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.leo.lc_ss1_krn);
+			break;
+		case LEO_LD_GBL_MAP:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.leo.ld_gbl);
+			break;
+		case LEO_UNK2_MAP:
+			map_size = 0x100000;
+			map_offset = fb->info.leo.offset + LEO_OFF_UNK2;
+			break;
+		}
+		if (!map_size){
+			page += PAGE_SIZE;
+			continue;
+		}
+		if (page + map_size > size)
+			map_size = size - page;
+		r = io_remap_page_range (vma->vm_start+page,
+					 map_offset,
+					 map_size, vma->vm_page_prot,
+					 fb->space);
+		if (r) return -EAGAIN;
+		page += map_size;
+	}
+        vma->vm_inode = inode;
+        inode->i_count++;
+        return 0;
+}
+
+static void
+leo_setcursormap (fbinfo_t *fb, unsigned char *red,
+				 unsigned char *green,
+				 unsigned char *blue)
+{
+	struct leo_cursor *l = fb->info.leo.cursor;
+	int i;
+
+	for (i = 0; (l->cur_misc & LEO_CUR_PROGRESS) && i < 300000; i++)
+		udelay (1); /* Busy wait at most 0.3 sec */
+	if (i == 300000) return; /* Timed out - should we print some message? */
+	l->cur_type = LEO_CUR_TYPE_CMAP;
+	l->cur_data = (red[0] | (green[0]<<8) | (blue[0]<<16));
+	l->cur_data = (red[1] | (green[1]<<8) | (blue[1]<<16));
+	l->cur_misc = LEO_CUR_UPDATECMAP;
+}
+
+/* Load cursor information */
+static void
+leo_setcursor (fbinfo_t *fb)
+{
+	struct cg_cursor *c = &fb->cursor;
+	struct leo_cursor *l = fb->info.leo.cursor;
+
+	l->cur_misc &= ~LEO_CUR_ENABLE;
+	l->cur_cursxy = ((c->cpos.fbx - c->chot.fbx) & 0x7ff)
+			|(((c->cpos.fby - c->chot.fby) & 0x7ff) << 11);
+	l->cur_misc |= LEO_CUR_UPDATE;
+	if (c->enable)
+		l->cur_misc |= LEO_CUR_ENABLE;
+}
+
+/* Set cursor shape */
+static void
+leo_setcurshape (fbinfo_t *fb)
+{
+	int i, j, k;
+	u32 m, n, mask;
+	struct leo_cursor *l = fb->info.leo.cursor;
+
+	l->cur_misc &= ~LEO_CUR_ENABLE;
+	for (k = 0; k < 2; k ++) {
+		l->cur_type = (k * LEO_CUR_TYPE_IMAGE); /* LEO_CUR_TYPE_MASK is 0 */
+		for (i = 0; i < 32; i++) {
+			mask = 0;
+			m = fb->cursor.bits[k][i];
+			/* mask = m with reversed bit order */
+			for (j = 0, n = 1; j < 32; j++, n <<= 1)
+				if (m & n)
+					mask |= (0x80000000 >> j);
+			l->cur_data = mask;
+		}
+	}
+	l->cur_misc |= LEO_CUR_ENABLE;
+}
+
+static void
+leo_blank (fbinfo_t *fb)
+{
+	fb->info.leo.lx_krn->krn_type = LEO_KRN_TYPE_VIDEO;
+	fb->info.leo.lx_krn->krn_csr &= ~LEO_KRN_CSR_ENABLE;
+}
+
+static void
+leo_unblank (fbinfo_t *fb)
+{
+	fb->info.leo.lx_krn->krn_type = LEO_KRN_TYPE_VIDEO;
+	if (!(fb->info.leo.lx_krn->krn_csr & LEO_KRN_CSR_ENABLE))
+		fb->info.leo.lx_krn->krn_csr |= LEO_KRN_CSR_ENABLE;
+}
+
+static int leo_wait (struct leo_lx_krn *lx_krn)
+{
+	int i;
+	for (i = 0; (lx_krn->krn_csr & LEO_KRN_CSR_PROGRESS) && i < 300000; i++)
+		udelay (1); /* Busy wait at most 0.3 sec */
+	if (i == 300000) return -EFAULT; /* Timed out - should we print some message? */
+	return 0;
+}
+
+static int
+leo_wid_get (fbinfo_t *fb, struct fb_wid_list *wl)
+{
+	struct leo_lx_krn *lx_krn = fb->info.leo.lx_krn;
+	struct fb_wid_item *wi;
+	int i, j;
+	u32 l;
+	
+	lx_krn->krn_type = LEO_KRN_TYPE_WID;
+	i = leo_wait (lx_krn);
+	if (i) return i;
+	lx_krn->krn_csr &= ~LEO_KRN_CSR_UNK2;
+	lx_krn->krn_csr |= LEO_KRN_CSR_UNK;
+	lx_krn->krn_type = LEO_KRN_TYPE_WID;
+	i = leo_wait (lx_krn);
+	if (i) return i;
+	for (i = 0, wi = wl->wl_list; i < wl->wl_count; i++, wi++) {
+		switch (wi->wi_type) {
+		case FB_WID_DBL_8: j = (wi->wi_index & 0xf) + 0x40; break;
+		case FB_WID_DBL_24: j = wi->wi_index & 0x3f; break;
+		default: return -EINVAL;
+		}
+		wi->wi_attrs = 0xffff;
+		lx_krn->krn_type = 0x5800 + j;
+		l = lx_krn->krn_value;
+		for (j = 0; j < 32; j++)
+			wi->wi_values [j] = l;
+	}
+	return 0;
+}
+
+static int
+leo_wid_put (fbinfo_t *fb, struct fb_wid_list *wl)
+{
+	struct leo_lx_krn *lx_krn = fb->info.leo.lx_krn;
+	struct fb_wid_item *wi;
+	int i, j;
+	
+	lx_krn->krn_type = LEO_KRN_TYPE_WID;
+	i = leo_wait (lx_krn);
+	if (i) return i;
+	for (i = 0, wi = wl->wl_list; i < wl->wl_count; i++, wi++) {
+		switch (wi->wi_type) {
+		case FB_WID_DBL_8: j = (wi->wi_index & 0xf) + 0x40; break;
+		case FB_WID_DBL_24: j = wi->wi_index & 0x3f; break;
+		default: return -EINVAL;
+		}
+		lx_krn->krn_type = 0x5800 + j;
+		lx_krn->krn_value = wi->wi_values[0];
+	}
+	return 0;
+}
+
+static int leo_clutstore (fbinfo_t *fb, int clutid)
+{
+	int i;
+	u32 *clut = fb->info.leo.cluts [clutid];
+	struct leo_lx_krn *lx_krn = fb->info.leo.lx_krn;
+	
+	lx_krn->krn_type = LEO_KRN_TYPE_CLUT0 + clutid;
+	i = leo_wait (lx_krn);
+	if (i) return i;
+	lx_krn->krn_type = LEO_KRN_TYPE_CLUTDATA;
+	for (i = 0; i < 256; i++)
+		lx_krn->krn_value = *clut++; /* Throw colors there :)) */
+	lx_krn->krn_type = LEO_KRN_TYPE_CLUT0 + clutid;
+	lx_krn->krn_csr |= (LEO_KRN_CSR_UNK|LEO_KRN_CSR_UNK2);
+	return 0;
+}
+
+static int leo_clutpost (fbinfo_t *fb, struct leo_clut *lc)
+{
+	int xlate = 0, i;
+	u32 *clut;
+	u8 *xlut = fb->info.leo.xlut;
+	
+	switch (lc->clutid) {
+	case 0:
+	case 1:
+	case 2: break;
+	case 3: return -EINVAL; /* gamma clut - not yet implemented */
+	case 4: return -EINVAL; /* degamma clut - not yet implemented */
+	default: return -EINVAL;
+	}
+	clut = fb->info.leo.cluts [lc->clutid] + lc->offset;
+	for (i = 0; i < lc->count; i++)
+		*clut++ = xlate ? 
+		((xlut[(u8)(lc->red[i])])|(xlut[(u8)(lc->green[i])]<<8)|(xlut[(u8)(lc->blue[i])]<<16)) : 
+		(((u8)(lc->red[i]))|(((u8)(lc->green[i]))<<8)|(((u8)(lc->blue[i]))<<16));
+	return leo_clutstore (fb, lc->clutid);
+}
+
+static int leo_clutread (fbinfo_t *fb, struct leo_clut *lc)
+{
+	int i;
+	u32 u;
+	struct leo_lx_krn *lx_krn = fb->info.leo.lx_krn;
+
+	if (lc->clutid >= 3) return -EINVAL;	
+	lx_krn->krn_type = LEO_KRN_TYPE_CLUT0 + lc->clutid;
+	i = leo_wait (lx_krn);
+	if (i) return i;
+	lx_krn->krn_csr &= ~LEO_KRN_CSR_UNK2;
+	lx_krn->krn_csr |= LEO_KRN_CSR_UNK;
+	i = leo_wait (lx_krn);
+	if (i) return i;
+	lx_krn->krn_type = LEO_KRN_TYPE_CLUTDATA;
+	for (i = 0; i < lc->offset; i++)
+		u = lx_krn->krn_value;
+	for (i = 0; i < lc->count; i++) {
+		u = lx_krn->krn_value;
+		lc->red [i] = u;
+		lc->green [i] = (u >> 8);
+		lc->blue [i] = (u >> 16);
+	}
+	return 0;
+}
+
+static void
+leo_loadcmap (fbinfo_t *fb, int index, int count)
+{
+	u32 *clut = ((u32 *)fb->info.leo.cluts [0]) + index;
+	int i;
+	
+	for (i = index; count--; i++)
+		*clut++ = ((fb->color_map CM(i,0))) |
+			  ((fb->color_map CM(i,1)) << 8) |
+			  ((fb->color_map CM(i,2)) << 16);
+	leo_clutstore (fb, 0);
+}
+
+/* Handle leo-specific ioctls */
+static int
+leo_ioctl (struct inode *inode, struct file *file, unsigned cmd, unsigned long arg, fbinfo_t *fb)
+{
+	int i;
+	
+	switch (cmd) {
+	case FBIO_WID_GET:
+		i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct fb_wid_list));
+		if (i) return i;
+		if (((struct fb_wid_list *)arg)->wl_count != 1 ||
+		    !((struct fb_wid_list *)arg)->wl_list) return -EINVAL;
+		i = verify_area (VERIFY_WRITE, (void *)(((struct fb_wid_list *)arg)->wl_list), 
+			((struct fb_wid_list *)arg)->wl_count * sizeof (struct fb_wid_item));
+		if (i) return i;
+		return leo_wid_get (fb, (struct fb_wid_list *)arg);
+	case FBIO_WID_PUT:
+		i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct fb_wid_list));
+		if (i) return i;
+		if (((struct fb_wid_list *)arg)->wl_count != 1 ||
+		    !((struct fb_wid_list *)arg)->wl_list) return -EINVAL;
+		i = verify_area (VERIFY_WRITE, (void *)(((struct fb_wid_list *)arg)->wl_list), 
+			((struct fb_wid_list *)arg)->wl_count * sizeof (struct fb_wid_item));
+		if (i) return i;
+		return leo_wid_put (fb, (struct fb_wid_list *)arg);
+	case LEO_CLUTPOST:
+		i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct leo_clut));
+		if (i) return i;
+		i = ((struct leo_clut *)arg)->offset + ((struct leo_clut *)arg)->count;
+		if (i <= 0 || i > 256) return -EINVAL;
+		i = verify_area (VERIFY_READ, ((struct leo_clut *)arg)->red, ((struct leo_clut *)arg)->count);
+		if (i) return i;
+		i = verify_area (VERIFY_READ, ((struct leo_clut *)arg)->green, ((struct leo_clut *)arg)->count);
+		if (i) return i;
+		i = verify_area (VERIFY_READ, ((struct leo_clut *)arg)->blue, ((struct leo_clut *)arg)->count);
+		if (i) return i;
+		return leo_clutpost (fb, (struct leo_clut *)arg);
+	case LEO_CLUTREAD:
+		i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct leo_clut));
+		if (i) return i;
+		i = ((struct leo_clut *)arg)->offset + ((struct leo_clut *)arg)->count;
+		if (i <= 0 || i > 256) return -EINVAL;
+		i = verify_area (VERIFY_WRITE, ((struct leo_clut *)arg)->red, ((struct leo_clut *)arg)->count);
+		if (i) return i;
+		i = verify_area (VERIFY_WRITE, ((struct leo_clut *)arg)->green, ((struct leo_clut *)arg)->count);
+		if (i) return i;
+		i = verify_area (VERIFY_WRITE, ((struct leo_clut *)arg)->blue, ((struct leo_clut *)arg)->count);
+		if (i) return i;
+		return leo_clutread (fb, (struct leo_clut *)arg);
+		
+	default:
+		return -ENOSYS;
+	}
+}
+
+static void
+leo_reset (fbinfo_t *fb)
+{
+	if (fb->setcursor)
+		sun_hw_hide_cursor ();
+}
+
+
+__initfunc(static unsigned long leo_postsetup (fbinfo_t *fb, unsigned long memory_start))
+{
+	fb->info.leo.cluts[0] = (u32 *)(memory_start);
+	fb->info.leo.cluts[1] = (u32 *)(memory_start+256*4);
+	fb->info.leo.cluts[2] = (u32 *)(memory_start+256*4*2);
+	fb->info.leo.xlut = (u8 *)(memory_start+256*4*3);
+	fb->color_map = (u8 *)(memory_start+256*4*3+256);
+	return memory_start + (256*4*3) + 256 + 256*3;
+}
+
+__initfunc(void leo_setup (fbinfo_t *fb, int slot, uint leo, int leo_io))
+{
+	struct leo_info *leoinfo;
+	int i;
+	struct fb_wid_item wi;
+	struct fb_wid_list wl;
+	
+	printk ("leo%d at 0x%8.8x ", slot, (uint) leo);
+	
+	/* Fill in parameters we left out */
+	fb->type.fb_size = 0x800000; /* 8MB */
+	fb->type.fb_cmsize = 256;
+	fb->mmap = leo_mmap;
+	fb->loadcmap = leo_loadcmap;
+	fb->postsetup = leo_postsetup;
+	fb->ioctl = (void *)leo_ioctl;
+	fb->reset = leo_reset;
+	fb->blank = leo_blank;
+	fb->unblank = leo_unblank;
+	fb->setcursor = leo_setcursor;
+	fb->setcursormap = leo_setcursormap;
+	fb->setcurshape = leo_setcurshape;
+	fb->blitc = leo_blitc;
+	fb->setw = leo_setw;
+	fb->cpyw = leo_cpyw;
+	fb->fill = leo_fill;
+	fb->base_depth = 0;
+	
+	leoinfo = (struct leo_info *) &fb->info.leo;
+	
+	memset (leoinfo, 0, sizeof(struct leo_info));
+
+	leoinfo->offset = leo;
+	/* Map the hardware registers */
+	leoinfo->lc_ss0_krn = sparc_alloc_io ((void *) leo + LEO_OFF_LC_SS0_KRN, 0,
+		 PAGE_SIZE,"leo_lc_ss0_krn", fb->space, 0);
+	leoinfo->lc_ss0_usr = sparc_alloc_io ((void *) leo + LEO_OFF_LC_SS0_USR, 0,
+		 PAGE_SIZE,"leo_lc_ss0_usr", fb->space, 0);
+	leoinfo->lc_ss1_krn = sparc_alloc_io ((void *) leo + LEO_OFF_LC_SS1_KRN, 0,
+		 PAGE_SIZE,"leo_lc_ss1_krn", fb->space, 0);
+	leoinfo->lc_ss1_usr = sparc_alloc_io ((void *) leo + LEO_OFF_LC_SS1_USR, 0,
+		 PAGE_SIZE,"leo_lc_ss1_usr", fb->space, 0);
+	leoinfo->ld_ss0 = sparc_alloc_io ((void *) leo + LEO_OFF_LD_SS0, 0,
+		 PAGE_SIZE,"leo_ld_ss0", fb->space, 0);
+	leoinfo->ld_ss1 = sparc_alloc_io ((void *) leo + LEO_OFF_LD_SS1, 0,
+		 PAGE_SIZE,"leo_ld_ss1", fb->space, 0);
+	leoinfo->ld_gbl = sparc_alloc_io ((void *) leo + LEO_OFF_LD_GBL, 0,
+		 PAGE_SIZE,"leo_ld_gbl", fb->space, 0);
+	leoinfo->lx_krn = sparc_alloc_io ((void *) leo + LEO_OFF_LX_KRN, 0,
+		 PAGE_SIZE,"leo_lx_krn", fb->space, 0);
+	leoinfo->cursor = sparc_alloc_io ((void *) leo + LEO_OFF_LX_CURSOR, 0,
+		 sizeof(struct leo_cursor),"leo_lx_crsr", fb->space, 0);
+	fb->base = (long)sparc_alloc_io ((void *) leo + LEO_OFF_SS0, 0,
+		 0x800000,"leo_ss0", fb->space, 0);
+	
+	leoinfo->ld_ss0->unk = 0xffff;
+	leoinfo->ld_ss0->unk2 = 0;
+	leoinfo->ld_ss0->unk3 = (fb->type.fb_width - 1)	| ((fb->type.fb_height - 1) << 16);
+	wl.wl_count = 1;
+	wl.wl_list = &wi;
+	wi.wi_type = FB_WID_DBL_8;
+	wi.wi_index = 0;
+	wi.wi_values [0] = 0x2c0;
+	leo_wid_put (fb, &wl);
+	wi.wi_index = 1;
+	wi.wi_values [0] = 0x30;
+	leo_wid_put (fb, &wl);
+	wi.wi_index = 2;
+	wi.wi_values [0] = 0x20;
+	leo_wid_put (fb, &wl);
+	
+	leoinfo->ld_ss1->ss1_misc |= LEO_SS1_MISC_ENABLE;
+	
+	leoinfo->ld_ss0->fg = 0x30703;
+	leoinfo->ld_ss0->planemask = 0xff000000;
+	leoinfo->ld_ss0->rop = 0xd0840;
+	leoinfo->lc_ss0_usr->extent = (fb->type.fb_width-1) | ((fb->type.fb_height-1) << 11);
+	i = leoinfo->lc_ss0_usr->attrs;
+	leoinfo->lc_ss0_usr->fill = (0) | ((0) << 11) | ((i & 3) << 29) | ((i & 8) ? 0x80000000 : 0);
+	do {
+		i = leoinfo->lc_ss0_usr->csr;
+	} while (i & 0x20000000);
+	
+	if (slot == sun_prom_console_id)
+		fb_restore_palette = leo_restore_palette;
+	
+	printk("Cmd Rev %d\n",
+		(leoinfo->lc_ss0_krn->rev >> 28));
+	
+	/* Reset the leo */
+	leo_reset(fb);
+	
+	if (!slot)	
+	/* Enable Video */
+		leo_unblank (fb);
+	else if (slot != sun_prom_console_id)
+		leo_blank (fb);
+}
+
+extern unsigned char vga_font [];
+
+#define GX_BLITC_START(attr,x,y,count) \
+	{ \
+		register struct leo_lc_ss0_usr *us = fbinfo[0].info.leo.lc_ss0_usr; \
+		register struct leo_ld_ss0 *ss = fbinfo[0].info.leo.ld_ss0; \
+		register u32 i; \
+		do { \
+			i = us->csr; \
+		} while (i & 0x20000000); \
+		ss->fg = (attr >> 4)<<24; \
+		ss->planemask = 0xff000000; \
+		ss->rop = 0x310040; \
+		us->extent = (count*8-1) | (15<<11); \
+		i = us->attrs; \
+		us->fill = (x) | ((y) << 11) | ((i & 3) << 29) | ((i & 8) ? 0x80000000 : 0); \
+		do { \
+			i = us->csr; \
+		} while (i & 0x20000000); \
+		ss->fg = (attr & 0xf)<<24; \
+		us->fontc2 = ~(0); \
+		us->attrs = 4; \
+		us->fontc = ~(0); \
+		us->extent = ((u16)x) | (y << 16); \
+		us->src = ((u16)(x + (count << 3))) | ((y + 16) << 16);
+#define GX_BLITC_END \
+	}
+	
+static void leo_blitc(unsigned short charattr, int xoff, int yoff)
+{
+	unsigned char attrib = charattr >> 8;
+	unsigned char *p = &vga_font[((unsigned char)charattr) << 4];
+	u32 *u = ((u32 *)fbinfo[0].base) + (yoff << 11) + xoff;
+	GX_BLITC_START(attrib, xoff, yoff, 1)
+	for (i = 0; i < CHAR_HEIGHT; i++, u += 2048)
+		*u = (*p++) << 24;
+	GX_BLITC_END
+}
+
+static void leo_setw(int xoff, int yoff, unsigned short c, int count)
+{
+	unsigned char attrib = c >> 8;
+	unsigned char *p = &vga_font[((unsigned char)c) << 4];
+	register unsigned char *q;
+	u32 *u = ((u32 *)fbinfo[0].base) + (yoff << 11) + xoff;
+	GX_BLITC_START(attrib, xoff, yoff, count)
+	while (count-- > 0) {
+		q = p;
+		for (i = 0; i < CHAR_HEIGHT; i++, u += 2048)
+			*u = (*q++) << 24;
+		u += 8 - (CHAR_HEIGHT * 2048);
+	}
+	GX_BLITC_END
+}
+
+static void leo_cpyw(int xoff, int yoff, unsigned short *p, int count)
+{
+	unsigned char attrib = *p >> 8;
+	register unsigned char *q;
+	u32 *u = ((u32 *)fbinfo[0].base) + (yoff << 11) + xoff;
+	GX_BLITC_START(attrib, xoff, yoff, count)
+	while (count-- > 0) {
+		q = &vga_font[((unsigned char)*p++) << 4];
+		for (i = 0; i < CHAR_HEIGHT; i++, u += 2048)
+			*u = (*q++) << 24;
+		u += 8 - (CHAR_HEIGHT * 2048);
+	}
+	GX_BLITC_END
+}
+
+static void leo_fill(int attrib, int count, int *boxes)
+{
+	register struct leo_lc_ss0_usr *us = fbinfo[0].info.leo.lc_ss0_usr;
+	register struct leo_ld_ss0 *ss = fbinfo[0].info.leo.ld_ss0;
+	register u32 i;
+	do {
+		i = us->csr;
+	} while (i & 0x20000000);
+	ss->unk = 0xffff;
+	ss->unk2 = 0;
+	ss->unk3 = (fbinfo[0].type.fb_width - 1) | ((fbinfo[0].type.fb_height - 1) << 16);
+	ss->fg = ((attrib & 0xf)<<24) | 0x030703;
+	ss->planemask = 0xff000000;
+	ss->rop = 0xd0840;
+	while (count-- > 0) {
+		us->extent = ((boxes[2] - boxes[0] - 1) & 0x7ff) | (((boxes[3] - boxes[1] - 1) & 0x7ff) << 11);
+		i = us->attrs;
+		us->fill = (boxes[0] & 0x7ff) | ((boxes[1] & 0x7ff) << 11) | ((i & 3) << 29) | ((i & 8) ? 0x80000000 : 0);
+	}
+}
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/linux_logo.h linux/drivers/sbus/char/linux_logo.h
--- v2.1.15/linux/drivers/sbus/char/linux_logo.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/linux_logo.h	Fri Dec 13 11:37:32 1996
@@ -0,0 +1,1037 @@
+/* This is a linux logo to be displayed on boot.
+ *
+ * You can put anything here, but:
+ * LINUX_LOGO_COLORS has to be less than 224
+ * image size has to be 80x80
+ * values have to start from 0x20
+ * (i.e. RGB(linux_logo_red[0],
+ *	     linux_logo_green[0],
+ *	     linux_logo_blue[0]) is color 0x20)
+ * BW image has to be 80x80 as well, with MS bit
+ * on the left
+ * Serial_console ascii image can be any size,
+ * but should contain %s to display the version
+ */
+ 
+#include <linux/init.h>
+
+#define LINUX_LOGO_COLORS 221
+
+unsigned char linux_logo_red[] __initdata = {
+  0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xE7, 0xE5, 0xE3,
+  0xCA, 0xD4, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xE5,
+  0xF1, 0xED, 0xEE, 0xE6, 0xC6, 0xDA, 0xDD, 0xE5,
+  0xD9, 0xC6, 0xE3, 0xD0, 0xC6, 0xBA, 0xB0, 0xB6,
+  0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xB0, 0xAD,
+  0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA0, 0x9D,
+  0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x99, 0x9A, 0x99,
+  0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
+  0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0x0D, 0x03,
+  0x66, 0x44, 0x24, 0x08, 0xD6, 0xE6, 0xE9, 0xE6,
+  0xE7, 0xCA, 0xDC, 0xDB, 0xD5, 0xD0, 0xC9, 0xE2,
+  0xD5, 0xC6, 0xC4, 0xB3, 0xB2, 0xB9, 0xA9, 0x9A,
+  0xB2, 0x9D, 0xE8, 0xEC, 0xF5, 0xF5, 0xF4, 0xF4,
+  0xEC, 0xEE, 0xF0, 0xF5, 0xE0, 0xD6, 0xC5, 0xC2,
+  0xD9, 0xD5, 0xD8, 0xD6, 0xF6, 0xF4, 0xED, 0xEC,
+  0xEB, 0xF1, 0xF6, 0xF5, 0xF5, 0xEE, 0xEF, 0xEC,
+  0xE7, 0xE3, 0xE6, 0xD6, 0xDD, 0xC3, 0xD6, 0xD7,
+  0xCD, 0xCA, 0xC3, 0xAC, 0x95, 0x99, 0xB7, 0xA3,
+  0x8B, 0x88, 0x95, 0x8A, 0x94, 0xD2, 0xCC, 0xC4,
+  0xA8, 0x8E, 0x8F, 0xAE, 0xB8, 0xAC, 0xB6, 0xB4,
+  0xAD, 0xA5, 0xA0, 0x9B, 0x8B, 0xA3, 0x94, 0x87,
+  0x85, 0x89, 0x53, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
+  0x76, 0x71, 0x73, 0x6E, 0x6B, 0x67, 0x65, 0x62,
+  0x4B, 0x5B, 0x5F, 0x53, 0x56, 0x52, 0x4F, 0x46,
+  0x42, 0x0F, 0x75, 0x78, 0x7D, 0x72, 0x5F, 0x6E,
+  0x7A, 0x75, 0x6A, 0x58, 0x48, 0x4F, 0x00, 0x2B,
+  0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x3B, 0x11,
+  0x1D, 0x14, 0x06, 0x02, 0x00
+};
+
+unsigned char linux_logo_green[] __initdata = {
+  0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xE7, 0xE5, 0xE3,
+  0xCA, 0xD4, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xD3,
+  0xDA, 0xD4, 0xD7, 0xCC, 0xC1, 0xCC, 0xCB, 0xC9,
+  0xC5, 0xBC, 0xBC, 0xBB, 0xB7, 0xA5, 0xB0, 0xB6,
+  0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xAD, 0xAD,
+  0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA0, 0x95,
+  0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x99, 0x9A, 0x99,
+  0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
+  0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0x08, 0x02,
+  0x53, 0x2E, 0x19, 0x06, 0xC6, 0xC8, 0xCF, 0xBD,
+  0xB3, 0xB6, 0xB4, 0xAB, 0xA5, 0xA3, 0x9B, 0xB6,
+  0xA7, 0x99, 0x92, 0xA4, 0x9E, 0x9D, 0x98, 0x8C,
+  0x8A, 0x86, 0xCD, 0xCC, 0xC9, 0xD7, 0xCA, 0xC4,
+  0xCA, 0xC3, 0xC7, 0xC3, 0xC8, 0xB4, 0x91, 0x8E,
+  0x8A, 0x82, 0x87, 0x85, 0xBD, 0xBF, 0xB6, 0xBC,
+  0xAE, 0xB7, 0xBC, 0xB8, 0xBF, 0xB6, 0xBC, 0xB5,
+  0xAB, 0xA6, 0xAD, 0xB2, 0xA5, 0x87, 0x9C, 0x96,
+  0x95, 0x8E, 0x87, 0x8F, 0x86, 0x86, 0x8E, 0x80,
+  0x7A, 0x70, 0x7B, 0x78, 0x78, 0x7F, 0x77, 0x6F,
+  0x70, 0x76, 0x59, 0x77, 0x68, 0x64, 0x7B, 0x7C,
+  0x75, 0x6D, 0x77, 0x69, 0x65, 0x5F, 0x5B, 0x54,
+  0x4F, 0x5B, 0x39, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
+  0x76, 0x71, 0x73, 0x6E, 0x6B, 0x67, 0x65, 0x62,
+  0x4B, 0x5B, 0x5F, 0x53, 0x56, 0x52, 0x4F, 0x46,
+  0x42, 0x0B, 0x69, 0x66, 0x64, 0x57, 0x4A, 0x4E,
+  0x55, 0x4B, 0x46, 0x3B, 0x30, 0x33, 0x00, 0x2B,
+  0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x29, 0x0D,
+  0x1D, 0x14, 0x06, 0x02, 0x00
+};
+
+unsigned char linux_logo_blue[] __initdata = {
+  0xF3, 0xF6, 0xF8, 0xF7, 0xEF, 0xEE, 0xE5, 0xDE,
+  0xD7, 0xD3, 0xDD, 0xC8, 0xC7, 0xC4, 0xC2, 0xB5,
+  0xB0, 0xA6, 0xAC, 0x9B, 0xB5, 0xB5, 0xAE, 0x84,
+  0x90, 0xA9, 0x81, 0x8D, 0x96, 0x86, 0xB0, 0xB6,
+  0xBB, 0xBE, 0xB9, 0xB8, 0xB3, 0xB2, 0xA7, 0xAD,
+  0xAC, 0xA9, 0xA8, 0xA6, 0xA4, 0xA1, 0xA5, 0x87,
+  0xA0, 0x9F, 0x9E, 0x9C, 0x9B, 0x9A, 0x9A, 0x99,
+  0x98, 0x95, 0x96, 0x94, 0x93, 0x92, 0x8F, 0x8D,
+  0x8C, 0x8A, 0x87, 0x86, 0x83, 0x81, 0xC8, 0xD7,
+  0x9B, 0x8E, 0x8C, 0xB2, 0x77, 0x77, 0x4E, 0x77,
+  0x69, 0x71, 0x78, 0x6B, 0x65, 0x66, 0x64, 0x59,
+  0x5C, 0x5A, 0x48, 0x72, 0x7B, 0x6B, 0x67, 0x6E,
+  0x42, 0x5B, 0x29, 0x36, 0x25, 0x10, 0x17, 0x14,
+  0x19, 0x16, 0x13, 0x0E, 0x08, 0x2E, 0x2E, 0x3D,
+  0x24, 0x24, 0x24, 0x24, 0x13, 0x12, 0x14, 0x14,
+  0x0E, 0x08, 0x0D, 0x0F, 0x08, 0x0D, 0x0E, 0x08,
+  0x08, 0x0C, 0x06, 0x06, 0x07, 0x16, 0x07, 0x0E,
+  0x08, 0x0A, 0x07, 0x0D, 0x2D, 0x3E, 0x09, 0x4E,
+  0x68, 0x52, 0x56, 0x58, 0x4B, 0x22, 0x20, 0x20,
+  0x27, 0x39, 0x28, 0x19, 0x1E, 0x1E, 0x08, 0x06,
+  0x07, 0x09, 0x08, 0x08, 0x05, 0x1D, 0x1F, 0x17,
+  0x18, 0x06, 0x79, 0x80, 0x7D, 0x7C, 0x7A, 0x78,
+  0x76, 0x71, 0x73, 0x6E, 0x6B, 0x68, 0x65, 0x62,
+  0x4B, 0x5B, 0x5F, 0x55, 0x56, 0x52, 0x4F, 0x46,
+  0x42, 0x5A, 0x14, 0x23, 0x3D, 0x2B, 0x21, 0x14,
+  0x06, 0x04, 0x03, 0x07, 0x09, 0x13, 0x2A, 0x3A,
+  0x37, 0x3E, 0x32, 0x33, 0x25, 0x2C, 0x07, 0x09,
+  0x1D, 0x14, 0x06, 0x02, 0x00
+};
+
+unsigned char linux_logo[] __initdata = {
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x57,
+  0x58, 0x58, 0x59, 0x5C, 0x5D, 0x5F, 0x60, 0x61,
+  0x62, 0x61, 0x61, 0x62, 0x62, 0x62, 0x63, 0x63,
+  0x61, 0x61, 0x61, 0x61, 0x61, 0x60, 0x5E, 0x5E,
+  0x5E, 0x5D, 0x5D, 0x5C, 0x5D, 0x5B, 0x58, 0x58,
+  0x58, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x58,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x57,
+  0x54, 0x56, 0x57, 0x67, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x67, 0x4C,
+  0x4A, 0x49, 0x4A, 0x49, 0x4A, 0x49, 0x49, 0x4A,
+  0x4A, 0x4B, 0x4B, 0x4B, 0x4C, 0x50, 0x51, 0x52,
+  0x54, 0x54, 0x56, 0x57, 0x57, 0x57, 0x57, 0x58,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x58, 0x56, 0x56, 0x53,
+  0x52, 0x53, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xFB,
+  0x4B, 0x4B, 0x4B, 0x4A, 0x49, 0x4A, 0x4A, 0x49,
+  0x49, 0x49, 0x48, 0x49, 0x49, 0x4A, 0x4A, 0x4B,
+  0x4C, 0x4D, 0x52, 0x54, 0x56, 0x55, 0x57, 0x58,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50,
+  0x50, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xF8, 0xF0, 0xF4, 0xFB,
+  0xFC, 0x67, 0x53, 0x50, 0x4D, 0x4C, 0x4C, 0x4C,
+  0x4B, 0x4A, 0x4A, 0x48, 0x49, 0x48, 0x48, 0x49,
+  0x49, 0x49, 0x4B, 0x4C, 0x50, 0x52, 0x53, 0x56,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x55, 0x54, 0x53, 0x51, 0x51, 0x50, 0x4C, 0x4D,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0xD2, 0xD7, 0xF5,
+  0xFC, 0xFC, 0x5D, 0x5D, 0x5C, 0x5C, 0x59, 0x58,
+  0x58, 0x56, 0x52, 0x4C, 0x4B, 0x4A, 0x4A, 0x48,
+  0x48, 0x48, 0x48, 0x48, 0x49, 0x4B, 0x4D, 0x51,
+  0x54, 0x56, 0x58, 0x57, 0x57, 0x58, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x57, 0x55, 0x54,
+  0x53, 0x52, 0x51, 0x4D, 0x4D, 0x4D, 0x50, 0x50,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0x64, 0xD9, 0xF5,
+  0xF9, 0xFC, 0xFC, 0x64, 0x63, 0x62, 0x61, 0x61,
+  0x61, 0x60, 0x5E, 0x5B, 0x5A, 0x54, 0x52, 0x4C,
+  0x4B, 0x49, 0x49, 0x47, 0x47, 0x48, 0x49, 0x4B,
+  0x4C, 0x51, 0x53, 0x56, 0x57, 0x58, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x57, 0x57, 0x55, 0x53, 0x53,
+  0x51, 0x50, 0x50, 0x50, 0x50, 0x50, 0x53, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xF4, 0xF5, 0xF9, 0xFC,
+  0xFC, 0xFC, 0xFC, 0x64, 0x64, 0x64, 0x64, 0x64,
+  0x64, 0x64, 0x64, 0x63, 0x61, 0x61, 0x5E, 0x59,
+  0x55, 0x52, 0x4C, 0x4A, 0x49, 0x47, 0x48, 0x48,
+  0x49, 0x4B, 0x4D, 0x51, 0x54, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x58, 0x55, 0x54, 0x54, 0x52, 0x51,
+  0x51, 0x51, 0x51, 0x51, 0x53, 0x54, 0x59, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xF7, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0x60, 0x60, 0x60, 0x61,
+  0x62, 0x63, 0x64, 0x64, 0x65, 0x65, 0x64, 0x63,
+  0x61, 0x5E, 0x59, 0x56, 0x4D, 0x4B, 0x48, 0x48,
+  0x48, 0x48, 0x49, 0x4B, 0x50, 0x53, 0x56, 0x56,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x56, 0x54, 0x53, 0x52, 0x51, 0x51,
+  0x51, 0x52, 0x53, 0x55, 0x59, 0x5D, 0x5E, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFB, 0xFB, 0xFB, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0x4C, 0x4E, 0x51, 0x52,
+  0x57, 0x5A, 0x5E, 0x60, 0x61, 0x63, 0x65, 0xCB,
+  0x64, 0x64, 0x63, 0x60, 0x5C, 0x57, 0x50, 0x4B,
+  0x48, 0x47, 0x47, 0x47, 0x4A, 0x4C, 0x52, 0x53,
+  0x54, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x55, 0x54, 0x53, 0x53, 0x51, 0x52, 0x52, 0x53,
+  0x53, 0x57, 0x5A, 0x5D, 0x5E, 0x5E, 0x60, 0xFC,
+  0xFC, 0xFC, 0xFB, 0xF9, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFA, 0xF9, 0xF5, 0xFB, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0x45, 0x3F, 0x3F,
+  0x45, 0x48, 0x4B, 0x4D, 0x54, 0x5A, 0x5E, 0x61,
+  0x63, 0xCB, 0xCB, 0x65, 0x64, 0x62, 0x5E, 0x57,
+  0x50, 0x4B, 0x48, 0x47, 0x47, 0x48, 0x4B, 0x4D,
+  0x51, 0x56, 0x56, 0x57, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55,
+  0x54, 0x54, 0x53, 0x53, 0x52, 0x53, 0x54, 0x57,
+  0x59, 0x5C, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0xFC,
+  0xFC, 0xFA, 0xFC, 0xFA, 0xE0, 0xFC, 0xFC, 0xFC,
+  0xFB, 0xFB, 0xFB, 0xDF, 0xD8, 0xF9, 0xE0, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0x4C, 0x4A, 0x48,
+  0x48, 0x3E, 0x44, 0x43, 0x3F, 0x47, 0x4B, 0x52,
+  0x5A, 0x5E, 0x62, 0x64, 0xCB, 0xCB, 0x64, 0x61,
+  0x5E, 0x57, 0x4D, 0x49, 0x47, 0x47, 0x48, 0x4A,
+  0x4C, 0x52, 0x54, 0x56, 0x57, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55,
+  0x54, 0x53, 0x53, 0x54, 0x54, 0x55, 0x58, 0x5B,
+  0x5C, 0x5D, 0x5E, 0x5D, 0x5D, 0x5B, 0x58, 0xFC,
+  0xFC, 0xD8, 0x4C, 0x60, 0xFC, 0xF5, 0xFC, 0xFC,
+  0xFC, 0xF7, 0x5F, 0x48, 0x48, 0x2C, 0xF8, 0xF9,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x4B, 0x4A, 0x49,
+  0x49, 0x49, 0x49, 0x47, 0x3E, 0x44, 0x42, 0x3F,
+  0x3E, 0x4B, 0x54, 0x5C, 0x61, 0x64, 0xCB, 0xCB,
+  0x64, 0x61, 0x5D, 0x53, 0x4B, 0x49, 0x47, 0x47,
+  0x49, 0x4B, 0x50, 0x53, 0x56, 0x57, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x57, 0x55, 0x55, 0x54,
+  0x53, 0x53, 0x54, 0x56, 0x58, 0x5A, 0x5B, 0x5D,
+  0x5D, 0x5D, 0x5C, 0x5A, 0x54, 0x52, 0x4C, 0xFC,
+  0xF7, 0x4E, 0x2D, 0x29, 0x4E, 0xFC, 0xFC, 0xFC,
+  0xFB, 0x5F, 0x26, 0x24, 0x20, 0x2E, 0x65, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x45, 0x3F, 0x45,
+  0x3E, 0x47, 0x47, 0x47, 0x47, 0x47, 0x3E, 0x44,
+  0x43, 0x40, 0x44, 0x49, 0x51, 0x5C, 0x62, 0x64,
+  0xCB, 0xCB, 0x63, 0x60, 0x58, 0x50, 0x49, 0x48,
+  0x48, 0x48, 0x4A, 0x4D, 0x53, 0x54, 0x57, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54, 0x54,
+  0x54, 0x54, 0x55, 0x57, 0x59, 0x5B, 0x5C, 0x5D,
+  0x5C, 0x5A, 0x54, 0x51, 0x4C, 0x4C, 0x54, 0xFC,
+  0xF9, 0x23, 0xDB, 0x2D, 0x23, 0xFA, 0xFB, 0xFA,
+  0xF5, 0x27, 0x21, 0xD9, 0xF8, 0x20, 0x21, 0xFB,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0x5D, 0x58, 0x55,
+  0x50, 0x48, 0x45, 0x43, 0x44, 0x44, 0x45, 0x45,
+  0x3E, 0x3F, 0x43, 0x41, 0x3F, 0x48, 0x52, 0x5D,
+  0x63, 0x65, 0xCB, 0x65, 0x61, 0x5D, 0x52, 0x4B,
+  0x48, 0x47, 0x47, 0x49, 0x4C, 0x51, 0x54, 0x57,
+  0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54, 0x54,
+  0x54, 0x58, 0x5A, 0x59, 0x5B, 0x5B, 0x5B, 0x5A,
+  0x55, 0x52, 0x4D, 0x4D, 0x55, 0x5B, 0x5D, 0xFC,
+  0xF1, 0xF9, 0xFC, 0xD4, 0x21, 0xCC, 0xF7, 0xF8,
+  0xF2, 0x21, 0xD9, 0xFC, 0xF2, 0xFB, 0x21, 0x45,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFB, 0xD1, 0xD0, 0xCD,
+  0xCC, 0x63, 0x5E, 0x58, 0x50, 0x47, 0x43, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x40, 0x41, 0x3F, 0x4A,
+  0x56, 0x5E, 0x64, 0xCB, 0x65, 0x63, 0x5E, 0x56,
+  0x4C, 0x48, 0x47, 0x47, 0x49, 0x4C, 0x51, 0x54,
+  0x58, 0x57, 0x57, 0x57, 0x57, 0x55, 0x54, 0x54,
+  0x57, 0x5A, 0x5A, 0x5C, 0x5B, 0x5A, 0x58, 0x54,
+  0x51, 0x4C, 0x55, 0x5D, 0x5D, 0x5B, 0x54, 0xFC,
+  0xF0, 0xF9, 0xFC, 0x65, 0x45, 0xCD, 0xFB, 0xFB,
+  0xF8, 0x26, 0xFB, 0xFC, 0xFC, 0xFC, 0x21, 0x27,
+  0xFB, 0xFC, 0xFC, 0xFC, 0xFB, 0xD7, 0x35, 0x34,
+  0x2F, 0x35, 0x36, 0x2F, 0x2F, 0x36, 0x2F, 0x2F,
+  0x36, 0x36, 0x35, 0x35, 0x43, 0x42, 0x41, 0x2E,
+  0x45, 0x4C, 0x5B, 0x62, 0x65, 0xCC, 0x64, 0x60,
+  0x58, 0x4D, 0x49, 0x47, 0x47, 0x49, 0x4C, 0x51,
+  0x58, 0x57, 0x57, 0x57, 0x57, 0x57, 0x55, 0x57,
+  0x58, 0x5A, 0x5A, 0x5B, 0x5A, 0x55, 0x54, 0x51,
+  0x53, 0x5C, 0x5D, 0x5D, 0x54, 0x4B, 0x4D, 0xFC,
+  0xFC, 0x44, 0xFC, 0xFB, 0x7B, 0xAB, 0xA8, 0xAE,
+  0xAB, 0x7F, 0xFC, 0xFC, 0xFB, 0xFB, 0x22, 0x2A,
+  0xFC, 0xFC, 0xFC, 0xFC, 0x36, 0x2F, 0x30, 0x30,
+  0x32, 0x30, 0x32, 0x30, 0x30, 0x30, 0x30, 0x30,
+  0x30, 0x30, 0x30, 0x30, 0x2F, 0x2F, 0x40, 0x41,
+  0x2E, 0x40, 0x48, 0x56, 0x5F, 0x64, 0xCC, 0x65,
+  0x61, 0x59, 0x50, 0x49, 0x47, 0x47, 0x49, 0x4C,
+  0x5A, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58,
+  0x5A, 0x5A, 0x5A, 0x58, 0x55, 0x52, 0x51, 0x5A,
+  0x5D, 0x5D, 0x57, 0x4C, 0x51, 0x54, 0x5D, 0xFC,
+  0xFC, 0x2A, 0xFC, 0xC9, 0xAA, 0x8B, 0x8A, 0x8C,
+  0xAB, 0x8C, 0x8C, 0xFB, 0xFB, 0x23, 0x20, 0xF1,
+  0xFC, 0xFC, 0xFC, 0x3B, 0x33, 0x33, 0x32, 0x32,
+  0x31, 0x32, 0x30, 0x32, 0x32, 0x32, 0x32, 0x30,
+  0x31, 0x31, 0x31, 0x32, 0x33, 0x33, 0x3C, 0x41,
+  0x41, 0x2E, 0x2D, 0x45, 0x4D, 0x5D, 0x63, 0xCC,
+  0x65, 0x62, 0x5D, 0x51, 0x49, 0x47, 0x47, 0x4A,
+  0x59, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58,
+  0x5A, 0x5A, 0x58, 0x55, 0x53, 0x53, 0x5C, 0x5E,
+  0x59, 0x51, 0x4E, 0x54, 0x59, 0x5E, 0x62, 0xFC,
+  0xFC, 0xDB, 0xAA, 0xA1, 0x95, 0x9C, 0x8C, 0x88,
+  0x82, 0x83, 0x83, 0x8C, 0x88, 0xAE, 0xB9, 0xFB,
+  0xFC, 0xFC, 0xFC, 0x3C, 0x3B, 0x72, 0x38, 0x33,
+  0x33, 0x33, 0x31, 0x33, 0x31, 0x31, 0x31, 0x31,
+  0x33, 0x33, 0x38, 0x33, 0x72, 0x3B, 0x44, 0x2E,
+  0x41, 0x2E, 0x2E, 0x2D, 0x43, 0x4B, 0x5B, 0x63,
+  0xCB, 0xCC, 0x63, 0x5D, 0x51, 0x49, 0x47, 0x49,
+  0x5C, 0x58, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58,
+  0x58, 0x58, 0x57, 0x53, 0x58, 0x5D, 0x5E, 0x55,
+  0x51, 0x53, 0x58, 0x5E, 0x60, 0x63, 0x64, 0xFC,
+  0xFC, 0xC0, 0xA6, 0x9D, 0x8B, 0x9C, 0x8C, 0x8C,
+  0x6E, 0x83, 0x88, 0x8C, 0x8C, 0x8C, 0x83, 0xE8,
+  0xFB, 0xFC, 0xFC, 0xFC, 0x33, 0x70, 0x70, 0x6F,
+  0x6F, 0x6F, 0x6F, 0x3A, 0x6F, 0x6D, 0x6F, 0x6F,
+  0x70, 0x6F, 0x6F, 0x70, 0x6F, 0x32, 0x5A, 0x48,
+  0x41, 0x2D, 0x2D, 0x2D, 0x2C, 0x41, 0x49, 0x5A,
+  0x62, 0xCB, 0xCB, 0x63, 0x5D, 0x50, 0x49, 0x4A,
+  0x5C, 0x58, 0x58, 0x57, 0x55, 0x57, 0x57, 0x57,
+  0x57, 0x55, 0x56, 0x59, 0x5E, 0x5C, 0x52, 0x53,
+  0x55, 0x5B, 0x5E, 0x61, 0x63, 0x64, 0x63, 0xFC,
+  0xE8, 0xBF, 0xA4, 0x99, 0x9C, 0x8C, 0x88, 0x88,
+  0x6E, 0x88, 0x8C, 0x8C, 0x8C, 0xC2, 0xA6, 0xC4,
+  0xFC, 0xFC, 0xFC, 0xFC, 0x36, 0x3A, 0x6F, 0x70,
+  0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70,
+  0x70, 0x70, 0x70, 0x70, 0x37, 0x32, 0xCD, 0x5E,
+  0x4C, 0x43, 0x2C, 0x2D, 0x2D, 0x2C, 0x2E, 0x47,
+  0x57, 0x61, 0x65, 0xCC, 0x63, 0x5C, 0x50, 0x4D,
+  0x5C, 0x5A, 0x57, 0x55, 0x55, 0x55, 0x58, 0x58,
+  0x55, 0x54, 0x5B, 0x5E, 0x5D, 0x53, 0x53, 0x55,
+  0x5D, 0x5E, 0x61, 0x61, 0x61, 0x61, 0x5E, 0xFC,
+  0xEA, 0xBE, 0xA4, 0x9B, 0x8B, 0x85, 0x8C, 0x6E,
+  0x8C, 0x8C, 0x8C, 0xA3, 0xAA, 0xA4, 0xA4, 0xE9,
+  0xFB, 0xFC, 0xFC, 0xFC, 0x36, 0x6D, 0x70, 0x73,
+  0x70, 0x70, 0x70, 0x73, 0x73, 0x73, 0x73, 0x70,
+  0x70, 0x70, 0x73, 0x70, 0x37, 0x38, 0xD1, 0xCF,
+  0x61, 0x4D, 0x44, 0x2C, 0x2D, 0x2E, 0x2C, 0x2E,
+  0x3E, 0x56, 0x61, 0xCB, 0xCC, 0x62, 0x5B, 0x57,
+  0x59, 0x58, 0x55, 0x54, 0x54, 0x55, 0x58, 0x58,
+  0x58, 0x5B, 0x5E, 0x5B, 0x53, 0x55, 0x55, 0x5C,
+  0x5E, 0x61, 0x61, 0x60, 0x5D, 0x5A, 0x4E, 0xFC,
+  0xFC, 0xEA, 0xAA, 0x9C, 0x8A, 0x85, 0x82, 0x8C,
+  0x8C, 0xA8, 0xEB, 0xA8, 0xA4, 0xA4, 0xAA, 0xFC,
+  0xFC, 0xFC, 0x64, 0xFB, 0x39, 0x31, 0x72, 0x78,
+  0x73, 0x78, 0x73, 0x74, 0x74, 0x74, 0x74, 0x73,
+  0x78, 0x70, 0x73, 0x73, 0x33, 0xCC, 0xD2, 0xD1,
+  0xCE, 0x62, 0x53, 0x3F, 0x2D, 0x2D, 0x41, 0x2C,
+  0x2E, 0x3E, 0x56, 0x62, 0xCB, 0xCB, 0x61, 0x5D,
+  0x54, 0x54, 0x54, 0x54, 0x56, 0x58, 0x58, 0x58,
+  0x5C, 0x5E, 0x5A, 0x55, 0x58, 0x58, 0x5B, 0x5E,
+  0x61, 0x5E, 0x5D, 0x5A, 0x52, 0x55, 0xCD, 0xFC,
+  0xFC, 0x34, 0xC9, 0xE8, 0xA8, 0xAE, 0xC2, 0xE8,
+  0xC3, 0xA6, 0xA7, 0xA6, 0xAA, 0x78, 0x2E, 0x42,
+  0xFC, 0xFC, 0xD2, 0x64, 0xF8, 0x31, 0x72, 0x73,
+  0x73, 0x73, 0x73, 0x74, 0x75, 0x75, 0x74, 0x73,
+  0x73, 0x73, 0x73, 0x72, 0x33, 0x5C, 0x64, 0xD2,
+  0xD1, 0xCF, 0x63, 0x54, 0x3F, 0x2C, 0x41, 0x41,
+  0x2C, 0x2E, 0x47, 0x58, 0x63, 0xCB, 0xCB, 0x62,
+  0x52, 0x53, 0x53, 0x56, 0x58, 0x58, 0x5A, 0x5B,
+  0x5E, 0x5A, 0x57, 0x58, 0x58, 0x58, 0x60, 0x60,
+  0x5D, 0x5A, 0x55, 0x4E, 0x64, 0xD2, 0xD1, 0xFC,
+  0xFC, 0x41, 0x3E, 0xC1, 0xC0, 0xA3, 0xA6, 0xA7,
+  0xA7, 0xA9, 0xAA, 0xB8, 0x2E, 0x3F, 0x2C, 0x41,
+  0xFC, 0xFC, 0xF7, 0xCE, 0xCD, 0x36, 0x72, 0x73,
+  0x74, 0x75, 0x78, 0x75, 0x75, 0x75, 0x74, 0x74,
+  0x74, 0x74, 0x78, 0x72, 0x6D, 0x49, 0x59, 0xCB,
+  0xD1, 0xD1, 0xD2, 0xCB, 0x56, 0x3F, 0x2C, 0x41,
+  0x40, 0x2D, 0x2E, 0x49, 0x5B, 0x64, 0xCC, 0x64,
+  0x51, 0x53, 0x53, 0x55, 0x58, 0x59, 0x5B, 0x5E,
+  0x59, 0x58, 0x58, 0x58, 0x55, 0x60, 0x60, 0x5C,
+  0x5A, 0x53, 0x5B, 0xD0, 0xD3, 0xD3, 0xD3, 0xFB,
+  0xFC, 0x40, 0x41, 0x45, 0xC4, 0xC0, 0xBE, 0xBE,
+  0xC1, 0xC0, 0x3C, 0x47, 0x2E, 0x21, 0x22, 0x20,
+  0x65, 0xFC, 0xFC, 0xFC, 0xFC, 0x6D, 0x72, 0x75,
+  0x78, 0x76, 0x75, 0x79, 0x76, 0x76, 0x76, 0x76,
+  0x75, 0x75, 0x75, 0x72, 0x6D, 0x2E, 0x48, 0x5D,
+  0xCE, 0xD1, 0xD4, 0xD3, 0xCB, 0x56, 0x43, 0x2C,
+  0x42, 0x43, 0x2E, 0x2E, 0x4A, 0x5D, 0x64, 0x64,
+  0x50, 0x52, 0x56, 0x58, 0x5C, 0x5D, 0x5E, 0x5D,
+  0x5A, 0x58, 0x58, 0x55, 0x61, 0x60, 0x58, 0x58,
+  0x4E, 0x61, 0xD1, 0xD4, 0xD4, 0xD1, 0xEE, 0xFC,
+  0xFC, 0x2B, 0x29, 0x2E, 0x3F, 0xB0, 0xAD, 0x81,
+  0x46, 0x2D, 0x46, 0x2C, 0x24, 0x22, 0x22, 0x23,
+  0x25, 0xFC, 0xFC, 0xFC, 0xFC, 0x6E, 0x73, 0x76,
+  0x76, 0x79, 0x79, 0x79, 0x76, 0x76, 0x79, 0x76,
+  0x79, 0x79, 0x79, 0x74, 0x3F, 0x41, 0x2C, 0x48,
+  0x5F, 0xCF, 0xD5, 0xD7, 0xD6, 0xCD, 0x57, 0x40,
+  0x2E, 0x3F, 0x44, 0x2E, 0x41, 0x4C, 0x60, 0x61,
+  0x51, 0x53, 0x58, 0x5C, 0x5D, 0x5E, 0x5D, 0x5C,
+  0x58, 0x57, 0x54, 0x5F, 0x5E, 0x55, 0x55, 0x52,
+  0x64, 0xD4, 0xD5, 0xD4, 0xD1, 0x5D, 0xFA, 0xFB,
+  0xF4, 0x21, 0x24, 0x41, 0x40, 0x44, 0x2E, 0x2E,
+  0x42, 0x41, 0x2A, 0x24, 0x22, 0x22, 0x22, 0x22,
+  0x23, 0xD9, 0xFC, 0xFC, 0xFC, 0xFC, 0xE5, 0xB8,
+  0x8F, 0x8F, 0x7A, 0x8F, 0x7A, 0x8F, 0x7A, 0x8F,
+  0x8F, 0x8F, 0xB8, 0xE5, 0x3F, 0x3E, 0x43, 0x2C,
+  0x48, 0x61, 0xD1, 0xD7, 0xD9, 0xD7, 0xD0, 0x57,
+  0x41, 0x2E, 0x3E, 0x44, 0x2D, 0x40, 0x52, 0x5D,
+  0x53, 0x55, 0x59, 0x5D, 0x5E, 0x5E, 0x5D, 0x5A,
+  0x57, 0x53, 0x5E, 0x5E, 0x54, 0x53, 0x54, 0x65,
+  0xD5, 0xD6, 0xD4, 0xCE, 0x53, 0xFB, 0xF9, 0xFC,
+  0x24, 0x22, 0x23, 0x23, 0x41, 0x42, 0x2E, 0x40,
+  0x2B, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+  0x23, 0x23, 0xFC, 0xFC, 0xFC, 0xFC, 0xE7, 0xBD,
+  0xB5, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+  0x93, 0xB5, 0xC6, 0xEB, 0x2D, 0x47, 0x4A, 0x47,
+  0x2C, 0x3E, 0x61, 0xD4, 0xDC, 0xDC, 0xDA, 0xCF,
+  0x54, 0x41, 0x41, 0x3E, 0x45, 0x2C, 0x3F, 0x4A,
+  0x58, 0x5A, 0x5C, 0x5F, 0x60, 0x5E, 0x5D, 0x57,
+  0x51, 0x5D, 0x5D, 0x51, 0x53, 0x53, 0xCB, 0xD5,
+  0xD6, 0xD5, 0x63, 0x55, 0xFC, 0xFC, 0xFC, 0x2C,
+  0x23, 0x22, 0x23, 0x22, 0x20, 0x2D, 0x2C, 0x26,
+  0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+  0x22, 0x21, 0xF0, 0xFC, 0xFC, 0xFC, 0xE2, 0xC6,
+  0xB5, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+  0x93, 0x93, 0xC7, 0xE3, 0x3E, 0x2E, 0x49, 0x52,
+  0x4C, 0x41, 0x44, 0x62, 0xD6, 0xDE, 0xDE, 0xD9,
+  0xD0, 0x51, 0x2E, 0x40, 0x47, 0x44, 0x2C, 0x42,
+  0x5D, 0x5D, 0x5F, 0x60, 0x60, 0x5D, 0x57, 0x51,
+  0x58, 0x5D, 0x4E, 0x52, 0x55, 0x64, 0xD5, 0xD6,
+  0xD4, 0x61, 0x59, 0x6B, 0xFC, 0xFC, 0xFC, 0x21,
+  0x23, 0x22, 0x23, 0x22, 0x23, 0x21, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+  0x22, 0x21, 0x24, 0xFC, 0xFC, 0xFC, 0xE2, 0xC7,
+  0xB5, 0x90, 0x93, 0x93, 0x93, 0x90, 0x93, 0x93,
+  0x90, 0xB5, 0xC8, 0xE4, 0x5F, 0x45, 0x2E, 0x4D,
+  0x57, 0x57, 0x44, 0x43, 0x63, 0xDA, 0xDF, 0xDF,
+  0xD9, 0xCE, 0x4C, 0x2C, 0x3F, 0x3E, 0x40, 0x40,
+  0x60, 0x5E, 0x61, 0x61, 0x5E, 0x5B, 0x53, 0x52,
+  0x5C, 0x52, 0x52, 0x55, 0x61, 0xD4, 0xD5, 0xD1,
+  0x5E, 0x5B, 0x5C, 0xFB, 0xFC, 0xFC, 0x2A, 0x21,
+  0x23, 0x22, 0x23, 0x22, 0x22, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+  0x22, 0x22, 0x22, 0xFB, 0xFC, 0xFC, 0xB3, 0xC8,
+  0xB5, 0x90, 0x92, 0xB5, 0x93, 0x93, 0xB5, 0x93,
+  0x92, 0xB5, 0xC8, 0xB9, 0xD0, 0x5E, 0x44, 0x40,
+  0x52, 0x58, 0x57, 0x48, 0x40, 0x63, 0xD9, 0xE0,
+  0xE0, 0xD9, 0xCB, 0x49, 0x2D, 0x3F, 0x45, 0x3F,
+  0x63, 0x61, 0x62, 0x60, 0x5E, 0x55, 0x4D, 0x59,
+  0x53, 0x4E, 0x54, 0x5D, 0xD2, 0xD4, 0xD2, 0x5E,
+  0x5C, 0x5D, 0xFC, 0xFC, 0xFC, 0xF8, 0x29, 0x23,
+  0x23, 0x23, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
+  0x23, 0x22, 0x22, 0x23, 0x23, 0x23, 0x22, 0x22,
+  0x22, 0x22, 0x22, 0xF0, 0xFC, 0xFC, 0xB3, 0xC7,
+  0xB5, 0x93, 0xB5, 0x93, 0x93, 0x91, 0x93, 0x93,
+  0x91, 0xB5, 0xC7, 0xAD, 0xD6, 0xD2, 0x5E, 0x3F,
+  0x3F, 0x57, 0x57, 0x58, 0x4A, 0x41, 0x64, 0xDC,
+  0xF1, 0xDF, 0xDA, 0x61, 0x45, 0x2E, 0x43, 0x47,
+  0xCB, 0x63, 0x62, 0x5F, 0x58, 0x51, 0x53, 0x54,
+  0x4C, 0x52, 0x5C, 0xCD, 0xD3, 0xD2, 0x60, 0x5D,
+  0x5D, 0xFB, 0xFC, 0xFC, 0xFC, 0xDB, 0x49, 0x24,
+  0x21, 0x23, 0x23, 0x22, 0x26, 0x26, 0x2A, 0x24,
+  0x22, 0x23, 0x22, 0x21, 0x24, 0x26, 0x26, 0x2A,
+  0x29, 0x2B, 0x24, 0x25, 0xFC, 0xFC, 0xB3, 0xC5,
+  0x91, 0x91, 0x92, 0x91, 0x92, 0x92, 0x93, 0x93,
+  0x91, 0x93, 0xC6, 0xAD, 0xDC, 0xD9, 0xD4, 0x60,
+  0x43, 0x45, 0x58, 0x58, 0x57, 0x4B, 0x43, 0xCC,
+  0xDD, 0xF1, 0xD8, 0xD5, 0x5D, 0x43, 0x41, 0x47,
+  0xCD, 0x63, 0x62, 0x5D, 0x54, 0x4C, 0x55, 0x4B,
+  0x51, 0x58, 0x62, 0xD0, 0xD0, 0x62, 0x5D, 0x5D,
+  0x67, 0xFC, 0xFC, 0xFC, 0xFC, 0x58, 0x4E, 0x28,
+  0x2A, 0x20, 0x23, 0x22, 0x23, 0x2A, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x23, 0x25, 0x2A, 0x2E, 0x2D,
+  0x2E, 0x2E, 0x2E, 0x23, 0xFA, 0xFC, 0xB2, 0xBD,
+  0xB5, 0x90, 0x91, 0x93, 0x92, 0x90, 0x91, 0x93,
+  0x92, 0x91, 0xBD, 0xAD, 0xDE, 0xE0, 0xD8, 0xD7,
+  0x61, 0x40, 0x48, 0x58, 0x58, 0x58, 0x48, 0x44,
+  0xCF, 0xDE, 0xE0, 0xDD, 0xD0, 0x52, 0x41, 0x45,
+  0xCD, 0x63, 0x61, 0x58, 0x4D, 0x51, 0x4C, 0x4B,
+  0x54, 0x5D, 0xCC, 0xCE, 0x63, 0x61, 0x5D, 0x5D,
+  0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0x4B, 0x27, 0x21,
+  0x22, 0x22, 0x23, 0x22, 0x22, 0x24, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x20,
+  0x27, 0x2B, 0x41, 0x2B, 0x23, 0xFC, 0xB2, 0xB6,
+  0x93, 0x90, 0x92, 0xB5, 0x92, 0x90, 0xB5, 0x90,
+  0x92, 0x93, 0xBC, 0xAD, 0xDC, 0xF1, 0xF3, 0xF0,
+  0xD9, 0x61, 0x41, 0x4A, 0x58, 0x57, 0x57, 0x44,
+  0x49, 0xD2, 0xDD, 0xD8, 0xDA, 0x63, 0x4A, 0x45,
+  0xCC, 0x63, 0x5E, 0x52, 0x4B, 0x4C, 0x49, 0x51,
+  0x5C, 0x61, 0xCD, 0x65, 0x63, 0x5E, 0x4E, 0xCF,
+  0xFB, 0xFB, 0xF0, 0xFC, 0xD2, 0x2A, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x26, 0x41, 0x27, 0xF9, 0x81, 0xB7,
+  0xB5, 0x91, 0x92, 0xB5, 0x91, 0xB5, 0x93, 0xB5,
+  0x93, 0xB6, 0xB7, 0xB9, 0xCB, 0xD8, 0xF3, 0xF2,
+  0xF2, 0xDB, 0x61, 0x2D, 0x51, 0x58, 0x57, 0x58,
+  0x41, 0x51, 0xD4, 0xDB, 0xDC, 0xD1, 0x5B, 0x4C,
+  0xCB, 0x62, 0x59, 0x4C, 0x4A, 0x49, 0x4B, 0x55,
+  0x60, 0x64, 0xCC, 0x64, 0x5E, 0x55, 0x60, 0xE1,
+  0xFB, 0xF8, 0xFC, 0xFC, 0x21, 0x22, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x21, 0x24, 0x2D, 0x21, 0xB4, 0xBB,
+  0xB6, 0xB5, 0xB6, 0xB7, 0xB7, 0xB7, 0xB7, 0xB6,
+  0xB6, 0xB6, 0xBB, 0xB9, 0x45, 0xCB, 0xDF, 0xF3,
+  0xF3, 0xF3, 0xDB, 0x5E, 0x2C, 0x51, 0x58, 0x58,
+  0x52, 0x2D, 0x5C, 0xD4, 0xD9, 0xD5, 0x63, 0x58,
+  0x64, 0x60, 0x53, 0x49, 0x4A, 0x49, 0x52, 0x5C,
+  0x63, 0xCD, 0xCD, 0x63, 0x5C, 0x4E, 0x65, 0xFC,
+  0xFC, 0xF5, 0xFC, 0xD2, 0x23, 0x22, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x22, 0x22, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x21, 0x22, 0x25, 0x29, 0xB3, 0xC7,
+  0xB5, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
+  0xB6, 0xB5, 0xC7, 0xAD, 0x57, 0x3F, 0xCB, 0xF0,
+  0xF3, 0xF3, 0xF2, 0xD9, 0x58, 0x41, 0x4C, 0x58,
+  0x57, 0x47, 0x42, 0x62, 0xD4, 0xD4, 0xCC, 0x60,
+  0x63, 0x5D, 0x50, 0x47, 0x48, 0x4B, 0x58, 0x60,
+  0xCC, 0xCE, 0xCD, 0x60, 0x53, 0x5C, 0x62, 0xFB,
+  0xF9, 0xFC, 0xFC, 0x21, 0x23, 0x22, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x23, 0x23, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x23, 0x22, 0x23, 0x81, 0xC7,
+  0xB7, 0xB7, 0xBC, 0xB7, 0xBC, 0xBC, 0xBC, 0xB7,
+  0xB7, 0xB7, 0xC8, 0x80, 0x58, 0x57, 0x40, 0xCE,
+  0xF3, 0xF2, 0xF2, 0xF0, 0xD5, 0x4C, 0x3F, 0x4B,
+  0x52, 0x50, 0x2D, 0x4B, 0x64, 0xD2, 0xCC, 0x61,
+  0x60, 0x58, 0x4A, 0x47, 0x47, 0x4C, 0x59, 0x64,
+  0xD0, 0xD0, 0x64, 0x59, 0x49, 0x5D, 0xFB, 0xFC,
+  0xD9, 0xFC, 0xD6, 0x23, 0x22, 0x22, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x23, 0x21, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x23, 0x22, 0x23, 0xB4, 0xC8,
+  0xBD, 0xB7, 0xBD, 0xBC, 0xBD, 0xC5, 0xBC, 0xC5,
+  0xBC, 0xBD, 0xC7, 0xAC, 0x58, 0x57, 0x58, 0x2C,
+  0xD1, 0xF0, 0xF3, 0xF3, 0xE0, 0xCD, 0x45, 0x3E,
+  0x48, 0x4B, 0x3F, 0x41, 0x56, 0x64, 0x65, 0x62,
+  0x5D, 0x52, 0x47, 0x48, 0x48, 0x53, 0x60, 0xCC,
+  0xD2, 0xD0, 0x63, 0x52, 0x4E, 0x53, 0xFB, 0xFB,
+  0xFC, 0xFC, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x23, 0x20, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x22, 0x23, 0x22, 0xB4, 0xC7,
+  0xC5, 0xBC, 0xC5, 0xBD, 0xC5, 0xC5, 0xBD, 0xC5,
+  0xBC, 0xC6, 0xC7, 0xB9, 0x58, 0x57, 0x58, 0x57,
+  0x2D, 0xD4, 0xF1, 0xF2, 0xF0, 0xD9, 0x5D, 0x47,
+  0x48, 0x3F, 0x42, 0x2C, 0x48, 0x5C, 0x5F, 0x60,
+  0x58, 0x50, 0x47, 0x4A, 0x49, 0x55, 0x63, 0xD0,
+  0xD2, 0xCD, 0x5D, 0x49, 0x4E, 0xE1, 0xFC, 0xF0,
+  0xFC, 0xF8, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x20, 0x21, 0x21, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x22,
+  0x23, 0x22, 0x23, 0x23, 0x23, 0x22, 0xC4, 0xC8,
+  0xBD, 0xBD, 0xC6, 0xBD, 0xC6, 0xC6, 0xC5, 0xC6,
+  0xBD, 0xC6, 0xC7, 0xE4, 0x54, 0x57, 0x58, 0x57,
+  0x57, 0x43, 0xD7, 0xE0, 0xF1, 0xD8, 0xCD, 0x4B,
+  0x4A, 0x47, 0x42, 0x2C, 0x3F, 0x4D, 0x58, 0x5C,
+  0x52, 0x4B, 0x48, 0x4B, 0x4A, 0x58, 0xCB, 0xD3,
+  0xD2, 0xCD, 0x58, 0x47, 0x4A, 0xFC, 0xFC, 0xFB,
+  0xFC, 0x2B, 0x22, 0x22, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x26, 0x21, 0x21, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0xE5, 0xC8,
+  0xBA, 0xC5, 0xC6, 0xC6, 0xC6, 0xC7, 0xC6, 0xC7,
+  0xC5, 0xC6, 0xC8, 0xE5, 0x2E, 0x54, 0x58, 0x57,
+  0x57, 0x4C, 0x4D, 0xDA, 0xD8, 0xD8, 0xD4, 0x5C,
+  0x4B, 0x4B, 0x3F, 0x42, 0x44, 0x4A, 0x51, 0x58,
+  0x4B, 0x48, 0x4B, 0x51, 0x4D, 0x5F, 0xD0, 0xD1,
+  0xD0, 0x64, 0x51, 0x44, 0x6B, 0xFC, 0xFB, 0xFC,
+  0xFC, 0x21, 0x23, 0x22, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x22, 0x23, 0x26, 0x21, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0xE5, 0xED,
+  0xE7, 0xBA, 0xC8, 0xC6, 0xC6, 0xC6, 0xC6, 0xC7,
+  0xC7, 0xE5, 0xED, 0xE6, 0x61, 0x41, 0x52, 0x58,
+  0x58, 0x57, 0x45, 0x5E, 0xD7, 0xDD, 0xD5, 0x60,
+  0x4B, 0x4C, 0x48, 0x4D, 0x4D, 0x50, 0x4D, 0x56,
+  0x4A, 0x3E, 0x53, 0x53, 0x52, 0x63, 0xD3, 0xD0,
+  0xCE, 0x60, 0x4A, 0x45, 0xFC, 0xFC, 0xF7, 0xFC,
+  0xFC, 0x21, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x23, 0x21, 0x2A, 0x20, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x22, 0x21, 0x23, 0xEB, 0xF6,
+  0xF6, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED,
+  0xF6, 0xF6, 0xF6, 0xE6, 0xDB, 0x58, 0x45, 0x4B,
+  0x58, 0x57, 0x4D, 0x4B, 0x64, 0xD4, 0xD0, 0x5C,
+  0x48, 0x51, 0x4C, 0x5D, 0x5E, 0x5C, 0x56, 0x59,
+  0x3E, 0x4A, 0x58, 0x54, 0x52, 0x65, 0xD3, 0xD0,
+  0xCF, 0x5D, 0x48, 0xFC, 0xFC, 0xFC, 0xFA, 0xFC,
+  0xFC, 0x21, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x23, 0x21, 0x2A, 0x21, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x22, 0x21, 0x4F, 0xE6, 0xC6,
+  0xC6, 0xBD, 0xC6, 0xBD, 0xBD, 0xBD, 0xBD, 0xC6,
+  0xC5, 0xBA, 0xC7, 0xE6, 0xF2, 0xD4, 0x49, 0x4B,
+  0x3E, 0x4D, 0x52, 0x3E, 0x52, 0x63, 0x64, 0x56,
+  0x48, 0x54, 0x4D, 0x61, 0xCC, 0xCC, 0x60, 0x60,
+  0x47, 0x4D, 0x5C, 0x53, 0x58, 0xCF, 0xD1, 0xCF,
+  0xD0, 0x59, 0x45, 0xFC, 0xFC, 0xFC, 0xEF, 0xF9,
+  0xFC, 0x21, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+  0x23, 0x22, 0x23, 0x2A, 0x21, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x22, 0x23, 0x4F, 0xE4, 0xB9,
+  0xAF, 0x80, 0x80, 0x8E, 0x8E, 0x8E, 0x8E, 0x8F,
+  0x80, 0xB4, 0xB9, 0xE4, 0x7F, 0xDE, 0x61, 0x52,
+  0x54, 0x48, 0x3F, 0x43, 0x4D, 0x56, 0x59, 0x4B,
+  0x3E, 0x58, 0x53, 0x61, 0xD3, 0xD4, 0xCF, 0xCD,
+  0x4C, 0x58, 0x5F, 0x53, 0x5E, 0xD3, 0xD0, 0xCE,
+  0xCE, 0x52, 0x3F, 0xFC, 0xFC, 0xFC, 0xF7, 0x65,
+  0xFA, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+  0x23, 0x22, 0x21, 0x2A, 0x23, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x23, 0x22, 0x23, 0x22, 0x21, 0xB1, 0xE4, 0xE6,
+  0x7C, 0xB1, 0x7C, 0xB1, 0xB2, 0xB2, 0xB3, 0x3D,
+  0xB3, 0x3C, 0xE5, 0xB3, 0xB0, 0xF1, 0xD0, 0x58,
+  0x5D, 0x4D, 0x40, 0x41, 0x48, 0x51, 0x4C, 0x3F,
+  0x3F, 0x4D, 0x5A, 0x5A, 0xD5, 0xD9, 0xD7, 0xD4,
+  0x57, 0x5E, 0x61, 0x4C, 0x63, 0xD4, 0xCF, 0xCE,
+  0xCB, 0x4D, 0x4A, 0xFC, 0xFC, 0xFC, 0xFC, 0xF0,
+  0xFB, 0x22, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+  0x23, 0x22, 0x23, 0x2A, 0x21, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x22, 0x23, 0x22, 0x23, 0x23, 0xB1, 0x81, 0x7D,
+  0x39, 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x36,
+  0x36, 0x36, 0x7C, 0xB2, 0xB0, 0xDF, 0xD2, 0x57,
+  0x60, 0x59, 0x5B, 0x59, 0x52, 0x4C, 0x4A, 0x40,
+  0x42, 0x4A, 0x53, 0x4D, 0xD2, 0xDE, 0xDE, 0xD9,
+  0x5E, 0x5E, 0x60, 0x4A, 0xCD, 0xD1, 0xCF, 0xCE,
+  0x63, 0x49, 0x5C, 0xFB, 0xE8, 0x89, 0x9F, 0xFC,
+  0xD6, 0x21, 0x21, 0x23, 0x22, 0x22, 0x23, 0x22,
+  0x23, 0x22, 0x21, 0x2A, 0x22, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x7F, 0xB9,
+  0x71, 0x6C, 0x38, 0x38, 0x33, 0x33, 0x33, 0x38,
+  0x38, 0x71, 0xAD, 0xE4, 0xD3, 0xDA, 0xCC, 0x52,
+  0x63, 0x60, 0xCE, 0xD4, 0xCF, 0x60, 0x4C, 0x40,
+  0x3F, 0x45, 0x4B, 0x5A, 0xCB, 0xD8, 0xDE, 0xDC,
+  0x5E, 0x5E, 0x5F, 0x4C, 0xD2, 0xD2, 0xCF, 0xCF,
+  0x61, 0x45, 0x5E, 0xA7, 0x9D, 0x95, 0x8B, 0x99,
+  0xFC, 0x41, 0x21, 0x23, 0x23, 0x22, 0x23, 0x22,
+  0x23, 0x22, 0x23, 0x2A, 0x23, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x77, 0x77, 0xF6,
+  0xFC, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7E, 0x7D,
+  0x7D, 0xFC, 0x47, 0x64, 0xD0, 0xD0, 0x5D, 0x4B,
+  0x62, 0xCC, 0xD1, 0xDE, 0xDE, 0xD4, 0x5E, 0x43,
+  0x3F, 0x3E, 0x48, 0x53, 0x58, 0xDB, 0xD8, 0xDC,
+  0x5E, 0x5E, 0x5E, 0x53, 0xD4, 0xD2, 0xD0, 0xD0,
+  0x5E, 0x49, 0xA7, 0xA6, 0x89, 0x95, 0x8B, 0x9C,
+  0x9C, 0xFB, 0xD4, 0x22, 0x22, 0x22, 0x22, 0x23,
+  0x22, 0x23, 0x23, 0x2A, 0x22, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x23, 0x22, 0x23, 0x23, 0x98, 0x8C, 0x8C, 0x88,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF8,
+  0xE9, 0x9C, 0x48, 0x5C, 0xD0, 0xCB, 0x48, 0x49,
+  0x5B, 0xCB, 0xCD, 0xE0, 0xF1, 0xDD, 0xD0, 0x4A,
+  0x41, 0x47, 0x45, 0x4C, 0x48, 0xD7, 0xDE, 0xDC,
+  0x5E, 0x5E, 0x5A, 0x58, 0xD1, 0xD0, 0xD0, 0xD2,
+  0x5C, 0x55, 0xA7, 0xA6, 0x87, 0x86, 0x89, 0x94,
+  0x9C, 0xA9, 0xFC, 0xF4, 0x22, 0x23, 0x22, 0x23,
+  0x22, 0x23, 0x22, 0x2A, 0x21, 0x23, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x22, 0x23, 0x22, 0x23, 0xA4, 0x89, 0x8C, 0xAA,
+  0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xF7,
+  0x85, 0x88, 0x8D, 0x59, 0x64, 0x63, 0x47, 0x3E,
+  0x4C, 0x60, 0x61, 0xE0, 0xF0, 0xDF, 0xD9, 0x5D,
+  0x2E, 0x3E, 0x3E, 0x47, 0x4D, 0xCD, 0xDE, 0xDC,
+  0x5D, 0x5C, 0x51, 0x5D, 0xD1, 0xD2, 0xD2, 0xD4,
+  0x5A, 0xBE, 0xA7, 0x98, 0x8A, 0x8A, 0xA0, 0x8B,
+  0x86, 0x86, 0xF7, 0xFC, 0xF7, 0x26, 0x23, 0x23,
+  0x22, 0x22, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x22, 0x21, 0x21, 0x21, 0xA1, 0x98, 0x9F, 0xBF,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xA7,
+  0x8C, 0x86, 0x8D, 0x59, 0x5E, 0x5D, 0x3F, 0x3E,
+  0x47, 0x53, 0x63, 0xD9, 0xF0, 0xF1, 0xDE, 0xD0,
+  0x43, 0x3E, 0x47, 0x45, 0x4A, 0x5B, 0xDC, 0xDA,
+  0x5D, 0x59, 0x49, 0x5F, 0xD1, 0xD2, 0xD3, 0xB9,
+  0xA5, 0xA7, 0x98, 0x9B, 0x96, 0x9D, 0x89, 0x89,
+  0x8B, 0x9C, 0x9D, 0xFC, 0xFC, 0xFC, 0x26, 0x22,
+  0x23, 0x23, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x22, 0x22, 0x29, 0x2D, 0x99, 0x99, 0xA2, 0xAA,
+  0xC4, 0xFB, 0xFC, 0xFC, 0xFC, 0xF6, 0xBF, 0xA2,
+  0x9C, 0x9C, 0x8E, 0xDC, 0xCD, 0x51, 0x41, 0x3E,
+  0x45, 0x49, 0x58, 0xCD, 0xE0, 0xE0, 0xD8, 0xDA,
+  0x4C, 0x4A, 0x45, 0x45, 0x48, 0x47, 0xDA, 0xDA,
+  0x5C, 0x58, 0x44, 0x69, 0xA9, 0x98, 0xA4, 0xA6,
+  0xA1, 0xA4, 0x99, 0x9E, 0x9D, 0x8B, 0x8A, 0x97,
+  0x87, 0x9A, 0x8A, 0xC2, 0xFC, 0xFC, 0xFC, 0x4D,
+  0x21, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x22,
+  0x21, 0x22, 0x2D, 0x34, 0xA4, 0xA2, 0xA2, 0xA9,
+  0xBF, 0xC0, 0xC3, 0xC1, 0xC0, 0xBE, 0xA6, 0x9D,
+  0x99, 0x87, 0xA2, 0xF1, 0xDC, 0x64, 0x42, 0x45,
+  0x47, 0x3E, 0x49, 0x4C, 0xDD, 0xDF, 0xD8, 0xDB,
+  0x5E, 0x4C, 0x48, 0x45, 0x45, 0x41, 0xD1, 0xD6,
+  0x5A, 0x55, 0x3F, 0xA7, 0xA1, 0x98, 0x9F, 0x99,
+  0x9F, 0x9D, 0x9A, 0x95, 0x8B, 0x97, 0x89, 0x8A,
+  0x88, 0x94, 0x9C, 0x8C, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xF4, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x22, 0x23,
+  0x23, 0x23, 0x2C, 0x2C, 0xA8, 0xA2, 0xA4, 0xA4,
+  0xA9, 0xAA, 0xAA, 0xAA, 0xA9, 0xA6, 0x98, 0x9C,
+  0x8B, 0x88, 0x98, 0x8D, 0xD8, 0xD6, 0x4E, 0x47,
+  0x47, 0x49, 0x47, 0x3F, 0xDA, 0xDD, 0xDE, 0xDD,
+  0xCC, 0x4A, 0x4B, 0x3E, 0x45, 0x43, 0x61, 0xD4,
+  0x56, 0x51, 0x44, 0xA4, 0x9B, 0x8B, 0x9C, 0x9A,
+  0xA0, 0xA2, 0x98, 0x98, 0x8B, 0x8B, 0x98, 0x98,
+  0x84, 0x8B, 0x94, 0x8A, 0xA4, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xF2, 0x21, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x23, 0x22, 0x23, 0x23, 0x23, 0x23,
+  0x23, 0x22, 0x2C, 0x2D, 0xC0, 0xA4, 0xA2, 0xA4,
+  0xA4, 0xA6, 0xA6, 0xA6, 0xA4, 0xA2, 0x9F, 0x89,
+  0x8B, 0x9C, 0x9C, 0x8B, 0x68, 0xDB, 0x5F, 0x4B,
+  0x3E, 0x49, 0x4B, 0x3E, 0xCC, 0xDA, 0xDC, 0xDD,
+  0xD3, 0x49, 0x52, 0x48, 0x45, 0x45, 0x53, 0xD0,
+  0x51, 0x4A, 0x44, 0xA4, 0x9B, 0x8B, 0x9C, 0xA0,
+  0x9B, 0x86, 0x89, 0x98, 0x89, 0x8A, 0x96, 0x8A,
+  0x9C, 0x89, 0x89, 0x9C, 0x8C, 0xF6, 0xFC, 0xFC,
+  0xFC, 0xFC, 0x21, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x23,
+  0x22, 0x21, 0x2B, 0x34, 0xC0, 0xA8, 0xA4, 0xA2,
+  0xA2, 0x98, 0xA1, 0xA0, 0x98, 0x9F, 0x95, 0x8A,
+  0x94, 0xA1, 0x8A, 0x84, 0x9B, 0x68, 0xCC, 0x49,
+  0x4A, 0x47, 0x4C, 0x4B, 0x51, 0xD3, 0xDA, 0xDC,
+  0xD5, 0x56, 0x56, 0x4A, 0x3E, 0x45, 0x48, 0x63,
+  0x4A, 0x47, 0x3E, 0xA7, 0x98, 0x9D, 0x9E, 0x8B,
+  0x95, 0x9B, 0x89, 0x86, 0x9B, 0x8B, 0x89, 0x84,
+  0x9A, 0xA1, 0x95, 0x9A, 0x8C, 0xA4, 0xFC, 0xFC,
+  0xFC, 0xFA, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x23,
+  0x21, 0x23, 0x2C, 0xF6, 0xBF, 0xA9, 0xA2, 0x99,
+  0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9B, 0x87, 0x8B,
+  0x9C, 0x86, 0x9C, 0x8A, 0x87, 0x87, 0x89, 0x51,
+  0x54, 0x47, 0x4B, 0x50, 0x4B, 0xCF, 0xD6, 0xDC,
+  0xD5, 0x60, 0x54, 0x52, 0x48, 0x45, 0x40, 0x5A,
+  0x45, 0x43, 0x47, 0xA7, 0x98, 0x9B, 0x95, 0x95,
+  0x9A, 0x87, 0x98, 0x98, 0x8A, 0x86, 0x87, 0x9E,
+  0x9B, 0x95, 0x9D, 0x9D, 0x99, 0x85, 0xA6, 0xFA,
+  0xF2, 0x21, 0x23, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x22, 0x22,
+  0x21, 0x24, 0xFB, 0xF7, 0xBF, 0xA6, 0xA2, 0x99,
+  0x97, 0x89, 0x86, 0x89, 0x9C, 0x96, 0x9E, 0x94,
+  0x89, 0x99, 0x98, 0x89, 0x9E, 0x9B, 0x89, 0x8B,
+  0x58, 0x4B, 0x4A, 0x52, 0x48, 0xCC, 0xD3, 0xDA,
+  0xD3, 0x65, 0x4C, 0x58, 0x49, 0x3E, 0x2E, 0x4D,
+  0x40, 0x41, 0x45, 0xA9, 0xA1, 0x9B, 0x9E, 0x9C,
+  0x95, 0x8A, 0x94, 0x89, 0x96, 0x87, 0x9C, 0x9A,
+  0x84, 0x9D, 0x9C, 0x9E, 0x9A, 0x9C, 0x9D, 0xBB,
+  0x23, 0x23, 0x22, 0x22, 0x21, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x23, 0x22, 0x21, 0x23, 0x23,
+  0x24, 0xFC, 0xFC, 0xF6, 0xBF, 0xA6, 0x9F, 0x99,
+  0x89, 0x95, 0x87, 0x94, 0x9D, 0x9E, 0x97, 0x9E,
+  0x95, 0x9B, 0x89, 0x95, 0x95, 0x9B, 0x89, 0x87,
+  0x5D, 0x56, 0x3E, 0x51, 0x3E, 0x60, 0xCF, 0xD3,
+  0xD2, 0xCD, 0x5C, 0x49, 0x4B, 0x3E, 0x2C, 0x48,
+  0x3E, 0x43, 0x3E, 0xA9, 0xA1, 0x9B, 0x97, 0x94,
+  0x95, 0x9A, 0x9C, 0x87, 0x87, 0x9B, 0x9C, 0x95,
+  0x9D, 0x89, 0x9A, 0x89, 0x9E, 0x9E, 0x8C, 0xA6,
+  0x20, 0x23, 0x23, 0x22, 0x23, 0x22, 0x23, 0x22,
+  0x22, 0x22, 0x22, 0x22, 0x21, 0x21, 0x20, 0x40,
+  0xFC, 0xFC, 0xFC, 0xEC, 0xBE, 0xA4, 0x9F, 0x99,
+  0x95, 0x9F, 0xA0, 0x88, 0x9D, 0x8B, 0x97, 0x95,
+  0x87, 0x95, 0x96, 0x95, 0x97, 0x94, 0x94, 0x98,
+  0xD3, 0x4C, 0x47, 0x4D, 0x42, 0x4C, 0x60, 0xCC,
+  0xCE, 0xD0, 0x65, 0x4B, 0x47, 0x44, 0x2B, 0x45,
+  0x4B, 0x47, 0x49, 0xA7, 0xA1, 0x9A, 0x97, 0x89,
+  0x95, 0x97, 0x97, 0x9E, 0x89, 0x95, 0x89, 0x9C,
+  0x87, 0x95, 0x97, 0x99, 0x95, 0x99, 0x9F, 0xA4,
+  0xC4, 0x21, 0x21, 0x23, 0x21, 0x23, 0x23, 0x23,
+  0x23, 0x23, 0x23, 0x23, 0x21, 0x20, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xEA, 0xAA, 0xA6, 0xA2, 0x99,
+  0x8B, 0x9A, 0x95, 0x9E, 0x9E, 0x9A, 0x94, 0x87,
+  0x94, 0x94, 0x89, 0x94, 0x9B, 0x9B, 0xA7, 0xDC,
+  0xDB, 0x65, 0x2E, 0x3E, 0x43, 0x44, 0x49, 0x58,
+  0x63, 0xD3, 0xD3, 0x5E, 0x42, 0x42, 0x2D, 0x40,
+  0x54, 0x4C, 0x4A, 0xA7, 0xA0, 0x99, 0x9B, 0x94,
+  0xA0, 0x8A, 0x9B, 0x9D, 0x87, 0x95, 0x94, 0x8B,
+  0x8A, 0x98, 0x9C, 0x8A, 0x9B, 0x99, 0xA2, 0xA6,
+  0xBF, 0xEC, 0x2A, 0x20, 0x21, 0x23, 0x21, 0x20,
+  0x20, 0x20, 0x20, 0x4C, 0xF9, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xEB, 0xAA, 0xA4, 0x9F, 0x9C,
+  0x8B, 0x9B, 0x88, 0x84, 0x9E, 0x9D, 0x96, 0x94,
+  0x94, 0x9A, 0x9B, 0x9B, 0xA4, 0xD5, 0xCD, 0xDE,
+  0xF1, 0xDA, 0x4C, 0x2D, 0x41, 0x2B, 0x42, 0x4C,
+  0x5E, 0xD4, 0xD7, 0xCD, 0x49, 0x2E, 0x2E, 0x41,
+  0x5E, 0x57, 0xA7, 0xA6, 0xA7, 0xA4, 0xA2, 0x98,
+  0x9D, 0x9C, 0xA1, 0x99, 0x9D, 0x88, 0x8B, 0x9C,
+  0x8A, 0x9C, 0x9C, 0x94, 0x9C, 0x89, 0xA0, 0xA6,
+  0xAA, 0xEB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFB, 0xE9, 0xAA, 0xA6, 0xA2, 0x8B,
+  0x8B, 0x8A, 0x86, 0x9B, 0x9C, 0x98, 0xA0, 0x9B,
+  0x9B, 0x84, 0xA7, 0xB4, 0x61, 0xD1, 0xD2, 0xE0,
+  0xF1, 0xDC, 0x61, 0x2D, 0x2E, 0x3F, 0x56, 0x62,
+  0x5D, 0xD4, 0xD9, 0xD3, 0x54, 0x41, 0x41, 0x44,
+  0xCB, 0x60, 0x52, 0xA9, 0xA9, 0xA9, 0xA7, 0xA6,
+  0xA6, 0xA4, 0xA4, 0xA2, 0xA2, 0x9D, 0x95, 0x89,
+  0x9C, 0x8A, 0x9E, 0x9C, 0x8A, 0x9E, 0xA0, 0xA8,
+  0xC0, 0xE9, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xE9, 0xAA, 0xA6, 0xA0, 0x99,
+  0x9C, 0x8B, 0x9A, 0x84, 0x9B, 0x9B, 0x98, 0x98,
+  0xA9, 0xB9, 0x49, 0x57, 0xCB, 0xD4, 0xD3, 0xF1,
+  0xD8, 0xDA, 0xCE, 0x3F, 0x41, 0x4B, 0x5D, 0xCB,
+  0x5E, 0xD6, 0xDB, 0xD6, 0x5D, 0x43, 0x3F, 0x49,
+  0xD1, 0xCC, 0x4F, 0xDD, 0xC3, 0xBB, 0xBF, 0xAA,
+  0xAA, 0xA9, 0xAA, 0xA8, 0xA8, 0xA6, 0xA6, 0xA2,
+  0x9C, 0x9F, 0x9B, 0x9A, 0x9D, 0xA2, 0xA8, 0xAA,
+  0xC1, 0xEA, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xEA, 0xC0, 0xAA, 0xA6, 0xA2,
+  0xA2, 0x99, 0xA0, 0xA0, 0xA4, 0xA7, 0xA9, 0xC0,
+  0x67, 0x49, 0x54, 0x60, 0xD0, 0xD4, 0xCC, 0xDF,
+  0xD9, 0xD5, 0xD2, 0x3E, 0x47, 0x56, 0x60, 0xCD,
+  0x5D, 0xD9, 0xD9, 0xD6, 0x61, 0x3F, 0x47, 0x52,
+  0xD6, 0xD3, 0x62, 0x4D, 0x40, 0x4A, 0x57, 0xCA,
+  0xC3, 0xC1, 0xC1, 0xC0, 0xBF, 0xBF, 0xAA, 0xAA,
+  0xA6, 0xA4, 0xA4, 0xA4, 0xA6, 0xA8, 0xBE, 0xC1,
+  0xC9, 0xEB, 0xFB, 0xFB, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+  0xFC, 0xFC, 0xFC, 0xEB, 0xC3, 0xC0, 0xAA, 0xA8,
+  0xA6, 0xA6, 0xA6, 0xA9, 0xAA, 0xC0, 0xE8, 0xD0,
+  0xD2, 0x4C, 0x5E, 0x64, 0xD0, 0xD1, 0x5F, 0xD9,
+  0xD5, 0xD1, 0xD0, 0x48, 0x52, 0x5C, 0x64, 0xCD,
+  0x5C, 0xDC, 0xD7, 0xD5, 0x62, 0x3F, 0x4C, 0x53,
+  0xDA, 0xD7, 0xCE, 0x56, 0x40, 0x4B, 0x52, 0x56,
+  0xCE, 0xDF, 0x6A, 0xEB, 0xE9, 0xC9, 0xC3, 0xC0,
+  0xC0, 0xBF, 0xBE, 0xAA, 0xBF, 0xC0, 0xC3, 0xC9,
+  0xEA, 0xF6, 0xEE, 0x58, 0x57, 0x5E, 0xD6, 0xD0,
+  0xD2, 0x61, 0xCB, 0xD6, 0xD6, 0xD4, 0xDF, 0xF3,
+  0xF2, 0xDD, 0xD7, 0xEB, 0xC9, 0xC1, 0xC0, 0xBF,
+  0xAA, 0xAA, 0xAA, 0xBE, 0xC3, 0xF0, 0xD2, 0xD2,
+  0xD2, 0x51, 0x62, 0xCC, 0xD0, 0xCC, 0x61, 0xD3,
+  0xCF, 0xCE, 0xD2, 0x48, 0x5A, 0x61, 0xCC, 0xCE,
+  0x5F, 0xD9, 0xD5, 0xD1, 0x63, 0x44, 0x56, 0x56,
+  0xDC, 0xD9, 0xD4, 0x5E, 0x42, 0x4A, 0x4C, 0x57,
+  0x5D, 0xD8, 0xE0, 0xD8, 0xDC, 0xCB, 0x66, 0xEC,
+  0xE8, 0xC3, 0xC3, 0xC3, 0xC3, 0xC9, 0xE8, 0xEA,
+  0xF6, 0x50, 0x3E, 0x58, 0x57, 0x5A, 0xD6, 0xD4,
+  0xCC, 0x4B, 0x53, 0x5C, 0x64, 0xD1, 0xDF, 0xF3,
+  0xF1, 0xDE, 0xD9, 0xF6, 0xEB, 0xC9, 0xC1, 0xC1,
+  0xC0, 0xC0, 0xC1, 0xC9, 0xF0, 0xD6, 0xCD, 0xD6,
+  0xD3, 0x53, 0xCB, 0xCF, 0xCD, 0x5F, 0x5F, 0xCE,
+  0xCF, 0xCD, 0xD0, 0x47, 0x5F, 0xCB, 0xCE, 0xCD,
+  0x63, 0xD6, 0xD3, 0xD1, 0x63, 0x3F, 0x58, 0x58,
+  0xDB, 0xDC, 0xDA, 0x65, 0x3E, 0x49, 0x49, 0x4D,
+  0x49, 0xDC, 0xDF, 0xE0, 0xDE, 0xD5, 0x47, 0x47,
+  0x46, 0x6B, 0xEB, 0xEA, 0xE9, 0xEA, 0xEB, 0xF6,
+  0xD0, 0x57, 0x57, 0x47, 0x47, 0x5B, 0xD4, 0xD4,
+  0xCD, 0x44, 0x3E, 0x4B, 0x50, 0x4B, 0x51, 0xD5,
+  0xDB, 0xD8, 0xDE, 0x4B, 0xF6, 0xF6, 0xEA, 0xE9,
+  0xE8, 0xEA, 0xEB, 0x67, 0x5E, 0xCC, 0xD6, 0xDC,
+  0xD5, 0x58, 0xCE, 0xCE, 0x62, 0x50, 0xCC, 0xD3,
+  0xD2, 0xCD, 0xCD, 0x4B, 0x64, 0xCE, 0xCE, 0x64,
+  0xCC, 0xD3, 0xD2, 0xD2, 0x61, 0x47, 0x5D, 0x5C,
+  0xDD, 0xDD, 0xD9, 0xD1, 0x4C, 0x47, 0x49, 0x4A,
+  0x4B, 0xD1, 0xD8, 0xE0, 0xDF, 0xDD, 0x5D, 0x4A,
+  0x48, 0x52, 0x51, 0x3F, 0xF6, 0xEC, 0xE0, 0xE0,
+  0xD3, 0x5E, 0x5F, 0x50, 0x4B, 0x50, 0xCB, 0xCE,
+  0x64, 0x45, 0x4C, 0x57, 0x57, 0x58, 0x52, 0xD6,
+  0xD3, 0xDE, 0xDF, 0xD1, 0x3E, 0x4B, 0xF6, 0xF6,
+  0xEC, 0x66, 0x53, 0x43, 0x56, 0xD1, 0xD9, 0xDE,
+  0xD4, 0x5E, 0xCE, 0xCC, 0x5B, 0x2C, 0xD4, 0xD5,
+  0xD2, 0xD0, 0x63, 0x5D, 0xCD, 0xD0, 0xCD, 0x5E,
+  0xD0, 0xCF, 0xCE, 0xD2, 0x5E, 0x50, 0x60, 0x5D,
+  0xDE, 0xDD, 0xDC, 0xD7, 0x5D, 0x45, 0x47, 0x3E,
+  0x4B, 0x5E, 0xDE, 0xDF, 0xE0, 0xD8, 0xCF, 0x3E,
+  0x45, 0x51, 0x58, 0x42, 0xCB, 0xDA, 0xDE, 0xD8,
+  0xD2, 0x61, 0xCC, 0xCF, 0xD6, 0xDA, 0xDA, 0xD5,
+  0xD0, 0x50, 0x44, 0x57, 0x57, 0x58, 0x45, 0xD1,
+  0xD1, 0xD7, 0xDF, 0xDF, 0xD7, 0xCF, 0x64, 0x60,
+  0xCE, 0xCE, 0xCE, 0x63, 0xCF, 0xDA, 0xDE, 0xD9,
+  0xCF, 0x63, 0xCD, 0x63, 0x4D, 0x4B, 0xD6, 0xD5,
+  0xCE, 0xD3, 0x60, 0xCB, 0xD0, 0xD0, 0x65, 0x47,
+  0xD0, 0xCC, 0xCC, 0xD1, 0x59, 0x5D, 0x63, 0x5E,
+  0xDD, 0xDD, 0xDE, 0xDC, 0xCB, 0x40, 0x48, 0x45,
+  0x3E, 0x3E, 0xD9, 0xDF, 0xE0, 0xDF, 0xDA, 0x51,
+  0x4C, 0x48, 0x56, 0x4C, 0x5B, 0xD2, 0xDA, 0xDB,
+  0xCB, 0x5F, 0xD0, 0xCC, 0xDC, 0xF0, 0xF3, 0xE0,
+  0xDD, 0xCC, 0x41, 0x50, 0x57, 0x57, 0x4B, 0x5D,
+  0xD3, 0xD1, 0xDE, 0xDF, 0xDE, 0xD7, 0xD0, 0xD0,
+  0xD5, 0xD6, 0xD6, 0xCE, 0xD7, 0xDC, 0xDA, 0xD5,
+  0x60, 0x63, 0x64, 0x5E, 0x47, 0x61, 0xD5, 0xD2,
+  0xCF, 0xD0, 0x59, 0xCD, 0xD1, 0xCF, 0x61, 0x4D,
+  0xCC, 0xCE, 0xCD, 0xD0, 0x52, 0x61, 0x64, 0x60,
+  0xDA, 0xDE, 0xDE, 0xDD, 0xD1, 0x4B, 0x4A, 0x45,
+  0x3E, 0x41, 0xCD, 0xDE, 0xE0, 0xF1, 0xDE, 0x63,
+  0x4A, 0x4A, 0x4A, 0x4B, 0x50, 0xCB, 0xD4, 0xD7,
+  0x5E, 0x54, 0x62, 0xD3, 0xD4, 0xF0, 0xF3, 0xF3,
+  0xF2, 0xDE, 0x61, 0x40, 0x49, 0x56, 0x4D, 0x3E,
+  0x4B, 0xCE, 0xD9, 0xD8, 0xD9, 0xD5, 0xCF, 0xD2,
+  0xD6, 0xD6, 0xD1, 0xD1, 0xD7, 0xD5, 0xCF, 0xD0,
+  0x54, 0x64, 0x63, 0x56, 0x2C, 0xCB, 0xD1, 0xCC,
+  0xD3, 0xCD, 0x54, 0xCF, 0xD1, 0xCE, 0x5E, 0x5C,
+  0xCE, 0xCE, 0xCE, 0xCB, 0x4B, 0x63, 0xCC, 0x61,
+  0xD4, 0xDC, 0xDE, 0xDE, 0xDA, 0x5D, 0x45, 0x45,
+  0x48, 0x3F, 0x52, 0xD9, 0xD8, 0xDF, 0xDF, 0xD2,
+  0x52, 0x4B, 0x3E, 0x2E, 0x47, 0x60, 0xCF, 0xD3,
+  0x59, 0x48, 0x50, 0x5E, 0xCC, 0xDE, 0xF2, 0xF2,
+  0xF3, 0xF3, 0xDD, 0x5D, 0x3E, 0x48, 0x47, 0x47,
+  0x58, 0xD1, 0xDA, 0xDA, 0xD5, 0xD1, 0xCD, 0xD2,
+  0xD3, 0xCF, 0xD3, 0xD1, 0xCD, 0xD3, 0xD2, 0x5E,
+  0x52, 0x64, 0x60, 0x4B, 0x45, 0x61, 0xCD, 0xD3,
+  0xD3, 0x64, 0x61, 0xD0, 0xD0, 0x64, 0x45, 0x63,
+  0xD0, 0xCE, 0xD0, 0x60, 0x56, 0xCB, 0xCC, 0x62,
+  0xCE, 0xDA, 0xDE, 0xD8, 0xDD, 0xCC, 0x45, 0x49,
+  0x3E, 0x47, 0x42, 0xD1, 0xDC, 0xD8, 0xD8, 0xD3,
+  0x5D, 0x4C, 0x49, 0x3F, 0x47, 0x59, 0xCD, 0xCF,
+  0x59, 0x2E, 0x48, 0x47, 0x52, 0x63, 0xF0, 0xF2,
+  0xF3, 0xF3, 0xF2, 0xDA, 0x52, 0x4B, 0x52, 0x58,
+  0x5E, 0x63, 0xD0, 0xD0, 0xD0, 0xCF, 0xCE, 0xCE,
+  0xCF, 0x65, 0x61, 0xD6, 0xD6, 0xD6, 0xCB, 0x4B,
+  0x61, 0x62, 0x5D, 0x43, 0x4B, 0x61, 0xD0, 0xD4,
+  0xD1, 0x61, 0xCE, 0xD2, 0xCD, 0x5E, 0x4A, 0xCE,
+  0xD0, 0xCC, 0xD0, 0x59, 0x61, 0xCC, 0xCC, 0x62,
+  0xD1, 0xD5, 0xDE, 0xD8, 0xDD, 0xCF, 0x4B, 0x4A,
+  0x45, 0x3E, 0x2D, 0xCB, 0xDC, 0xDE, 0xD8, 0xD5,
+  0x60, 0x54, 0x51, 0x4C, 0x4D, 0x5C, 0xCC, 0xCE,
+  0x5A, 0x2C, 0x50, 0x53, 0x3E, 0x59, 0xD8, 0xF3,
+  0xF2, 0xF3, 0xF3, 0xE0, 0x5E, 0x4A, 0x4C, 0x53,
+  0x5E, 0x63, 0xCC, 0xCC, 0xCC, 0xCD, 0xCF, 0xD3,
+  0x62, 0x53, 0xD6, 0xD6, 0xD6, 0xD6, 0x5B, 0x48,
+  0x64, 0x63, 0x59, 0x44, 0x57, 0x63, 0xD2, 0xD3,
+  0xD0, 0x5E, 0xD0, 0xD1, 0xCB, 0x58, 0x4C, 0xCF,
+  0xCF, 0xCE, 0xCE, 0x57, 0x63, 0xCC, 0xCD, 0x57,
+};
+
+unsigned char linux_logo_bw[] __initdata = {
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x3F,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F,
+  0xFE, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFE, 0x3F, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFE, 0x7F, 0xFF, 0xC7, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xC3,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF,
+  0xFB, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFD, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xF1,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF,
+  0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xF9, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xF9, 0xCF, 0xC3, 0xF8, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x87, 0x81, 0xF9,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xA7,
+  0x99, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xF9, 0xF3, 0xBC, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xF9, 0xE3, 0xBC, 0xF9, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xB0, 0x3C, 0xF9,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xB0,
+  0x19, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xF9, 0xC0, 0x03, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xF9, 0x80, 0x01, 0xF8, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x80, 0x01, 0xF8,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0x80,
+  0x01, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xF9, 0xC0, 0x21, 0xD8, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xF9, 0xB1, 0x80, 0xEC, 0xC0, 0x1F,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x90, 0x00, 0xE4,
+  0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1, 0x8C,
+  0xC0, 0x7C, 0x04, 0x81, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xE3, 0x80, 0x00, 0x7C, 0x40, 0x11, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xE3, 0x80, 0x00, 0x7F, 0xD2, 0x29,
+  0xFF, 0xFF, 0xFF, 0xFF, 0x87, 0x00, 0x00, 0x3F,
+  0x80, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0x0E, 0x00,
+  0x00, 0x3F, 0x80, 0x19, 0xFF, 0xFF, 0xFF, 0xFF,
+  0x1E, 0x00, 0x00, 0x1F, 0x80, 0x19, 0xFF, 0xFF,
+  0xFF, 0xFE, 0x1C, 0x00, 0x00, 0x1E, 0x80, 0x19,
+  0xFF, 0xFF, 0xFF, 0xFE, 0x3C, 0x00, 0x00, 0x1E,
+  0x80, 0x11, 0xFF, 0xFF, 0xFF, 0xFC, 0x7C, 0x00,
+  0x00, 0x0F, 0x80, 0x11, 0xFF, 0xFF, 0xFF, 0xFC,
+  0xF8, 0x00, 0x00, 0x0E, 0x80, 0x11, 0xFF, 0xFF,
+  0xFF, 0xFC, 0xF8, 0x00, 0x00, 0x06, 0x00, 0x11,
+  0xFF, 0xFF, 0xFF, 0xF8, 0xF8, 0x00, 0x00, 0x06,
+  0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xF9, 0xF0, 0x00,
+  0x00, 0x02, 0x00, 0x09, 0xFF, 0xFF, 0xFF, 0xF1,
+  0xF0, 0x00, 0x00, 0x02, 0x80, 0x10, 0xFF, 0xFF,
+  0xFF, 0xF1, 0xE0, 0x00, 0x00, 0x00, 0x97, 0x10,
+  0xFF, 0xFF, 0xFF, 0xE3, 0xE0, 0x00, 0x00, 0x00,
+  0xDF, 0xF0, 0xFF, 0xFF, 0xFF, 0xE3, 0xC0, 0x00,
+  0x00, 0x00, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xC7,
+  0xC0, 0x00, 0x00, 0x01, 0xFF, 0xF8, 0xFF, 0xFF,
+  0xFF, 0xC7, 0x80, 0x00, 0x00, 0x01, 0xFF, 0xF8,
+  0xFF, 0xFF, 0xFF, 0x8F, 0x80, 0x00, 0x00, 0x01,
+  0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x8F, 0x80, 0x00,
+  0x00, 0x01, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0x9F,
+  0x80, 0x00, 0x00, 0x01, 0xFF, 0xF8, 0xFF, 0xFF,
+  0xFF, 0x9F, 0x80, 0x00, 0x00, 0x01, 0x80, 0x18,
+  0xFF, 0xFF, 0xFF, 0x9E, 0x80, 0x00, 0x00, 0x03,
+  0xA8, 0x11, 0xFF, 0xFF, 0xFF, 0x9F, 0x80, 0x00,
+  0x00, 0x02, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x99,
+  0x80, 0x00, 0x00, 0x00, 0x00, 0x09, 0xFF, 0xFF,
+  0xFF, 0x00, 0x80, 0x00, 0x00, 0x01, 0xC0, 0x01,
+  0xFF, 0xFF, 0xFE, 0x20, 0x60, 0x00, 0x00, 0x00,
+  0xFF, 0xC3, 0xFF, 0xFF, 0xF8, 0x00, 0x30, 0x00,
+  0x00, 0x00, 0xFF, 0x0F, 0xFF, 0xFF, 0xC0, 0x40,
+  0x38, 0x00, 0x00, 0x00, 0xFE, 0x47, 0xFF, 0xFF,
+  0x81, 0x00, 0x1C, 0x00, 0x00, 0x00, 0xFC, 0x23,
+  0xFF, 0xFF, 0x90, 0x00, 0x1E, 0x00, 0x00, 0x00,
+  0x78, 0x11, 0xFF, 0xFF, 0x80, 0x00, 0x0F, 0x80,
+  0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00,
+  0x07, 0xC0, 0x00, 0x00, 0x00, 0x08, 0xFF, 0xFF,
+  0xC0, 0x00, 0x07, 0xC0, 0x00, 0x00, 0x00, 0x04,
+  0x7F, 0xFF, 0x80, 0x00, 0x03, 0xC0, 0x00, 0x10,
+  0x00, 0x00, 0x1F, 0xFF, 0x80, 0x00, 0x01, 0x80,
+  0x00, 0x30, 0x00, 0x00, 0x0F, 0xFF, 0x80, 0x00,
+  0x00, 0x00, 0x00, 0x70, 0x00, 0x01, 0x4F, 0xFF,
+  0x80, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00,
+  0x0F, 0xFF, 0xC0, 0x00, 0x00, 0x80, 0x03, 0xF0,
+  0x00, 0x00, 0x8F, 0xFF, 0x80, 0x00, 0x00, 0x40,
+  0x0F, 0xF0, 0x00, 0x04, 0x1F, 0xFF, 0x80, 0x00,
+  0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x10, 0x1F, 0xFF,
+  0xC0, 0x00, 0x00, 0x7F, 0xFF, 0xF0, 0x00, 0x40,
+  0xFF, 0xFF, 0x98, 0x00, 0x00, 0xFF, 0xFF, 0xF0,
+  0x00, 0x83, 0xFF, 0xFF, 0x81, 0xE0, 0x01, 0xFF,
+  0xFF, 0xF8, 0x02, 0x07, 0xFF, 0xFF, 0x80, 0x3F,
+  0x07, 0xE0, 0x00, 0x1C, 0x0C, 0x1F, 0xFF, 0xFF,
+  0xF8, 0x03, 0xFF, 0x80, 0x00, 0x1F, 0x78, 0x1F,
+  0xFF, 0xFF, 0xFF, 0x80, 0x7F, 0x00, 0x07, 0x0F,
+  0xF0, 0x7F, 0xFF, 0xFF, 0xFF, 0xFE, 0x0C, 0x07,
+  0xFF, 0x83, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0x00, 0x1F, 0xFF, 0xC0, 0x03, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x07, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+};
+
+/* Painted by Johnny Stenback <jst@uwasa.fi> */
+
+unsigned char *linux_serial_image __initdata = "\n"
+"         .u$e.\n"
+"       .$$$$$:S\n"
+"       $\"*$/\"*$$\n"
+"       $.`$ . ^F\n"
+"       4k+#+T.$F\n"
+"       4P+++\"$\"$\n"
+"       :R\"+  t$$B\n"
+"    ___#       $$$\n"
+"    |  |       R$$k\n"
+"   dd. | Linux  $!$\n"
+"   ddd |  Sparc $9$F\n"
+" '!!!!!$       !!#!`\n"
+"  !!!!!*     .!!!!!`\n"
+"'!!!!!!!W..e$$!!!!!!`    %s\n"
+" \"~^^~         ^~~^\n"
+"\n";
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/openprom.c linux/drivers/sbus/char/openprom.c
--- v2.1.15/linux/drivers/sbus/char/openprom.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/openprom.c	Fri Dec 13 11:37:32 1996
@@ -0,0 +1,610 @@
+/*
+ * Linux/SPARC PROM Configuration Driver
+ * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
+ * Copyright (C) 1996 Eddie C. Dost  (ecd@skynet.be)
+ *
+ * This character device driver allows user programs to access the
+ * PROM device tree. It is compatible with the SunOS /dev/openprom
+ * driver and the NetBSD /dev/openprom driver. The SunOS eeprom
+ * utility works without any modifications.
+ *
+ * The driver uses a minor number under the misc device major. The
+ * file read/write mode determines the type of access to the PROM.
+ * Interrupts are disabled whenever the driver calls into the PROM for
+ * sanity's sake.
+ */
+
+/* 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. 
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <asm/oplib.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <linux/openpromio.h>
+
+/* Private data kept by the driver for each descriptor. */
+typedef struct openprom_private_data
+{
+	int current_node;	/* Current node for SunOS ioctls. */
+	int lastnode;		/* Last valid node used by BSD ioctls. */
+} DATA;
+
+/* ID of the PROM node containing all of the EEPROM options. */
+static int options_node = 0;
+
+/*
+ * Copy an openpromio structure into kernel space from user space.
+ * This routine does error checking to make sure that all memory
+ * accesses are within bounds. A pointer to the allocated openpromio
+ * structure will be placed in "*opp_p". Return value is the length
+ * of the user supplied buffer.
+ */
+static int copyin(struct openpromio *info, struct openpromio **opp_p)
+{
+	int bufsize;
+
+	if (!info || !opp_p)
+		return -EFAULT;
+
+	get_user_ret(bufsize, &info->oprom_size, -EFAULT);
+
+	if (bufsize == 0 || bufsize > OPROMMAXPARAM)
+		return -EINVAL;
+
+	if (!(*opp_p = kmalloc(sizeof(int) + bufsize + 1, GFP_KERNEL)))
+		return -ENOMEM;
+	memset(*opp_p, 0, sizeof(int) + bufsize + 1);
+
+	if (copy_from_user(&(*opp_p)->oprom_array,
+			   &info->oprom_array, bufsize)) {
+		kfree(*opp_p);
+		return -EFAULT;
+	}
+	return bufsize;
+}
+
+static int getstrings(struct openpromio *info, struct openpromio **opp_p)
+{
+	int n, bufsize;
+	char c;
+
+	if (!info || !opp_p)
+		return -EFAULT;
+
+	if (!(*opp_p = kmalloc(sizeof(int) + OPROMMAXPARAM + 1, GFP_KERNEL)))
+		return -ENOMEM;
+
+	memset(*opp_p, 0, sizeof(int) + OPROMMAXPARAM + 1);
+	(*opp_p)->oprom_size = 0;
+
+	n = bufsize = 0;
+	while ((n < 2) && (bufsize < OPROMMAXPARAM)) {
+		if (get_user(c, &info->oprom_array[bufsize])) {
+			kfree(*opp_p);
+			return -EFAULT;
+		}
+		if (c == '\0')
+			n++;
+		(*opp_p)->oprom_array[bufsize++] = c;
+	}
+	if (!n) {
+		kfree(*opp_p);
+		return -EINVAL;
+	}
+	return bufsize;
+}
+
+/*
+ * Copy an openpromio structure in kernel space back to user space.
+ */
+static int copyout(void *info, struct openpromio *opp, int len)
+{
+	copy_to_user_ret(info, opp, len, -EFAULT);
+	return 0;
+}
+
+/*
+ *	SunOS and Solaris /dev/openprom ioctl calls.
+ */
+static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
+				unsigned int cmd, unsigned long arg, int node)
+{
+	DATA *data = (DATA *) file->private_data;
+	char buffer[OPROMMAXPARAM+1], *buf;
+	struct openpromio *opp;
+	unsigned long flags;
+	int bufsize, len, error = 0;
+
+	if (cmd == OPROMSETOPT)
+		bufsize = getstrings((void *)arg, &opp);
+	else
+		bufsize = copyin((void *)arg, &opp);
+
+	if (bufsize < 0)
+		return bufsize;
+
+	switch (cmd) {
+	case OPROMGETOPT:
+	case OPROMGETPROP:
+		save_and_cli(flags);
+		len = prom_getproplen(node, opp->oprom_array);
+		restore_flags(flags);
+
+		if (len <= 0 || len > bufsize) {
+			error = copyout((void *)arg, opp, sizeof(int));
+			break;
+		}
+
+		save_and_cli(flags);
+		len = prom_getproperty(node, opp->oprom_array, buffer, bufsize);
+		restore_flags(flags);
+
+		memcpy(opp->oprom_array, buffer, len);
+		opp->oprom_array[len] = '\0';
+		opp->oprom_size = len;
+
+		error = copyout((void *)arg, opp, sizeof(int) + bufsize);
+		break;
+
+	case OPROMNXTOPT:
+	case OPROMNXTPROP:
+		save_and_cli(flags);
+		buf = prom_nextprop(node, opp->oprom_array);
+		restore_flags(flags);
+
+		len = strlen(buf);
+		if (len == 0 || len + 1 > bufsize) {
+			error = copyout((void *)arg, opp, sizeof(int));
+			break;
+		}
+
+		memcpy(opp->oprom_array, buf, len);
+		opp->oprom_array[len] = '\0';
+		opp->oprom_size = ++len;
+
+		error = copyout((void *)arg, opp, sizeof(int) + bufsize);
+		break;
+
+	case OPROMSETOPT:
+	case OPROMSETOPT2:
+		buf = opp->oprom_array + strlen(opp->oprom_array) + 1;
+		len = opp->oprom_array + bufsize - buf;
+
+		printk(KERN_DEBUG "OPROMSETOPT%s %s='%s'\n",
+		       (cmd == OPROMSETOPT) ? "" : "2", opp->oprom_array, buf);
+
+		save_and_cli(flags);
+		error = prom_setprop(options_node, opp->oprom_array,
+				     buf, len);
+		restore_flags(flags);
+
+		if (error <= 0)
+			error = -EINVAL;
+		break;
+
+	case OPROMNEXT:
+	case OPROMCHILD:
+		if (bufsize < sizeof(int)) {
+			error = -EINVAL;
+			break;
+		}
+
+		node = *((int *) opp->oprom_array);
+
+		save_and_cli(flags);
+		if (cmd == OPROMNEXT)
+			node = prom_nodeops->no_nextnode(node);
+		else
+			node = prom_nodeops->no_child(node);
+		restore_flags(flags);
+
+		data->current_node = node;
+		*((int *)opp->oprom_array) = node;
+		opp->oprom_size = sizeof(int);
+
+		error = copyout((void *)arg, opp, bufsize + sizeof(int));
+		break;
+
+	case OPROMGETBOOTARGS:
+		save_and_cli(flags);
+		buf = prom_getbootargs();
+		restore_flags(flags);
+
+		len = strlen(buf);
+
+		if (len > bufsize) {
+			error = -EINVAL;
+			break;
+		}
+
+		strcpy(opp->oprom_array, buf);
+		opp->oprom_size = len;
+
+		error = copyout((void *)arg, opp, bufsize + sizeof(int));
+		break;
+
+	case OPROMU2P:
+	case OPROMGETCONS:
+	case OPROMGETFBNAME:
+		printk(KERN_INFO "openprom_sunos_ioctl: unimplemented ioctl\n");
+		error = -EINVAL;
+		break;
+	default:
+		printk(KERN_INFO "openprom_sunos_ioctl: cmd 0x%X, arg 0x%lX\n", cmd, arg);
+		error = -EINVAL;
+		break;
+	}
+
+	kfree(opp);
+	return error;
+}
+
+
+/* Return nonzero if a specific node is in the PROM device tree. */
+static int intree(int root, int node)
+{
+	for (; root != 0; root = prom_getsibling(root))
+		if (root == node || intree(prom_getchild(root),node))
+			return 1;
+	return 0;
+}
+
+/* Return nonzero if a specific node is "valid". */
+static int goodnode(int n, DATA *data)
+{
+	if (n == data->lastnode || n == prom_root_node || n == options_node)
+		return 1;
+	if (n == 0 || n == -1 || !intree(prom_root_node,n))
+		return 0;
+	data->lastnode = n;
+	return 1;
+}
+
+/* Copy in a whole string from userspace into kernelspace. */
+static int copyin_string(char *user, size_t len, char **ptr)
+{
+	char *tmp;
+
+	tmp = kmalloc(len + 1, GFP_KERNEL);
+	if (!tmp)
+		return -ENOMEM;
+
+	if(copy_from_user(tmp, user, len)) {
+		kfree(tmp);
+		return -EFAULT;
+	}
+
+	tmp[len] = '\0';
+
+	*ptr = tmp;
+
+	return 0;
+}
+
+/*
+ *	NetBSD /dev/openprom ioctl calls.
+ */
+static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
+			      unsigned int cmd, unsigned long arg)
+{
+	DATA *data = (DATA *) file->private_data;
+	struct opiocdesc op;
+	unsigned long flags;
+	int error, node, len;
+	char *str, *tmp;
+
+	switch (cmd) {
+	case OPIOCGET:
+		copy_from_user_ret(&op, (void *)arg, sizeof(op), -EFAULT);
+
+		if (!goodnode(op.op_nodeid,data))
+			return -EINVAL;
+
+		error = copyin_string(op.op_name, op.op_namelen, &str);
+		if (error)
+			return error;
+
+		save_and_cli(flags);
+		len = prom_getproplen(op.op_nodeid,str);
+		restore_flags(flags);
+
+		if (len > op.op_buflen) {
+			kfree(str);
+			return -ENOMEM;
+		}
+
+		op.op_buflen = len;
+
+		if (len <= 0) {
+			kfree(str);
+			/* Verified by the above copy_from_user_ret */
+			__copy_to_user_ret((void *)arg, &op,
+					   sizeof(op), -EFAULT);
+			return 0;
+		}
+
+		tmp = kmalloc(len + 1, GFP_KERNEL);
+		if (!tmp) {
+			kfree(str);
+			return -ENOMEM;
+		}
+
+		save_and_cli(flags);
+		prom_getproperty(op.op_nodeid, str, tmp, len);
+		restore_flags(flags);
+
+		tmp[len] = '\0';
+
+		error = __copy_to_user((void *)arg, &op, sizeof(op));
+		if (!error)
+			error = copy_to_user(op.op_buf, tmp, len);
+
+		kfree(tmp);
+		kfree(str);
+
+		return error;
+
+	case OPIOCNEXTPROP:
+		copy_from_user_ret(&op, (void *)arg, sizeof(op), -EFAULT);
+
+		if (!goodnode(op.op_nodeid,data))
+			return -EINVAL;
+
+		error = copyin_string(op.op_name, op.op_namelen, &str);
+		if (error)
+			return error;
+
+		save_and_cli(flags);
+		tmp = prom_nextprop(op.op_nodeid,str);
+		restore_flags(flags);
+
+		if (tmp) {
+			len = strlen(tmp);
+			if (len > op.op_buflen)
+				len = op.op_buflen;
+			else
+				op.op_buflen = len;
+		} else {
+			len = op.op_buflen = 0;
+		}
+
+		error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(op));
+		if (error) {
+			kfree(str);
+			return error;
+		}
+
+		error = verify_area(VERIFY_WRITE, op.op_buf, len);
+		if (error) {
+			kfree(str);
+			return error;
+		}
+
+		error = __copy_to_user((void *)arg, &op, sizeof(op));
+		if (!error) error = __copy_to_user(op.op_buf, tmp, len);
+
+		kfree(str);
+
+		return error;
+
+	case OPIOCSET:
+		copy_from_user_ret(&op, (void *)arg, sizeof(op), -EFAULT);
+
+		if (!goodnode(op.op_nodeid,data))
+			return -EINVAL;
+
+		error = copyin_string(op.op_name, op.op_namelen, &str);
+		if (error)
+			return error;
+
+		error = copyin_string(op.op_buf, op.op_buflen, &tmp);
+		if (error) {
+			kfree(str);
+			return error;
+		}
+
+		save_and_cli(flags);
+		len = prom_setprop(op.op_nodeid,str,tmp,op.op_buflen+1);
+		restore_flags(flags);
+
+		if (len != op.op_buflen)
+			return -EINVAL;
+
+		kfree(str);
+		kfree(tmp);
+
+		return 0;
+
+	case OPIOCGETOPTNODE:
+		copy_to_user_ret((void *)arg, &options_node,
+				 sizeof(int), -EFAULT);
+		return 0;
+
+	case OPIOCGETNEXT:
+	case OPIOCGETCHILD:
+		copy_from_user_ret(&node, (void *)arg, sizeof(int), -EFAULT);
+
+		save_and_cli(flags);
+		if (cmd == OPIOCGETNEXT)
+			node = prom_nodeops->no_nextnode(node);
+		else
+			node = prom_nodeops->no_child(node);
+		restore_flags(flags);
+
+		__copy_to_user_ret((void *)arg, &node, sizeof(int), -EFAULT);
+
+		return 0;
+
+	default:
+		printk(KERN_INFO "openprom_bsd_ioctl: cmd 0x%X\n", cmd);
+		return -EINVAL;
+
+	}
+}
+
+
+/*
+ *	Handoff control to the correct ioctl handler.
+ */
+static int openprom_ioctl(struct inode * inode, struct file * file,
+			  unsigned int cmd, unsigned long arg)
+{
+	DATA *data = (DATA *) file->private_data;
+
+	switch (cmd) {
+	case OPROMGETOPT:
+	case OPROMNXTOPT:
+		if ((file->f_mode & FMODE_READ) == 0)
+			return -EPERM;
+		return openprom_sunos_ioctl(inode, file, cmd, arg,
+					    options_node);
+
+	case OPROMSETOPT:
+	case OPROMSETOPT2:
+		if ((file->f_mode & FMODE_WRITE) == 0)
+			return -EPERM;
+		return openprom_sunos_ioctl(inode, file, cmd, arg,
+					    options_node);
+
+	case OPROMNEXT:
+	case OPROMCHILD:
+	case OPROMGETPROP:
+	case OPROMNXTPROP:
+		if ((file->f_mode & FMODE_READ) == 0)
+			return -EPERM;
+		return openprom_sunos_ioctl(inode, file, cmd, arg,
+					    data->current_node);
+
+	case OPROMU2P:
+	case OPROMGETCONS:
+	case OPROMGETFBNAME:
+	case OPROMGETBOOTARGS:
+		if ((file->f_mode & FMODE_READ) == 0)
+			return -EPERM;
+		return openprom_sunos_ioctl(inode, file, cmd, arg, 0);
+
+	case OPIOCGET:
+	case OPIOCNEXTPROP:
+	case OPIOCGETOPTNODE:
+	case OPIOCGETNEXT:
+	case OPIOCGETCHILD:
+		if ((file->f_mode & FMODE_READ) == 0)
+			return -EBADF;
+		return openprom_bsd_ioctl(inode,file,cmd,arg);
+
+	case OPIOCSET:
+		if ((file->f_mode & FMODE_WRITE) == 0)
+			return -EBADF;
+		return openprom_bsd_ioctl(inode,file,cmd,arg);
+
+	default:
+		printk("openprom_ioctl: cmd 0x%X, arg 0x%lX\n", cmd, arg);
+		return -EINVAL;
+	}
+}
+
+static long long openprom_lseek(struct inode * inode, struct file * file,
+			  long long offset, int origin)
+{
+	return -ESPIPE;
+}
+
+static int openprom_open(struct inode * inode, struct file * file)
+{
+	DATA *data;
+
+	data = (DATA *) kmalloc(sizeof(DATA), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->current_node = prom_root_node;
+	data->lastnode = prom_root_node;
+	file->private_data = (void *)data;
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+static void openprom_release(struct inode * inode, struct file * file)
+{
+	kfree_s(file->private_data, sizeof(DATA));
+	MOD_DEC_USE_COUNT;
+}
+
+static struct file_operations openprom_fops = {
+	openprom_lseek,
+	NULL,			/* openprom_read */
+	NULL,			/* openprom_write */
+	NULL,			/* openprom_readdir */
+	NULL,			/* openprom_select */
+	openprom_ioctl,
+	NULL,			/* openprom_mmap */
+	openprom_open,
+	openprom_release
+};
+
+static struct miscdevice misc_openprom = {
+	SUN_OPENPROM_MINOR, "openprom", &openprom_fops
+};
+
+__initfunc(int openprom_init(void))
+{
+	unsigned long flags;
+	int error;
+
+	error = misc_register(&misc_openprom);
+	if (error) {
+		printk(KERN_ERR "openprom: unable to get misc minor\n");
+		return error;
+	}
+
+	save_and_cli(flags);
+	options_node = prom_getchild(prom_root_node);
+	options_node = prom_searchsiblings(options_node,"options");
+	restore_flags(flags);
+
+	if (options_node == 0 || options_node == -1) {
+		printk(KERN_ERR "openprom: unable to find options node\n");
+		misc_deregister(&misc_openprom);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+	register_symtab(0);
+	return openprom_init();
+}
+
+void cleanup_module(void)
+{
+	misc_deregister(&misc_openprom);
+}
+
+#endif
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/rtc.c linux/drivers/sbus/char/rtc.c
--- v2.1.15/linux/drivers/sbus/char/rtc.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/rtc.c	Fri Dec 13 11:37:32 1996
@@ -0,0 +1,158 @@
+/* $Id: rtc.c,v 1.6 1996/11/21 16:57:50 jj Exp $
+ *
+ * Linux/SPARC Real Time Clock Driver
+ * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
+ *
+ * This is a little driver that lets a user-level program access
+ * the SPARC Mostek real time clock chip. It is no use unless you
+ * use the modified clock utility.
+ *
+ * Get the modified clock utility from:
+ *   ftp://vger.rutgers.edu/pub/linux/Sparc/userland/clock.c
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <asm/mostek.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/rtc.h>
+
+static int rtc_busy = 0;
+
+/* Retrieve the current date and time from the real time clock. */
+void get_rtc_time(struct rtc_time *t)
+{
+	register struct mostek48t02 *regs = mstk48t02_regs;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	regs->creg |= MSTK_CREG_READ;
+
+	t->sec = MSTK_REG_SEC(regs);
+	t->min = MSTK_REG_MIN(regs);
+	t->hour = MSTK_REG_HOUR(regs);
+	t->dow = MSTK_REG_DOW(regs);
+	t->dom = MSTK_REG_DOM(regs);
+	t->month = MSTK_REG_MONTH(regs);
+	t->year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) );
+
+	regs->creg &= ~MSTK_CREG_READ;
+	restore_flags(flags);
+}
+
+/* Set the current date and time inthe real time clock. */
+void set_rtc_time(struct rtc_time *t)
+{
+	register struct mostek48t02 *regs = mstk48t02_regs;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	regs->creg |= MSTK_CREG_WRITE;
+
+	MSTK_SET_REG_SEC(regs,t->sec);
+	MSTK_SET_REG_MIN(regs,t->min);
+	MSTK_SET_REG_HOUR(regs,t->hour);
+	MSTK_SET_REG_DOW(regs,t->dow);
+	MSTK_SET_REG_DOM(regs,t->dom);
+	MSTK_SET_REG_MONTH(regs,t->month);
+	MSTK_SET_REG_YEAR(regs,t->year - MSTK_YEAR_ZERO);
+
+	regs->creg &= ~MSTK_CREG_WRITE;
+	restore_flags(flags);
+}
+
+static long long rtc_lseek(struct inode *inode, struct file *file,
+	long long offset, int origin)
+{
+	return -ESPIPE;
+}
+
+static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	unsigned long arg)
+{
+	struct rtc_time rtc_tm;
+
+	switch (cmd)
+	{
+	case RTCGET:
+		get_rtc_time(&rtc_tm);
+
+		copy_to_user_ret((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time), -EFAULT);
+
+		return 0;
+
+
+	case RTCSET:
+		if (!suser())
+			return -EPERM;
+
+		copy_from_user_ret(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time), -EFAULT);
+
+		set_rtc_time(&rtc_tm);
+
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int rtc_open(struct inode *inode, struct file *file)
+{
+	if (rtc_busy)
+		return -EBUSY;
+
+	rtc_busy = 1;
+
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+static void rtc_release(struct inode *inode, struct file *file)
+{
+	MOD_DEC_USE_COUNT;
+	rtc_busy = 0;
+}
+
+static struct file_operations rtc_fops = {
+	rtc_lseek,
+	NULL,		/* rtc_read */
+	NULL,		/* rtc_write */
+	NULL,		/* rtc_readdir */
+	NULL,		/* rtc_select */
+	rtc_ioctl,
+	NULL,		/* rtc_mmap */
+	rtc_open,
+	rtc_release
+};
+
+static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops };
+
+#ifdef MODULE
+int init_module(void)
+#else
+__initfunc(int rtc_init(void))
+#endif
+{
+#ifdef MODULE
+	register_symtab(0);
+#endif
+	misc_register(&rtc_dev);
+	return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	misc_deregister(&rtc_dev);
+}
+#endif
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/suncons.c linux/drivers/sbus/char/suncons.c
--- v2.1.15/linux/drivers/sbus/char/suncons.c	Thu Apr 25 13:27:42 1996
+++ linux/drivers/sbus/char/suncons.c	Fri Dec 13 11:37:32 1996
@@ -1,8 +1,13 @@
-/* suncons.c: Sun SparcStation console support.
+/* $Id: suncons.c,v 1.42 1996/11/27 20:10:06 jj Exp $
+ *
+ * suncons.c: Sun SparcStation console support.
  *
  * Copyright (C) 1995 Peter Zaitcev (zaitcev@lab.ipmce.su)
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1995, 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
  *
  * Added font loading Nov/21, Miguel de Icaza (miguel@nuclecu.unam.mx)
  * Added render_screen and faster scrolling Nov/27, miguel
@@ -11,14 +16,23 @@
  * Added cgsix and bwtwo drivers Jan/96, miguel
  * Added 4m, and cg3 driver Feb/96, miguel
  * Fixed the cursor on color displays Feb/96, miguel.
- *
  * Cleaned up the detection code, generic 8bit depth display 
- * code, Mar/96 miguel
+ *   code, Mar/96 miguel
+ * Hacked support for cg14 video cards -- Apr/96, miguel.
+ * Color support for cg14 video cards -- May/96, miguel.
+ * Code split, Dave Redman, May/96
+ * Be more VT change friendly, May/96, miguel.
+ * Support for hw cursor and graphics acceleration, Jun/96, jj.
+ * Added TurboGX+ detection (cgthree+), Aug/96, Iain Lea (iain@sbs.de)
+ * Added TCX support (8/24bit), Aug/96, jj.
+ * Support for multiple framebuffers, Sep/96, jj.
+ * Fix bwtwo inversion and handle inverse monochrome cells in
+ *   sun_blitc, Nov/96, ecd.
+ * Fix sun_blitc and screen size on displays other than 1152x900, 
+ *   128x54 chars, Nov/96, jj.
+ * Fix cursor spots left on some non-accelerated fbs, changed
+ *   software cursor to be like the hw one, Nov/96, jj.
  * 
- * This file contains the frame buffer device drivers.
- * Each driver is kept together in case we would like to
- * split this file.
- *
  * Much of this driver is derived from the DEC TGA driver by
  * Jay Estabrook who has done a nice job with the console
  * driver abstraction btw.
@@ -29,23 +43,12 @@
  * since not all Sparcs have the hardware to do it.
  *
  * TODO:
- * do not use minor to index into instances of the frame buffer,
- * since the numbers assigned to us are not consecutive.
- *
  * do not blank the screen when frame buffer is mapped.
  *
- * Change the detection loop to use more than one video card.
  */
 
 
-/* Define this one if you are debugging something in X, it will not disable the console output */
-/* #define DEBUGGING_X */
-/* See also: sparc/keyboard.c: CODING_NEW_DRIVER */
-
-#define GRAPHDEV_MAJOR 29
-
-#define FRAME_BUFFERS 1
-
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/interrupt.h>
@@ -59,9 +62,10 @@
 #include <linux/major.h>
 #include <linux/mm.h>
 #include <linux/types.h>
+#include <linux/version.h>
 
 #include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/bitops.h>
@@ -69,7 +73,6 @@
 #include <asm/sbus.h>
 #include <asm/fbio.h>
 #include <asm/io.h>
-#include <asm/pgtsun4c.h>	/* for the sun4c_nocache */
 
 #include "../../char/kbd_kern.h"
 #include "../../char/vt_kern.h"
@@ -77,51 +80,53 @@
 #include "../../char/selection.h"
 #include "../../char/console_struct.h"
 
+#include "fb.h"
+
 #define cmapsz 8192
 
+#include "suncons_font.h"
+#include "linux_logo.h"
+
+fbinfo_t *fbinfo;
+int fbinfos;
+
+#define ASM_BLITC
+
+int sun_hw_cursor_shown = 0;
+
+void sun_hw_hide_cursor(void);
+void sun_hw_set_cursor(int,int);
+
 extern void register_console(void (*proc)(const char *));
 extern void console_print(const char *);
+extern void putconsxy(int, char *);
 extern unsigned char vga_font[];
-extern int graphics_on;
 extern int serial_console;
-
-/* Based upon what the PROM tells us, we can figure out where
- * the console is currently located.  The situation can be either
- * of the following two scenarios:
- *
- * 1) Console i/o is done over the serial line, ttya or ttyb
- * 2) Console output on frame buffer (video card) and input
- *    coming from the keyboard/mouse which each use a zilog8530
- *    serial channel a piece.
- */
+char *console_fb_path = NULL; /* Set in setup.c */
 
 /* The following variables describe a Sparc console. */
 
-/* From the PROM */
-static char con_name[40];
-
 /* Screen dimensions and color depth. */
 static int con_depth, con_width, con_height, con_type;
 
-static int con_linebytes;
-
 /* Base address of first line. */
 static unsigned char *con_fb_base;
 
 /* Screen parameters: we compute those at startup to make the code faster */
 static int chars_per_line;	/* number of bytes per line */
 static int ints_per_line;	/* number of ints per  line */
-static int skip_bytes;		/* number of bytes we skip for the y margin */
+static int ints_per_cursor;  	/* 14 * ints_per_line */
+static int skip_bytes;		/* number of bytes we skip for the y margin + x_margin */
 static int x_margin, y_margin;	/* the x and y margins */
 static int bytes_per_row;	/* bytes used by one screen line (of 16 scan lines)  */
+int sun_prom_console_id = 0;
 
 /* Functions used by the SPARC dependent console code
- * to perform the restore_palette function.
+ * to perform the fb_restore_palette function.
  */
-static void (*restore_palette)(void);
+void (*fb_restore_palette)(fbinfo_t *fbinfo);
 void set_palette (void);
 
-
  /* Our screen looks like at 1152 X 900:
  *
  *  0,0
@@ -157,9 +162,53 @@
 	 ((NICE_X_MARGIN) + (((cindex)&127))))
 
 
-#define COLOR_FBUF_OFFSET(cindex) \
-        (((skip_bytes) + (((cindex)>>7) * bytes_per_row)) + \
-	 ((x_margin) + (((cindex)&127) << 3)))
+#define COLOR_FBUF_OFFSET(cindex) (*color_fbuf_offset)(cindex)
+
+/* These four routines are optimizations for the _generic routine for the most common cases.
+   I guess doing twice sll is much faster than doing .mul, sra faster than doing .div,
+   and the disadvantage that someone has to call it (it cannot be inline) runs away, 'cause
+   otherwise it would have to call .mul anyway. 
+   The shifting + addition only routines won't eat any stack frame :))
+   Names come from width, screen_num_columns */
+static int
+color_fbuf_offset_1152_128 (int cindex)
+{
+	register int i = (cindex>>7);
+	/* (1152 * CHAR_HEIGHT) == 10010000000.0000 */
+	return skip_bytes + (i << 14) + (i << 11) + ((cindex & 127) << 3);
+}
+
+static int
+color_fbuf_offset_1280_144 (int cindex)
+{
+	register int i = (cindex/144);
+	/* (1280 * CHAR_HEIGHT) == 10100000000.0000 */
+	return skip_bytes + (i << 14) + (i << 12) + ((cindex % 144) << 3);
+}
+	 
+static int
+color_fbuf_offset_1024_128 (int cindex)
+{
+	register int i = (cindex>>7);
+	return skip_bytes + (i << 14) + ((cindex & 127) << 3);
+}
+	 
+static int
+color_fbuf_offset_640_80 (int cindex)
+{
+	register int i = (cindex/80);
+	return skip_bytes + (i << 13) + (i << 11) + ((cindex % 80) << 3);
+}
+	 
+static int
+color_fbuf_offset_generic (int cindex)
+{
+	return skip_bytes + (cindex / video_num_columns) * bytes_per_row + ((cindex % video_num_columns) << 3);
+}
+
+static int (*color_fbuf_offset)(int) = color_fbuf_offset_generic;
+	 
+static int do_accel = 0;
 
 void
 __set_origin(unsigned short offset)
@@ -175,66 +224,57 @@
  * Hide the cursor from view, during blanking, usually...
  */
 static int cursor_pos = -1;
+
+static unsigned int under_cursor[4];
+
 void
 hide_cursor(void)
 {
 	unsigned long flags;
 	int j;
 
-	save_flags(flags); cli();
+	if (fbinfo[0].setcursor) {
+		sun_hw_hide_cursor();
+		return;
+	}
+	
+	if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
+		return; /* Don't paint anything on fb which is not ours,
+			   but turn off the hw cursor in such case */
+	
+	save_and_cli(flags);
 
 	if(cursor_pos == -1) {
 		restore_flags (flags);
 		return;
 	}
-	/* We just zero out the area for now.  Certain graphics
-	 * cards like the cg6 have a hardware cursor that we could
-	 * use, but this is an optimization for some time later.
-	 */
 	switch (con_depth){
 	case 1: {
 		unsigned char *dst;
 		dst = (unsigned char *)((unsigned long)con_fb_base +
 					FBUF_OFFSET(cursor_pos));
 		for(j = 0; j < CHAR_HEIGHT; j++, dst += CHARS_PER_LINE)
-			*dst = ~(0);
+			*dst = ~(*dst);
 		break;
 	}
 	case 8: {
-		unsigned long *dst;
-		const    int ipl = ints_per_line;
+		unsigned int *dst;
 		
-		dst = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(cursor_pos));
-		for(j = 0; j < CHAR_HEIGHT; j++, dst += ipl) {
-			*dst = ~(0UL);
-			*(dst + 1) = ~(0UL);
-		}
+		dst = (unsigned int *)((unsigned long)con_fb_base +
+					COLOR_FBUF_OFFSET(cursor_pos)) + ints_per_cursor;
+		dst[0] = under_cursor[0];
+		dst[1] = under_cursor[1];
+		dst[ints_per_line] = under_cursor[2];
+		dst[ints_per_line+1] = under_cursor[3];
 		break;
 	}
 	default:
 		break;
 	}
+	cursor_pos = -1;
 	restore_flags(flags);
 }
 
-/* The idea is the following:
- * we only use the colors in the range 0..15, and we only
- * setup the palette on that range, so we better keep the
- * pixel inversion using those colors, that's why we have
- * those constants below.
- */
-inline static void
-cursor_reverse (long *dst, int height, const int ints_on_line)
-{
-    int j;
-
-    for (j = 0; j < height; j++){
-	*dst     = ~(*dst)     & 0x0f0f0f0f;
-	*(dst+1) = ~(*(dst+1)) & 0x0f0f0f0f;
-	dst += ints_on_line;
-    }
-}
-
 void
 set_cursor(int currcons)
 {
@@ -244,19 +284,33 @@
 	if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
 		return;
 
+#if 0
+/* This is a nop anyway */
 	if (__real_origin != __origin)
 		__set_origin(__real_origin);
+#endif
+		
+	if (fbinfo[0].setcursor) {
+		if (!deccm)
+			hide_cursor();
+		else {
+			idx = (pos - video_mem_base) >> 1;
+			
+			sun_hw_set_cursor(x_margin + ((idx % video_num_columns) << 3), y_margin + ((idx / video_num_columns) * CHAR_HEIGHT));
+		}
+		return;
+	}
 
-	save_flags(flags); cli();
+	save_and_cli(flags);
 
 	idx = (pos - video_mem_base) >> 1;
 	oldpos = cursor_pos;
-	cursor_pos = idx;
 	if (!deccm) {
 		hide_cursor ();
 		restore_flags (flags);
 		return;
 	}
+	cursor_pos = idx;
 	switch (con_depth){
 	case 1: {
 		unsigned char *dst, *opos;
@@ -275,13 +329,24 @@
 		break;
 	}
 	case 8: {
-		unsigned long *dst, *opos;
-		dst = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(idx));
-		opos = (unsigned long *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(oldpos));
+		unsigned int *dst, *opos;
+		dst = (unsigned int *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(idx)) + ints_per_cursor;
 			
-		if(oldpos != -1) 
-			cursor_reverse(opos, CHAR_HEIGHT, ints_per_line);
-		cursor_reverse (dst, CHAR_HEIGHT, ints_per_line);
+		if(oldpos != -1) {
+			opos = (unsigned int *)((unsigned long)con_fb_base + COLOR_FBUF_OFFSET(oldpos)) + ints_per_cursor;
+			opos[0] = under_cursor[0];
+			opos[1] = under_cursor[1];
+			opos[ints_per_line] = under_cursor[2];
+			opos[ints_per_line+1] = under_cursor[3];
+		}
+		under_cursor[0] = dst[0];
+		under_cursor[1] = dst[1];
+		under_cursor[2] = dst[ints_per_line];
+		under_cursor[3] = dst[ints_per_line+1];
+		dst[0] = 0x0f0f0f0f;
+		dst[1] = 0x0f0f0f0f;
+		dst[ints_per_line] = 0x0f0f0f0f;
+		dst[ints_per_line+1] = 0x0f0f0f0f;
 		break;
 	}
 	default:
@@ -291,9 +356,10 @@
 
 /*
  * Render the current screen
- * Only used at startup to avoid the caching that is being done in selection.h
+ * Only used at startup and when switching from KD_GRAPHICS to KD_TEXT
+ * to avoid the caching that is being done in selection.h
  */
-static void
+void
 render_screen(void)
 {
     int count;
@@ -306,8 +372,62 @@
 	sun_blitc (*contents, (unsigned long) contents);
 }
 
-unsigned long
-con_type_init(unsigned long kmem_start, const char **display_desc)
+__initfunc(void serial_finish_init(void (*printfunc)(const char *)))
+{
+	char buffer[2048];
+	
+	sprintf (buffer, linux_serial_image, UTS_RELEASE);
+	(*printfunc)(buffer);
+}
+
+__initfunc(void con_type_init_finish(void))
+{
+	int i;
+	char *p = con_fb_base + skip_bytes;
+	char q[2] = {0,5};
+	int currcons = 0;
+	unsigned short *ush;
+
+	if (serial_console)
+		return;
+	if (con_type == FBTYPE_SUNLEO) {
+		int rects [4];
+		
+		rects [0] = 0;
+		rects [1] = 0;
+		rects [2] = con_width;
+		rects [3] = con_height;
+		(*fbinfo[0].fill)(0, 1, rects);
+		return; /* Dunno how to display logo on leo/zx yet */
+	}
+	if (con_depth == 8 && fbinfo[0].loadcmap) {
+		for (i = 0; i < LINUX_LOGO_COLORS; i++) {
+			fbinfo[0].color_map CM(i+32,0) = linux_logo_red [i];
+			fbinfo[0].color_map CM(i+32,1) = linux_logo_green [i];
+			fbinfo[0].color_map CM(i+32,2) = linux_logo_blue [i];
+		}
+		(*fbinfo [0].loadcmap)(&fbinfo [0], 0, LINUX_LOGO_COLORS + 32);
+		for (i = 0; i < 80; i++, p += chars_per_line)
+			memcpy (p, linux_logo + 80 * i, 80);
+	} else if (con_depth == 1) {
+		for (i = 0; i < 80; i++, p += chars_per_line)
+			memcpy (p, linux_logo_bw + 10 * i, 10);
+	}
+	putconsxy(0, q);
+	ush = (unsigned short *) video_mem_base + video_num_columns * 2 + 20;
+
+	for (p = "Linux/SPARC version " UTS_RELEASE; *p; p++, ush++) {
+		*ush = (attr << 8) + *p;
+		sun_blitc (*ush, (unsigned long) ush);
+	}
+	for (i = 0; i < 5; i++) {
+		ush = (unsigned short *) video_mem_base + i * video_num_columns;
+		memset (ush, 0, 20);
+	}
+}
+
+__initfunc(unsigned long
+con_type_init(unsigned long kmem_start, const char **display_desc))
 {
         can_do_color = (con_type != FBTYPE_SUN2BW);
 
@@ -315,7 +435,7 @@
         *display_desc = "SUN";
 
 	if (!serial_console) {
-		/* If we fall back to PROM than our output have to remain readable. */
+		/* If we fall back to PROM then our output have to remain readable. */
 		prom_putchar('\033');  prom_putchar('[');  prom_putchar('H');
 
 		/*
@@ -324,8 +444,6 @@
 		video_mem_base = kmem_start;
 		kmem_start += video_screen_size;
 		video_mem_term = kmem_start;
-
-		render_screen();
 	}
 	return kmem_start;
 }
@@ -364,31 +482,37 @@
 int
 set_get_font(char * arg, int set, int ch512)
 {
-	int error, i, line;
+	int i, line;
 
 	if (!arg)
 		return -EINVAL;
-	error = verify_area (set ? VERIFY_READ : VERIFY_WRITE, (void *) arg,
-			     ch512 ? 2* cmapsz : cmapsz);
-	if (error)
-		return error;
 
 	/* download the current font */
 	if (!set){
-		memset (arg, 0, cmapsz);
-		for (i = 0; i < 256; i++)
-		    for (line = 0; line < CHAR_HEIGHT; line++)
-			put_user (vga_font [i], arg+(i*32+line));
+		if(clear_user(arg, cmapsz))
+			return -EFAULT;
+		for (i = 0; i < 256; i++) {
+			for (line = 0; line < CHAR_HEIGHT; line++) {
+				unsigned char value = vga_font[i];
+
+				/* Access checked by the above clear_user */
+				__put_user_ret (value, (arg + (i * 32 + line)),
+						-EFAULT);
+			}
+		}
 		return 0;
 	}
 	
         /* set the font */
-	for (i = 0; i < 256; i++)
+        
+        if (verify_area (VERIFY_READ, arg, 256 * CHAR_HEIGHT)) return -EFAULT;
+	for (i = 0; i < 256; i++) {
 		for (line = 0; line < CHAR_HEIGHT; line++){
-			vga_font [i*CHAR_HEIGHT + line] = (get_user (arg + (i * 32 + line)));
-			if (con_depth == 1)
-				vga_font [i*CHAR_HEIGHT + line] = vga_font [i*CHAR_HEIGHT + line];
+			unsigned char value;
+			__get_user_ret(value, (arg + (i * 32 + line)),-EFAULT);
+			vga_font [i*CHAR_HEIGHT + line] = value;
 		}
+	}
 	return 0;
 }
 
@@ -411,20 +535,23 @@
 {
 	int i;
 
-	i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
-	if (i)
-		return i;
-
+	if(set)
+		i = VERIFY_READ;
+	else
+		i = VERIFY_WRITE;
+	if(verify_area(i, arg, (16 * 3 * sizeof(unsigned char))))
+		return -EFAULT;
 	for (i=0; i<16; i++) {
 		if (set) {
-			default_red[i] = get_user(arg++) ;
-			default_grn[i] = get_user(arg++) ;
-			default_blu[i] = get_user(arg++) ;
+			__get_user_ret(default_red[i], (arg+0),-EFAULT);
+			__get_user_ret(default_grn[i], (arg+1),-EFAULT);
+			__get_user_ret(default_blu[i], (arg+2),-EFAULT);
 		} else {
-			put_user (default_red[i], arg++) ;
-			put_user (default_grn[i], arg++) ;
-			put_user (default_blu[i], arg++) ;
+			__put_user_ret(default_red[i], (arg+0),-EFAULT);
+			__put_user_ret(default_grn[i], (arg+1),-EFAULT);
+			__put_user_ret(default_blu[i], (arg+2),-EFAULT);
 		}
+		arg += 3;
 	}
 	if (set) {
 		for (i=0; i<MAX_NR_CONSOLES; i++)
@@ -442,271 +569,118 @@
 	return 0;
 }
 
-
 void
 sun_clear_screen(void)
 {
-	memset (con_fb_base, (con_depth == 1 ? ~(0) : (0)),
-		(con_depth * con_height * con_width) / 8);
+	if (fbinfo[0].fill) {
+		int rects [4];
+		
+		rects [0] = 0;
+		rects [1] = 0;
+		rects [2] = con_width;
+		rects [3] = con_height;
+		(*fbinfo[0].fill)(0, 1, rects);
+	} else if (fbinfo[0].base && fbinfo[0].base_depth)
+		memset (con_fb_base, (con_depth == 1) ? ~(0) : 0,
+			(con_depth * con_height * con_width) / 8);
 	/* also clear out the "shadow" screen memory */
 	memset((char *)video_mem_base, 0, (video_mem_term - video_mem_base));
+	cursor_pos = -1;
 }
 
-/*
- * dummy routines for the VESA blanking code, which is VGA only,
- * so we don't have to carry that stuff around for the Sparc...
- */
-void vesa_blank(void)
-{
-}
-void vesa_unblank(void)
-{
-}
-void set_vesa_blanking(const unsigned long arg)
-{
-}
-
-void vesa_powerdown(void)
+void
+sun_clear_fb(int n)
 {
+	if (!n) sun_clear_screen ();
+#if 0
+/* This makes in some configurations serious problems. 
+ * Who cares if other screens are cleared?
+ */ 
+	else if (fbinfo[n].fill) { 
+		int rects [4];
+		
+		rects [0] = 0;
+		rects [1] = 0;
+		rects [2] = fbinfo[n].type.fb_width;
+		rects [3] = fbinfo[n].type.fb_height;
+		(*fbinfo[n].fill)(0, 1, rects);
+	} 
+#endif		
+	else if (fbinfo[n].base && fbinfo[n].base_depth) {
+		memset((void *)fbinfo[n].base,
+		       (fbinfo[n].base_depth == 1) ? ~(0) : 0,
+		       (fbinfo[n].base_depth * fbinfo[n].type.fb_height
+					     * fbinfo[n].type.fb_width) / 8);
+	}
 }
 
-#undef color
-/* cg6 cursor status, kernel tracked copy */
-struct cg6_cursor {
-        short   enable;	        /* cursor is enabled */
-        struct  fbcurpos cpos;	/* position */
-        struct  fbcurpos chot;	/* hot-spot */
-        struct  fbcurpos size;	/* size of mask & image fields */
-        int     bits[2][32];	/* space for mask & image bits */
-	char    color [6];	/* cursor colors */
-};
-
-struct cg6_info {
-	struct bt_regs *bt;	/* color control */
-	void *fbc;
-	struct cg6_fhc *fhc;
-	struct cg6_tec *tec;
-	struct cg6_thc *thc;
-	struct cg6_cursor cursor; /* cursor control */
-	void *dhc;
-};
-
-struct bwtwo_info {
-        struct bwtwo_regs *regs;
-};
-
-struct cg3_info {
-	struct bt_regs *bt;	/* brooktree (color) registers */
-};
-
-/* Array holding the information for the frame buffers */
-typedef struct {
-	union {
-		struct bwtwo_info bwtwo;
-		struct cg3_info   cg3;
-		struct cg6_info   cg6;
-	} info;		        /* per frame information */
-	int    space;           /* I/O space this card resides in */
-	int    blanked;		/* true if video blanked */
-	int    open;		/* is this fb open? */
-	int    mmaped;		/* has this fb been mmapped? */
-	int    vtconsole;	/* virtual console where it is opened */
-	long   base;		/* frame buffer base    */
-	struct fbtype type;	/* frame buffer type    */
-	int    (*mmap)(struct inode *, struct file *, struct vm_area_struct *, long fb_base, void *);
-	void   (*loadcmap)(void *this, int index, int count);
-	void   (*blank)(void *this);
-	void   (*unblank)(void *this);
-	int    (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long, void *);
-} fbinfo_t;
-
-static fbinfo_t fbinfo [FRAME_BUFFERS];
-
-/* We need to keep a copy of the color map to answer ioctl requests */
-static union {
-	unsigned char   map[256][3];    /* reasonable way to access */
-        unsigned int    raw[256*3/4];   /* hardware wants it like this */
-} color_map;
-
-#define FB_MMAP_VM_FLAGS (VM_SHM| VM_LOCKED)
-
-static int
-fb_open (struct inode * inode, struct file * file)
+void
+sun_clear_margin(void)
 {
-	int minor = MINOR (inode->i_rdev);
+	int h, he, i;
+	unsigned char *p;
 
-	if (minor >= FRAME_BUFFERS)
-		return -EBADF;
-	if (fbinfo [minor].open)
-		return -EBUSY;
-	fbinfo [minor].open = 1;
-	fbinfo [minor].mmaped = 0;
-	return 0;
-}
+	if (fbinfo[0].fill) {
+		int rects [16];
 
-static int
-fb_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	int minor = MINOR (inode->i_rdev);
-	fbinfo_t *fb;
-	struct fbcmap *cmap;
-	int i;
-	
-	if (minor >= FRAME_BUFFERS)
-		return -EBADF;
-	fb = &fbinfo [minor];
-	
-	switch (cmd){
-	case FBIOGTYPE:		/* return frame buffer type */
-		i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbtype));
-		if (i) return i;
-		*(struct fbtype *)arg = (fb->type);
-		break;
-	case FBIOGATTR:{
-		struct fbgattr *fba = (struct fbgattr *) arg;
-		
-		i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbgattr));
-		if (i) return i;
-		fba->real_type = fb->type.fb_type;
-		fba->owner = 0;
-		fba->fbtype = fb->type;
-		fba->sattr.flags = 0;
-		fba->sattr.emu_type = fb->type.fb_type;
-		fba->sattr.dev_specific [0] = -1;
-		fba->emu_types [0] = fb->type.fb_type;
-		fba->emu_types [1] = -1;
-		break;
-	}
-	case FBIOSVIDEO:
-		i = verify_area(VERIFY_READ, (void *)arg, sizeof(int));
-		if (i) return i;
-		
-		if (*(int *)arg){
-			if (!fb->blanked || !fb->unblank)
-				break;
-			(*fb->unblank)(fb);
-			fb->blanked = 0;
+		memset (rects, 0, sizeof (rects));
+		rects [2] = con_width;
+		rects [3] = y_margin;
+		rects [5] = y_margin;
+		rects [6] = x_margin;
+		rects [7] = con_height;
+		rects [8] = con_width - x_margin;
+		rects [9] = y_margin;
+		rects [10] = con_width;
+		rects [11] = con_height;
+		rects [12] = x_margin;
+		rects [13] = con_height - y_margin;
+		rects [14] = con_width - x_margin;
+		rects [15] = con_height;
+		(*fbinfo[0].fill)(0, 4, rects);
+	} else {
+		memset (con_fb_base, 
+			(con_depth == 1) ? ~(0) : 0,
+			skip_bytes - (x_margin<<1));
+		memset (con_fb_base + chars_per_line * con_height
+					- skip_bytes + (x_margin<<1),
+			(con_depth == 1) ? ~(0) : 0,
+			skip_bytes - (x_margin<<1));
+		he = con_height - 2 * y_margin;
+		i = 2 * x_margin;
+		if (con_depth == 1) {
+			for (p = con_fb_base+skip_bytes-(x_margin<<1), h = 0;
+			     h <= he; p += chars_per_line, h++)
+				memset (p, ~(0), i);			
 		} else {
-			if (fb->blanked || !fb->blank)
-				break;
-			(*fb->blank)(fb);
-			fb->blanked = 1;
-		}
-		break;
-	case FBIOGVIDEO:
-		i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (int));
-		if (i) return i;
-		*(int *) arg = fb->blanked;
-		break;
-	case FBIOPUTCMAP: {	/* load color map entries */
-		char *rp, *gp, *bp;
-		int end, count;;
-		
-		if (!fb->loadcmap)
-			return -EINVAL;
-		i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcmap));
-		if (i) return i;
-		cmap = (struct fbcmap *) arg;
-		count = cmap->count;
-		if ((cmap->index < 0) || (cmap->index > 255))
-			return -EINVAL;
-		if (cmap->index + count > 256)
-			count = 256 - cmap->index;
-		i = verify_area (VERIFY_READ, rp = cmap->red, cmap->count);
-		if (i) return i;
-		i = verify_area (VERIFY_READ, gp = cmap->green, cmap->count);
-		if (i) return i;
-		i = verify_area (VERIFY_READ, bp = cmap->blue, cmap->count);
-		if (i) return i;
-
-		end = cmap->index + count;
-		for (i = cmap->index; i < end; i++){
-			color_map.map [i][0] = *rp++;
-			color_map.map [i][1] = *gp++;
-			color_map.map [i][2] = *bp++;
+			for (p = con_fb_base+skip_bytes-(x_margin<<1), h = 0;
+			     h <= he; p += chars_per_line, h++)
+				memset (p, 0, i);
 		}
-		(*fb->loadcmap)(fb, cmap->index, count);
-                break;			
 	}
-
-	default:
-		if (fb->ioctl){
-			i = fb->ioctl (inode, file, cmd, arg, fb);
-			if (i == -EINVAL)
-				printk ("[[FBIO: %8.8x]]\n", cmd);
-			return i;
-		}
-		printk ("[[FBIO: %8.8x]]\n", cmd);
-		return -EINVAL;
-	}
-	return 0;
+	if (fbinfo [0].switch_from_graph)
+		(*fbinfo [0].switch_from_graph)();
 }
 
-static void
-fb_close (struct inode * inode, struct file *filp)
+/*
+ * dummy routines for the VESA blanking code, which is VGA only,
+ * so we don't have to carry that stuff around for the Sparc...
+ */
+void vesa_blank(void)
 {
-	int minor = MINOR(inode->i_rdev);
-	struct fbcursor cursor;
-	
-	if (minor >= FRAME_BUFFERS)
-		return;
-	if (fbinfo [minor].open)
-		fbinfo [minor].open = 0;
-	vt_cons [fbinfo [minor].vtconsole]->vc_mode = KD_TEXT;
-
-	/* Leaving graphics mode, turn off the cursor */
-	graphics_on = 0;
-	if (fbinfo [minor].mmaped)
-		sun_clear_screen ();
-	cursor.set    = FB_CUR_SETCUR;
-	cursor.enable = 0;
-	fb_ioctl (inode, filp, FBIOSCURPOS, (unsigned long) &cursor);
-	set_palette ();
-	render_screen ();
-	return;
 }
 
-static int
-fb_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma)
+void vesa_unblank(void)
 {
-	int minor = MINOR (inode->i_rdev);
-	fbinfo_t *fb;
-
-	if (minor >= FRAME_BUFFERS)
-		return -ENXIO;
-	/* FIXME: the fg_console below should actually be the
-	 * console on which the invoking process is running
-	 */
-	if (vt_cons [fg_console]->vc_mode == KD_GRAPHICS)
-		return -ENXIO;
-	fbinfo [minor].vtconsole = fg_console;
-	fb = &fbinfo [minor];
+}
 
-	if (fb->mmap){
-		int v;
-		
-		v = (*fb->mmap)(inode, file, vma, fb->base, fb);
-		if (v) return v;
-		fbinfo [minor].mmaped = 1;
-		vt_cons [fg_console]->vc_mode = KD_GRAPHICS;
-		graphics_on = 1;
-		return 0;
-	} else
-		return -ENXIO;
+void set_vesa_blanking(const unsigned long arg)
+{
 }
 
-static struct file_operations graphdev_fops =
+void vesa_powerdown(void)
 {
-	NULL,			/* lseek */
-	NULL,			/* read */
-	NULL,			/* write */
-	NULL,			/* readdir */
-	NULL,			/* select */
-	fb_ioctl,
-	fb_mmap,
-	fb_open,		/* open */
-	fb_close,		/* close */
-};
+}
 
 /* Call the frame buffer routine for setting the palette */
 void
@@ -721,24 +695,39 @@
 		/* First keep color_map with the palette colors */
 		for (i = 0; i < 16; i++){
 			j = color_table [i];
-			color_map.map [i][0] = default_red [j];
-			color_map.map [i][1] = default_grn [j];
-			color_map.map [i][2] = default_blu [j];
+			fbinfo[0].color_map CM(i,0) = default_red [j];
+			fbinfo[0].color_map CM(i,1) = default_grn [j];
+			fbinfo[0].color_map CM(i,2) = default_blu [j];
 		}
 		(*fbinfo [0].loadcmap)(&fbinfo [0], 0, 16);
 	}
 }
 
+void
+set_other_palette (int n)
+{
+	if (!n) {
+		set_palette ();
+		return;
+	}
+	if (fbinfo [n].loadcmap){
+		fbinfo[n].color_map CM(0,0) = 0;
+		fbinfo[n].color_map CM(0,1) = 0;
+		fbinfo[n].color_map CM(0,2) = 0;
+		(*fbinfo [n].loadcmap)(&fbinfo [n], 0, 1);
+	}
+}
+
 /* Called when returning to prom */
 void
 console_restore_palette (void)
 {
-        if (restore_palette)
-	        (*restore_palette) ();
+        if (fb_restore_palette)
+	        (*fb_restore_palette) (&fbinfo[0]);
 }
 
 /* This routine should be moved to srmmu.c */
-static __inline__ unsigned int
+static __inline__ uint
 srmmu_get_pte (unsigned long addr)
 {
 	register unsigned long entry;
@@ -749,8 +738,8 @@
 	return entry;
 }
 
-unsigned int
-get_phys (unsigned int addr)
+uint
+get_phys (uint addr)
 {
 	switch (sparc_cpu_model){
 	case sun4c:
@@ -763,524 +752,241 @@
 	}
 }
 
-/* CG6 support code */
+int
+get_iospace (uint addr)
+{
+	switch (sparc_cpu_model){
+	case sun4c:
+		return -1; /* Don't check iospace on sun4c */
+	case sun4m:
+		return (srmmu_get_pte (addr) >> 28);
+	default:
+		panic ("get_iospace called for unsupported cpu model\n");
+		return -1;
+	}
+}
 
-/* Offset of interesting structures in the OBIO space */
-/*
- * Brooktree is the video dac and is funny to program on the cg6.
- * (it's even funnier on the cg3)
- * The FBC could be the the frame buffer control
- * The FHC could be the frame buffer hardware control.
- */
-#define CG6_ROM_OFFSET       0x0
-#define CG6_BROOKTREE_OFFSET 0x200000
-#define CG6_DHC_OFFSET       0x240000
-#define CG6_ALT_OFFSET       0x280000
-#define CG6_FHC_OFFSET       0x300000
-#define CG6_THC_OFFSET       0x301000
-#define CG6_FBC_OFFSET       0x700000
-#define CG6_TEC_OFFSET       0x701000
-#define CG6_RAM_OFFSET       0x800000
-
-struct bt_regs {
-	unsigned int  addr;	/* address register */
-	unsigned int  color_map; /* color map */
-	unsigned int  control;	/* control register */
-	unsigned int  cursor;	/* cursor map register */
-};
+__initfunc(unsigned long sun_cg_postsetup(fbinfo_t *fb, unsigned long start_mem))
+{
+	fb->color_map = (char *)start_mem;
+	return start_mem + 256*3;
+}
 
-/* The contents are unknown */
-struct cg6_tec {
-	int tec_matrix;
-	int tec_clip;
-	int tec_vdc;
+static char *known_cards [] __initdata = {
+	"cgsix", "cgthree", "cgRDI", "cgthree+", "bwtwo", "SUNW,tcx", "cgfourteen", "SUNW,leo", 0
 };
-
-struct cg6_thc {
-        unsigned int thc_xxx0[512];  /* ??? */
-        unsigned int thc_hsync1;     /* hsync timing */
-        unsigned int thc_hsync2;
-        unsigned int thc_hsync3;
-        unsigned int thc_vsync1;     /* vsync timing */
-        unsigned int thc_vsync2;
-        unsigned int thc_refresh;
-        unsigned int thc_misc;
-        unsigned int thc_xxx1[56];
-        unsigned int thc_cursxy;             /* cursor x,y position (16 bits each) */
-        unsigned int thc_cursmask[32];       /* cursor mask bits */
-        unsigned int thc_cursbits[32];       /* what to show where mask enabled */
+static char *v0_known_cards [] __initdata = {
+	"cgsix", "cgthree", "cgRDI", "cgthree+", "bwtwo", 0
 };
 
-static void
-cg6_restore_palette (void)
+__initfunc(static int known_card (char *name, char **known_cards))
 {
-	volatile struct bt_regs *bt;
+	int i;
 
-	bt = fbinfo [0].info.cg6.bt;
-	bt->addr = 0;
-	bt->color_map = 0xffffffff;
-	bt->color_map = 0xffffffff;
-	bt->color_map = 0xffffffff;
+	for (i = 0; known_cards [i]; i++)
+		if (strcmp (name, known_cards [i]) == 0)
+			return 1;
+	return 0;
 }
 
-/* Ugh: X wants to mmap a bunch of cute stuff at the same time :-( */
-/* So, we just mmap the things that are being asked for */
-static int
-cg6_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx)
+static struct {
+	int depth;
+	int resx, resy;
+	int x_margin, y_margin;
+} scr_def [] = {
+	{ 1, 1152, 900,  8,  18 },
+	{ 8, 1152, 900,  64, 18 },
+	{ 8, 1152, 1024, 64, 80 },
+	{ 8, 1280, 1024, 64, 80 },
+	{ 8, 1024, 768,  0,  0 },
+	{ 8, 640, 480, 0, 0 },
+	{ 0 },
+};
+
+__initfunc(static int cg14_present(void))
 {
-	unsigned int size, page, r, map_size;
-	unsigned int map_offset = 0;
-	fbinfo_t *fb = (fbinfo_t *) xx;
-	
-	size = vma->vm_end - vma->vm_start;
-        if (vma->vm_offset & ~PAGE_MASK)
-                return -ENXIO;
+	int root, n;
 
-	/* To stop the swapper from even considering these pages */
-	vma->vm_flags |= FB_MMAP_VM_FLAGS;
-	
-	/* Each page, see which map applies */
-	for (page = 0; page < size; ){
-		switch (vma->vm_offset+page){
-		case CG6_TEC:
-			map_size = PAGE_SIZE;
-			map_offset = get_phys ((uint)fb->info.cg6.tec);
-			break;
-		case CG6_FBC:
-			map_size = PAGE_SIZE;
-			map_offset = get_phys ((uint)fb->info.cg6.fbc);
-			break;
-		case CG6_FHC:
-			map_size = PAGE_SIZE;
-			map_offset = get_phys ((uint)fb->info.cg6.fhc);
-			break;
-		case CG6_THC:
-			map_size = PAGE_SIZE;
-			map_offset = get_phys ((uint)fb->info.cg6.thc);
-			break;
-		case CG6_BTREGS:
-			map_size = PAGE_SIZE;
-			map_offset = get_phys ((uint)fb->info.cg6.bt);
-			break;
-			
-		case CG6_DHC:
-			map_size = PAGE_SIZE * 40;
-			map_offset = get_phys ((uint)fb->info.cg6.dhc);
-			break;
-			
-		case CG6_ROM:
-			map_size = 0;
-			break;
+	root = prom_getchild (prom_root_node);
+	if ((n = prom_searchsiblings (root, "obio")) == 0)
+		return 0;
 
-		case CG6_RAM:
-			map_size = size-page;
-			map_offset = get_phys ((uint) con_fb_base);
-			if (map_size < fb->type.fb_size)
-				map_size = fb->type.fb_size;
-			break;
-		default:
-			map_size = 0;
-			break;
-		}
-		if (!map_size){
-			page += PAGE_SIZE;
-			continue;
-		}
-		r = io_remap_page_range (vma->vm_start+page,
-					 map_offset,
-					 map_size, vma->vm_page_prot,
-					 fb->space);
-		if (r) return -EAGAIN;
-		page += map_size;
-	}
-        vma->vm_inode = inode;
-        inode->i_count++;
-        return 0;
+	n = prom_getchild (n);
+	if ((n = prom_searchsiblings (n, "cgfourteen")) == 0)
+		return 0;
+	return n;
 }
 
-#define BT_D4M3(x) ((((x) >> 2) << 1) + ((x) >> 2))     /* (x / 4) * 3 */
-#define BT_D4M4(x) ((x) & ~3)                           /* (x / 4) * 4 */
-
-static void
-cg6_loadcmap (void *fbinfo, int index, int count)
-{
-	fbinfo_t *fb = (fbinfo_t *) fbinfo;
-	struct bt_regs *bt = fb->info.cg6.bt;
-	int i;
+__initfunc(static void
+sparc_framebuffer_setup(int primary, int con_node, int type, struct linux_sbus_device *sbdp, 
+			uint base, uint con_base, int prom_fb, int parent_node))
+{
+	static int frame_buffers = 1;
+	int n, i;
+	int linebytes;
+	uint io = 0;
+	char *p;
 	
-	bt->addr = index << 24;
-	for (i = index; count--; i++){
-		bt->color_map = color_map.map [i][0] << 24;
-		bt->color_map = color_map.map [i][1] << 24;
-		bt->color_map = color_map.map [i][2] << 24;
+	if (primary)
+		n = 0;
+	else {
+		if (frame_buffers == FRAME_BUFFERS) return; /* Silently ignore */
+		n = frame_buffers++;
 	}
-}
-
-/* Load cursor information */
-static void
-cg6_setcursor (struct cg6_info *info)
-{
-	unsigned int v;
-	struct cg6_cursor *c = &info->cursor;
 	
-	if (c->enable){
-		v = ((c->cpos.fbx - c->chot.fbx) << 16)
-		   |((c->cpos.fby - c->chot.fby) & 0xffff);
-	} else {
-		/* Magic constant to turn off the cursor */
-		v = ((65536-32) << 16) | (65536-32);
-	}
-	info->thc->thc_cursxy = v;
-}
+	if (prom_fb) sun_prom_console_id = n;
+		
+	if (sbdp) io = sbdp->reg_addrs [0].which_io;
 
-#undef pos
-static int
-cg6_scursor (struct fbcursor *cursor, fbinfo_t *fb)
-{
-	int op = cursor->set;
-	volatile struct cg6_thc *thc = fb->info.cg6.thc;
-	struct cg6_cursor *cursor_info = &fb->info.cg6.cursor;
-	int i, bytes = 0;
+	/* Fill in common fb information */
+	fbinfo [n].type.fb_type   = type;
+	fbinfo [n].real_type	  = type;
+	fbinfo [n].prom_node	  = con_node;
+	memset (&(fbinfo [n].emulations), 0xff, sizeof (fbinfo [n].emulations));
+	fbinfo [n].type.fb_height = prom_getintdefault(con_node, "height", 900);
+	fbinfo [n].type.fb_width  = prom_getintdefault(con_node, "width", 1152);
+	fbinfo [n].type.fb_depth  = (type == FBTYPE_SUN2BW) ? 1 : 8;
+	linebytes = prom_getint(con_node, "linebytes");
+	if (linebytes == -1) linebytes = fbinfo [n].type.fb_width;
+	fbinfo [n].type.fb_size   = PAGE_ALIGN((linebytes) * (fbinfo [n].type.fb_height));
+	fbinfo [n].space = io;
+	fbinfo [n].blanked = 0;
+	fbinfo [n].base = con_base;
+	fbinfo [n].cursor.hwsize.fbx = 32;
+	fbinfo [n].cursor.hwsize.fby = 32;
+	fbinfo [n].proc_entry.node = parent_node;
+	fbinfo [n].proc_entry.rdev = MKDEV(GRAPHDEV_MAJOR, n);
+	fbinfo [n].proc_entry.mode = S_IFCHR | S_IRUSR | S_IWUSR;
+	prom_getname (con_node, fbinfo [n].proc_entry.name, 32 - 3);
+	p = strchr (fbinfo [n].proc_entry.name, 0);
+        sprintf (p, ":%d", n);
 	
-	if (op & FB_CUR_SETSHAPE){
-		if ((unsigned int) cursor->size.fbx > 32)
-			return -EINVAL;
-		if ((unsigned int) cursor->size.fby > 32)
-			return -EINVAL;
-		bytes = (cursor->size.fby * 32)/8;
-		i = verify_area (VERIFY_READ, cursor->image, bytes);
-		if (i) return i;
-		i = verify_area (VERIFY_READ, cursor->mask, bytes);
-		if (i) return i;
-	}
-	if (op & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)){
-		if (op & FB_CUR_SETCUR)
-			cursor_info->enable = cursor->enable;
-		if (op & FB_CUR_SETPOS)
-			cursor_info->cpos = cursor->pos;
-		if (op & FB_CUR_SETHOT)
-			cursor_info->chot = cursor->hot;
-		cg6_setcursor (&fb->info.cg6);
-	}
-	if (op & FB_CUR_SETSHAPE){
-		unsigned int u;
-		
-		cursor_info->size = cursor->size;
-		memset ((void *)&cursor_info->bits, 0, sizeof (cursor_info->size));
-		memcpy (cursor_info->bits [0], cursor->mask, bytes);
-		memcpy (cursor_info->bits [1], cursor->image, bytes);
-		u = ~0;
-		if (cursor_info->size.fbx < 32)
-			u = ~(u  >> cursor_info->size.fbx);
-		for (i = 0; i < 32; i++){
-			int m = cursor_info->bits [0][i] & u;
-			thc->thc_cursmask [i] = m;
-			thc->thc_cursbits [i] = m & cursor_info->bits [1][i];
-		}
-	}
-	return 0;
-}
-
-/* Handle cg6-specific ioctls */
-static int
-cg6_ioctl (struct inode *inode, struct file *file, unsigned cmd, unsigned long arg, fbinfo_t *fb)
-{
-	int i;
-
-	switch (cmd){
-	case FBIOGCURMAX:
-		i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbcurpos));
-		if (i) return i;
-		((struct fbcurpos *) arg)->fbx = 32;
-		((struct fbcurpos *) arg)->fby = 32;
+	/* Should be filled in for supported video cards */
+	fbinfo [n].mmap = 0; 
+	fbinfo [n].loadcmap = 0;
+	fbinfo [n].ioctl = 0;
+	fbinfo [n].reset = 0;
+	fbinfo [n].blank = 0;
+	fbinfo [n].unblank = 0;
+	fbinfo [n].setcursor = 0;
+	fbinfo [n].base_depth = fbinfo [n].type.fb_depth;
+	
+	/* Per card setup */
+	switch (fbinfo [n].type.fb_type){
+#ifdef SUN_FB_CGTHREE
+	case FBTYPE_SUN3COLOR:
+		cg3_setup (&fbinfo [n], n, base, io, sbdp);
 		break;
-
-	case FBIOSVIDEO:
-		/* vesa_blank and vesa_unblank could do the job on fb [0] */
+#endif
+#ifdef SUN_FB_TCX
+	case FBTYPE_TCXCOLOR:
+		tcx_setup (&fbinfo [n], n, con_node, base, sbdp);
 		break;
-
-	case FBIOSCURSOR:
-		return cg6_scursor ((struct fbcursor *) arg, fb);
-
-	case FBIOSCURPOS:
-		/*
-		i= verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcurpos));
-		if (i) return i;
-		*/
-		fb->info.cg6.cursor.cpos = *(struct fbcurpos *)arg;
-		cg6_setcursor (&fb->info.cg6);
+#endif
+#ifdef SUN_FB_CGSIX
+	case FBTYPE_SUNFAST_COLOR:
+		cg6_setup (&fbinfo [n], n, base, io);
+		break;
+#endif
+#ifdef SUN_FB_BWTWO
+	case FBTYPE_SUN2BW:
+		bwtwo_setup (&fbinfo [n], n, base, io);
+		break;
+#endif
+#ifdef SUN_FB_CGFOURTEEN
+	case FBTYPE_MDICOLOR:
+		cg14_setup (&fbinfo [n], n, con_node, base, io);
+		break;
+#endif
+#ifdef SUN_FB_LEO
+	case FBTYPE_SUNLEO:
+		leo_setup (&fbinfo [n], n, base, io);
 		break;
+#endif
 	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static void
-cg6_setup (int slot, unsigned int cg6, int cg6_io)
-{
-	struct cg6_info *cg6info;
-
-	printk ("cgsix%d at 0x%8.8x\n", slot, (unsigned int) cg6);
-	
-	/* Fill in parameters we left out */
-	fbinfo [slot].type.fb_cmsize = 256;
-	fbinfo [slot].mmap = cg6_mmap;
-	fbinfo [slot].loadcmap = cg6_loadcmap;
-	fbinfo [slot].ioctl = (void *) cg6_ioctl;
-	fbinfo [slot].blank = 0;
-	fbinfo [slot].unblank = 0;
-	
-	cg6info = (struct cg6_info *) &fbinfo [slot].info.cg6;
-
-	/* Map the hardware registers */
-	cg6info->bt = sparc_alloc_io ((void *) cg6+CG6_BROOKTREE_OFFSET, 0,
-		 sizeof (struct bt_regs),"cgsix_dac", cg6_io, 0);
-	cg6info->fhc = sparc_alloc_io ((void *) cg6+CG6_FHC_OFFSET, 0,
-		 sizeof (int), "cgsix_fhc", cg6_io, 0);
-	cg6info->thc = sparc_alloc_io ((void *) cg6+CG6_THC_OFFSET, 0,
-		 sizeof (struct cg6_thc), "cgsix_thc", cg6_io, 0);
-	cg6info->tec = sparc_alloc_io ((void *) cg6+CG6_TEC_OFFSET, 0,
-		 sizeof (struct cg6_tec), "cgsix_tec", cg6_io, 0);
-	cg6info->dhc = sparc_alloc_io ((void *) cg6+CG6_DHC_OFFSET, 0,
-		 0x40000, "cgsix_dhc", cg6_io, 0);
-	cg6info->fbc = sparc_alloc_io ((void *) cg6+CG6_FBC_OFFSET, 0,
-		 0x1000, "cgsix_fbc", cg6_io, 0);
-	if (!con_fb_base){
-		con_fb_base = sparc_alloc_io ((void *) cg6+CG6_RAM_OFFSET, 0,
-                    fbinfo [slot].type.fb_size, "cgsix_ram", cg6_io, 0);
+		fbinfo [n].type.fb_type = FBTYPE_NOTYPE;
+		return;
 	}
-	if (!slot)
-		restore_palette = cg6_restore_palette;
-}
-
-/* The cg3 driver, obio space addresses for mapping the cg3 stuff */
-#define CG3_REGS 0x400000
-#define CG3_RAM  0x800000
-#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2))      /* (x/4)*3 */
-#define D4M4(x) ((x)&~0x3)                      /* (x/4)*4 */
-
-/* The cg3 palette is loaded with 4 color values at each time  */
-/* so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on */
-static void
-cg3_loadcmap (void *fbinfo, int index, int count)
-{
-	fbinfo_t *fb = (fbinfo_t *) fbinfo;
-	struct bt_regs *bt = fb->info.cg3.bt;
-	int *i, steps;
-
-	i = &color_map.raw [D4M3(index)];
-	steps = D4M3(index+count-1) - D4M3(index)+3;
-	bt->addr = D4M4(index);
-	while (steps--)
-		bt->color_map = *i++;
-}
-
-/* The cg3 is presumed to emulate a cg4, I guess older programs will want that */
-/* addresses above 0x4000000 are for cg3, below that it's cg4 emulation          */
-static int
-cg3_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx)
-{
-	unsigned int size, page, r, map_size;
-	unsigned int map_offset = 0;
-	fbinfo_t *fb = (fbinfo_t *) xx;
-	
-	size = vma->vm_end - vma->vm_start;
-        if (vma->vm_offset & ~PAGE_MASK)
-                return -ENXIO;
-
-	/* To stop the swapper from even considering these pages */
-	vma->vm_flags |= FB_MMAP_VM_FLAGS; 
-	
-	/* Each page, see which map applies */
-	for (page = 0; page < size; ){
-		switch (vma->vm_offset+page){
-		case CG3_MMAP_OFFSET:
-			map_size = size-page;
-			map_offset = get_phys ((uint) con_fb_base);
-			if (map_size > fb->type.fb_size)
-				map_size = fb->type.fb_size;
-			break;
-		default:
-			map_size = 0;
+	if (!n) {
+		con_type = type;
+		con_height = fbinfo [n].type.fb_height;
+		con_width = fbinfo [n].type.fb_width;
+		con_depth = (type == FBTYPE_SUN2BW) ? 1 : 8;
+		for (i = 0; scr_def [i].depth; i++){
+			if ((scr_def [i].resx != con_width) ||
+			    (scr_def [i].resy != con_height))
+				continue;
+			if (scr_def [i].depth != con_depth)
+		        	continue;
+			x_margin = scr_def [i].x_margin;
+			y_margin = scr_def [i].y_margin;
+			chars_per_line = (con_width * con_depth) / 8;
+			skip_bytes = chars_per_line * y_margin + x_margin;
+			ints_per_line = chars_per_line / 4;
+			ints_per_cursor = 14 * ints_per_line;
+			bytes_per_row = CHAR_HEIGHT * chars_per_line;
+			ORIG_VIDEO_COLS = con_width / 8 -
+						2 * x_margin / con_depth;
+			ORIG_VIDEO_LINES = (con_height - 2 * y_margin) / 16;
+			switch (chars_per_line) {
+			case 1152:
+				if (ORIG_VIDEO_COLS == 128)
+					color_fbuf_offset =
+						color_fbuf_offset_1152_128;
+				break;
+			case 1280:
+				if (ORIG_VIDEO_COLS == 144)
+					color_fbuf_offset =
+						color_fbuf_offset_1280_144;
+				break;
+			case 1024:
+				if (ORIG_VIDEO_COLS == 128)
+					color_fbuf_offset =
+						color_fbuf_offset_1024_128;
+				break;
+			case 640:
+				if (ORIG_VIDEO_COLS == 80)
+					color_fbuf_offset =
+						color_fbuf_offset_640_80;
+				break;
+			}
 			break;
 		}
-		if (!map_size){
-			page += PAGE_SIZE;
-			continue;
-		}
-		r = io_remap_page_range (vma->vm_start+page,
-					 map_offset,
-					 map_size, vma->vm_page_prot,
-					 fb->space);
-		if (r) return -EAGAIN;
-		page += map_size;
-	}
-        vma->vm_inode = inode;
-        inode->i_count++;
-        return 0;
-}
 
-static void
-cg3_setup (int slot, unsigned int cg3, int cg3_io)
-{
-	struct cg3_info *cg3info;
+		if (!scr_def [i].depth){
+			x_margin = y_margin = 0;
+			prom_printf ("console: unknown video resolution %dx%d, depth %d\n",
+			      	     con_width, con_height, con_depth);
+			prom_halt ();
+		}
 
-	printk ("cgthree%d at 0x%8.8x\n", slot, cg3);
-	
-	/* Fill in parameters we left out */
-	fbinfo [slot].type.fb_cmsize = 256;
-	fbinfo [slot].mmap = cg3_mmap;
-	fbinfo [slot].loadcmap = cg3_loadcmap;
-	fbinfo [slot].ioctl = 0; /* no special ioctls */
-
-	cg3info = (struct cg3_info *) &fbinfo [slot].info.cg3;
-
-	/* Map the card registers */
-	cg3info->bt = sparc_alloc_io ((void *) cg3+CG3_REGS, 0,
-		 sizeof (struct bt_regs),"cg3_bt", cg3_io, 0);
-	
-	if (!con_fb_base){
-		con_fb_base=sparc_alloc_io ((void*) cg3+CG3_RAM, 0,
-                    fbinfo [slot].type.fb_size, "cg3_ram", cg3_io, 0);
+		/* P3: I fear this strips 15inch 1024/768 PC-like
+		 * monitors out. */
+		if ((linebytes*8) / con_depth != con_width) {
+			prom_printf("console: unusual video, linebytes=%d, "
+			    	    "width=%d, height=%d depth=%d\n",
+			    	    linebytes, con_width, con_height,
+				    con_depth);
+			prom_halt ();
+		}
 	}
 }
 
-/* OBio addresses for the bwtwo registers */
-#define BWTWO_REGISTER_OFFSET 0x400000
-
-struct bwtwo_regs {
-	char          unknown [16];
-#define BWTWO_ENABLE_VIDEO 0x40
-	unsigned char control;
-	char          unknown2 [15];
-};
-
-static int
-bwtwo_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, long base, void *xx)
-{
-	unsigned int size, map_offset, r;
-	fbinfo_t *fb = (fbinfo_t *) xx;
-	int map_size;
-	
-	map_size = size = vma->vm_end - vma->vm_start;
-	
-	if (vma->vm_offset & ~PAGE_MASK)
-		return -ENXIO;
-
-	/* To stop the swapper from even considering these pages */
-	vma->vm_flags |= FB_MMAP_VM_FLAGS;
-	printk ("base=%8.8xl start=%8.8xl size=%x offset=%8.8x\n",
-		(unsigned int) base,
-		(unsigned int) vma->vm_start, size,
-		(unsigned int) vma->vm_offset);
-
-	/* This routine should also map the register if asked for, but we don't do that yet */
-	map_offset = get_phys ((uint) con_fb_base);
-	r = io_remap_page_range (vma->vm_start, map_offset, map_size, vma->vm_page_prot,
-				 fb->space);
-	if (r) return -EAGAIN;
-	vma->vm_inode = inode;
-	inode->i_count++;
-	return 0;
-}
-
-static void
-bwtwo_blank (void *xx)
-{
-	fbinfo_t *fb = (fbinfo_t *) xx;
-
-	fb->info.bwtwo.regs->control &= ~BWTWO_ENABLE_VIDEO;
-}
-
-static void
-bwtwo_unblank (void *xx)
-{
-	fbinfo_t *fb = (fbinfo_t *) xx;
-	fb->info.bwtwo.regs->control |= BWTWO_ENABLE_VIDEO;
-}
-
-static void
-bwtwo_setup (int slot, unsigned int bwtwo, int bw2_io)
-{
-	printk ("bwtwo%d at 0x%8.8x\n", slot, bwtwo);
-	fbinfo [slot].type.fb_cmsize = 2;
-	fbinfo [slot].mmap = bwtwo_mmap;
-	fbinfo [slot].loadcmap = 0;
-	fbinfo [slot].ioctl = 0;
-	fbinfo [slot].blank = bwtwo_blank;
-	fbinfo [slot].unblank = bwtwo_unblank;
-	fbinfo [slot].info.bwtwo.regs = sparc_alloc_io ((void *) bwtwo+BWTWO_REGISTER_OFFSET,
-		0, sizeof (struct bwtwo_regs), "bwtwo_regs", bw2_io, 0);
-}
-
-static void
-cg14_setup (int slot, unsigned int cg14, int cg14_io)
-{
-	printk ("cgfourteen%d at 0x%8.8x\n", slot, cg14);
-	fbinfo [slot].type.fb_cmsize = 256;
-	fbinfo [slot].mmap =  0;
-	fbinfo [slot].loadcmap = 0;
-	fbinfo [slot].ioctl = 0;
-	fbinfo [slot].blank = 0;
-	fbinfo [slot].unblank = 0;
-}
-
-static char *known_cards [] = {
-	"cgsix", "cgthree", "bwtwo", "SUNW,tcx", "cgfourteen", 0
-};
-
-static int
-known_card (char *name)
-{
-	int i;
-
-	for (i = 0; known_cards [i]; i++)
-		if (strcmp (name, known_cards [i]) == 0)
-			return 1;
-	return 0;
-}
-
-static struct {
-	int depth;
-	int resx, resy;
-	int x_margin, y_margin;
-} scr_def [] = {
-	{ 1, 1152, 900,  8,  18 },
-	{ 8, 1152, 900,  64, 18 },
-	{ 8, 1280, 1024, 96, 80 },
-	{ 8, 1024, 768,  0,  0 },
-	{ 0 },
-};
-
-static int
-cg14_present(void)
-{
-	int root, n;
-
-	prom_printf ("Looking for cg14\n");
-	root = prom_getchild (prom_root_node);
-	if ((n = prom_searchsiblings (root, "obio")) == 0)
-		return 0;
-
-	n = prom_getchild (n);
-	if ((n = prom_searchsiblings (n, "cgfourteen")) == 0)
-		return 0;
-	prom_printf ("Cg14 found!\n");
-	return n;
-}
-
-static int
-sparc_console_probe(void)
+__initfunc(static int sparc_console_probe(void))
 {
-	int propl, con_node, i;
-	struct linux_sbus_device *sbdp;
-	unsigned int fbbase = 0xb001b001;
-	int fbiospace = 0;
+	int propl, con_node, default_node = 0, i;
+	char prop[16];
+	struct linux_sbus_device *sbdp, *sbdprom;
+	struct linux_sbus *sbus;
 	int cg14 = 0;
-
-	/* XXX The detection code needs to support multiple video cards in one system */
-	con_node = 0;
+	char prom_name[40];	
+	int type;
+	uint con_base;
+	u32 prom_console_node = 0;
+
+	for (i = 0; i < FRAME_BUFFERS; i++)
+		fbinfo [i].type.fb_type = FBTYPE_NOTYPE;
+	sbdprom = 0;
 	switch(prom_vers) {
 	case PROM_V0:
 		/* V0 proms are at sun4c only. Can skip many checks. */
@@ -1290,206 +996,191 @@
 			prom_halt();
 		}
 		for_each_sbusdev(sbdp, SBus_chain) {
-			con_node = sbdp->prom_node;
-
 			/* If no "address" than it is not the PROM console. */
 			if(sbdp->num_vaddrs) {
-				if(!strncmp(sbdp->prom_name, "cgsix", 5)) {
-					con_type = FBTYPE_SUNFAST_COLOR;
-					fbbase = (uint) sbdp->reg_addrs [0].phys_addr;
-					fbiospace = sbdp->reg_addrs[0].which_io;
-					break;
-				} else if(!strncmp(sbdp->prom_name, "cgthree", 7)) {
-					con_type = FBTYPE_SUN3COLOR;
-					fbbase = (uint) sbdp->reg_addrs [0].phys_addr;
-					fbiospace = sbdp->reg_addrs[0].which_io;
-					break;
-				} else if (!strncmp(sbdp->prom_name, "bwtwo", 5)) {
-					con_type = FBTYPE_SUN2BW;
-					fbbase = (uint) sbdp->reg_addrs [0].phys_addr;
-					fbiospace = sbdp->reg_addrs[0].which_io;
+				if(known_card(sbdp->prom_name, v0_known_cards)) {
+				   	sbdprom = sbdp;
+					strncpy(prom_name, sbdp->prom_name, sizeof (prom_name));
 					break;
 				}
 			}
 		}
-		if(con_type == FBTYPE_NOTYPE) return -1;
-		con_fb_base = (unsigned char *) sbdp->sbus_vaddrs[0];
-		strncpy(con_name, sbdp->prom_name, sizeof (con_name));
+		if(!sbdprom) return -1;
+		for_each_sbusdev(sbdp, SBus_chain) {
+			con_node = sbdp->prom_node;
+
+			if(!strncmp(sbdp->prom_name, "cgsix", 5) ||
+			   !strncmp(sbdp->prom_name, "cgthree+", 8)) {
+				type = FBTYPE_SUNFAST_COLOR;
+			} else if(!strncmp(sbdp->prom_name, "cgthree", 7) ||
+			   !strncmp(sbdp->prom_name, "cgRDI", 5)) {
+				type = FBTYPE_SUN3COLOR;
+			} else if (!strncmp(sbdp->prom_name, "bwtwo", 5)) {
+				type = FBTYPE_SUN2BW;
+			} else
+				continue;
+			sparc_framebuffer_setup (sbdprom == sbdp, con_node, type, sbdp, 
+						 (uint)sbdp->reg_addrs [0].phys_addr, sbdp->sbus_vaddrs[0], 0,
+						 sbdp->my_bus->prom_node);
+			/* XXX HACK */
+			if (sbdprom == sbdp && !strncmp(sbdp->prom_name, "cgRDI", 5))
+				break;
+		}
 		break;
 	case PROM_V2:
 	case PROM_V3:
 	case PROM_P1275:
-		for_each_sbusdev(sbdp, SBus_chain) {
-		        prom_printf ("Trying: %s\n", sbdp->prom_name);
-			if (known_card (sbdp->prom_name))
+		if (console_fb_path) {
+			char *q, c;
+
+			for (q = console_fb_path; *q && *q != ' '; q++);
+			c = *q;
+			*q = 0;
+			default_node = prom_pathtoinode(console_fb_path);
+			if (default_node) {
+				prom_printf ("Using %s for console\n", console_fb_path);
+				prom_console_node = prom_inst2pkg(*romvec->pv_v2bootargs.fd_stdout);
+				if (prom_console_node == default_node)
+					prom_console_node = 0;
+			}
+		}
+		if (!default_node)
+			default_node = prom_inst2pkg(*romvec->pv_v2bootargs.fd_stdout);
+		propl = prom_getproperty(default_node, "device_type",
+					 prop, sizeof (prop));
+		if (propl < 0) {
+			prom_printf ("output-device doesn't have device_type property\n");
+			prom_halt ();
+		} else if (propl != sizeof("display") || strncmp("display", prop, sizeof("display"))) {
+		    	prop [propl] = 0;
+			prom_printf ("console_probe: output-device is %s"
+				     " (not \"display\")\n", prop);
+			prom_halt ();
+		}
+		for_all_sbusdev(sbdp, sbus) {
+			if ((sbdp->prom_node == default_node)
+			    && known_card (sbdp->prom_name, known_cards)) {
+			    	sbdprom = sbdp;
 				break;
+			}
 		}
-		if (!sbdp){
-			if (!(cg14 = cg14_present ())){
-				prom_printf ("Could not find a known video card on this machine\n");
-				prom_halt ();
-			} 
-		}
-		if (!cg14){
-			prom_apply_sbus_ranges (&sbdp->reg_addrs [0], sbdp->num_registers);
-			fbbase = (long) sbdp->reg_addrs [0].phys_addr;
-			fbiospace = sbdp->reg_addrs[0].which_io;
-			con_node = (*romvec->pv_v2devops.v2_inst2pkg)
-				(*romvec->pv_v2bootargs.fd_stdout);
-			/*
-			 * Determine the type of hardware accelerator.
-			 */
-			propl = prom_getproperty(con_node, "emulation", con_name, sizeof (con_name));
-			if (propl < 0 || propl >= sizeof (con_name)) {
+		if (!sbdprom) /* I'm just wondering if this if shouldn't be deleted.
+				 Is /obio/cgfourteen present only if /sbus/cgfourteen
+				 is not? If so, then the test here should be deleted.
+				 Otherwise, this comment should be deleted. */
+			cg14 = cg14_present ();
+		if (!sbdprom && !cg14) {
+			prom_printf ("Could not find a known video card on this machine\n");
+			prom_halt ();
+		}
+		
+		for_all_sbusdev(sbdp, sbus) {
+			if (!known_card (sbdp->prom_name, known_cards)) continue;
+			con_node = sbdp->prom_node;
+			prom_apply_sbus_ranges (sbdp->my_bus, &sbdp->reg_addrs [0], sbdp->num_registers);
+
+			propl = prom_getproperty(con_node, "address", (char *) &con_base, 4);
+			if (propl != 4) con_base = 0;
+			propl = prom_getproperty(con_node, "emulation", prom_name, sizeof (prom_name));
+			if (propl < 0 || propl >= sizeof (prom_name)) {
 				/* Early cg3s had no "emulation". */
-				propl = prom_getproperty(con_node, "name", con_name, sizeof (con_name));
+				propl = prom_getproperty(con_node, "name", prom_name, sizeof (prom_name));
 				if (propl < 0) {
 					prom_printf("console: no device name!!\n");
 					return -1;
 				}
 			}
-			if(!strncmp(con_name, "cgsix", sizeof (con_name))) {
-				con_type = FBTYPE_SUNFAST_COLOR;
-			} else if(!strncmp(con_name, "cgthree", sizeof (con_name))) {
-				con_type = FBTYPE_SUN3COLOR;
-			} else if(!strncmp(con_name, "cgfourteen", sizeof (con_name))) {
-				con_type = FBTYPE_MDICOLOR;
-			} else if(!strncmp(con_name, "bwtwo", sizeof (con_name))) {
-				con_type = FBTYPE_SUN2BW;
-			} else if(!strncmp(con_name,"SUNW,tcx", sizeof (con_name))){
-				con_type = FBTYPE_SUN3COLOR;
+			prom_name [sizeof (prom_name) - 1] = 0;
+			if(!strcmp(prom_name, "cgsix") ||
+			   !strcmp(prom_name, "cgthree+")) {
+				type = FBTYPE_SUNFAST_COLOR;
+			} else if(!strcmp(prom_name, "cgthree") ||
+			   !strcmp(prom_name, "cgRDI")) {
+				type = FBTYPE_SUN3COLOR;
+			} else if(!strcmp(prom_name, "cgfourteen")) {
+				type = FBTYPE_MDICOLOR;
+			} else if(!strcmp(prom_name, "SUNW,leo")) {
+				type = FBTYPE_SUNLEO;
+			} else if(!strcmp(prom_name, "bwtwo")) {
+				type = FBTYPE_SUN2BW;
+			} else if(!strcmp(prom_name,"SUNW,tcx")){
+				sparc_framebuffer_setup (sbdprom == sbdp, con_node, FBTYPE_TCXCOLOR, sbdp,
+							 (uint)sbdp->reg_addrs [10].phys_addr, con_base, 
+							 prom_console_node == con_node, sbdp->my_bus->prom_node);
+				continue;
 			} else {
-				prom_printf("console: \"%s\" is unsupported\n", con_name);
-				return -1;
-			}
-			propl = prom_getproperty(con_node, "address", (char *) &con_fb_base, 4);
-			if (propl != 4) {
-				con_fb_base = 0;
+				prom_printf("console: \"%s\" is unsupported\n", prom_name);
+				continue;
 			}
-		} else {
-			int bases [2];
-
-			con_node = cg14;
-			prom_printf ("Found a cg14\n");
-			propl = prom_getproperty (cg14, "address",
-						  (char *) &bases[0], 8);
-			prom_printf ("Size=%d, %x\n", propl, bases [1]);
-			con_fb_base = (unsigned char *) bases [1];
-			con_type = FBTYPE_MDICOLOR;
+			sparc_framebuffer_setup (sbdprom == sbdp, con_node, type, sbdp,
+						 (uint)sbdp->reg_addrs [0].phys_addr, con_base,
+						 prom_console_node == con_node, sbdp->my_bus->prom_node);
+			/* XXX HACK */
+			if (sbdprom == sbdp && !strncmp(sbdp->prom_name, "cgRDI", 5))
+				break;
+		}
+		if (cg14) {
+			sparc_framebuffer_setup (!sbdprom, cg14, FBTYPE_MDICOLOR, 
+						 0, 0, 0, prom_console_node == cg14,
+						 prom_searchsiblings (prom_getchild (prom_root_node), "obio"));
 		}
 		break;
 	default:
 		return -1;
-	};
-
-	/* Get the device geometry */
-	con_linebytes = prom_getintdefault(con_node, "linebytes", 1152);
-	con_width = prom_getintdefault(con_node, "width", 1152);
-	con_height = prom_getintdefault(con_node, "height", 900);
-
-	/* Currently we just support 1-bit and 8-bit depth displays */
-	if (con_type == FBTYPE_SUN2BW) {
-		con_depth = 1;
-	} else {
-		con_depth = 8;
 	}
-	for (i = 0; scr_def [i].depth; i++){
-		if (scr_def [i].resx != con_width || scr_def [i].resy != con_height)
-			continue;
-		if (scr_def [i].depth != con_depth)
-		        continue;
-		x_margin = scr_def [i].x_margin;
-		y_margin = scr_def [i].y_margin;
-		chars_per_line = (con_width * con_depth) / 8;
-		skip_bytes = chars_per_line * y_margin;
-		ints_per_line = chars_per_line / 4;
-		bytes_per_row = CHAR_HEIGHT * chars_per_line;
-		break;
-	}
-	if (!scr_def [i].depth){
-		x_margin = y_margin = 0;
-		prom_printf ("PenguinCon: unknown video resolution %dx%d may be slow\n", con_width, con_height);
+	
+	if (fbinfo [0].type.fb_type == FBTYPE_NOTYPE) {
+		prom_printf ("Couldn't setup your primary frame buffer.\n");
 		prom_halt ();
 	}
-	/* P3: I fear this strips 15inch 1024/768 PC-like monitors out. */
-	if ((con_linebytes*8) / con_depth != con_width) {
-		prom_printf("console: UNUSUAL VIDEO, linebytes=%d, width=%d, depth=%d\n",
-			con_linebytes, con_width, con_depth);
-		return -1;
-	}
-
-	/* Negate the font table on 1 bit depth cards so we have white on black */
-	if (con_depth == 1)
-		for(i=0; i<(16 * 256); i++)
-			vga_font[i] = ~vga_font[i];
-
-	/* Fill in common fb information */
-	fbinfo [0].type.fb_type   = con_type;
-	fbinfo [0].type.fb_height = con_height;
-	fbinfo [0].type.fb_width  = con_width;
-	fbinfo [0].type.fb_depth  = con_depth;
-	fbinfo [0].type.fb_size   = PAGE_ALIGN((con_linebytes) * (con_height));
-	fbinfo [0].space = fbiospace;
-	fbinfo [0].blanked = 0;
-
-	/* Should be filled in for supported video cards */
-	fbinfo [0].mmap = 0; 
-	fbinfo [0].loadcmap = 0;
-	fbinfo [0].ioctl = 0;
-	fbinfo [0].blank = 0;
-	fbinfo [0].unblank = 0;
-
-	if (fbbase == 0xb001b001){
-		printk ("Mail miguel@nuclecu.unam.mx video_card=%d (%s)\n", con_type, con_name);
-	}
 
-	/* Per card setup */
-	switch (con_type){
-	case FBTYPE_SUN3COLOR:
-		cg3_setup (0, fbbase, fbiospace);
-		break;
-	case FBTYPE_SUNFAST_COLOR:
-		cg6_setup (0, fbbase, fbiospace);
-		break;
-	case FBTYPE_SUN2BW:
-		bwtwo_setup (0, fbbase, fbiospace);
-		break;
-	case FBTYPE_MDICOLOR:
-		cg14_setup (0, fbbase, fbiospace);
-		break;
-	default:
-		break;
-	}
+	if (fbinfo [0].blitc)
+		do_accel = 1;
+	
+	con_fb_base = (unsigned char *)fbinfo[0].base;
 	if (!con_fb_base){
 		prom_printf ("PROM does not have an 'address' property for this\n"
 			     "frame buffer and the Linux drivers do not know how\n"
 			     "to map the video of this device\n");
 		prom_halt ();
 	}
-	fbinfo [0].base = (long) con_fb_base;
-	
-	/* Register the frame buffer device */
-	if (register_chrdev (GRAPHDEV_MAJOR, "graphics", &graphdev_fops)){
-		printk ("Could not register graphics device\n");
-		return -EIO;
-	}
-	return 0; /* success */
+	return fb_init ();
 }
 
 /* video init code, called from within the SBUS bus scanner at
  * boot time.
  */
-void
-sun_console_init(void)
+__initfunc(unsigned long sun_console_init(unsigned long memory_start))
 {
+	int i, j;
 	if(serial_console)
-		return;
+		return memory_start;
 
+	fbinfo = (fbinfo_t *)memory_start;
+	memset (fbinfo, 0, FRAME_BUFFERS * sizeof (fbinfo_t));
 	if(sparc_console_probe()) {
 		prom_printf("Could not probe console, bailing out...\n");
 		prom_halt();
 	}
 	sun_clear_screen();
+	for (i = FRAME_BUFFERS; i > 1; i--)
+		if (fbinfo[i - 1].type.fb_type != FBTYPE_NOTYPE) break;
+	fbinfos = i;
+	memory_start = memory_start + i * sizeof (fbinfo_t);
+	for (j = 0; j < i; j++)
+		if (fbinfo[j].postsetup)
+			memory_start = (*fbinfo[j].postsetup)(fbinfo+j, memory_start);
+	for (j = 1; j < i; j++)
+		if (fbinfo[j].type.fb_type != FBTYPE_NOTYPE) {
+			sun_clear_fb(j);
+			set_other_palette(j);
+		}
+#if defined(CONFIG_PROC_FS) && ( defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE) )
+	for (j = 0; j < i; j++)
+		if (fbinfo[j].type.fb_type != FBTYPE_NOTYPE)
+			proc_openprom_regdev (&fbinfo[j].proc_entry);
+#endif
+	return memory_start;
 }
 
 /*
@@ -1501,7 +1192,7 @@
  * Called from scr_writew() when the destination is
  *  the "shadow" screen
  */
-static unsigned int
+static uint
 fontmask_bits[16] = {
     0x00000000,
     0x000000ff,
@@ -1522,53 +1213,229 @@
 };
 
 int
-sun_blitc(unsigned int charattr, unsigned long addr)
+sun_blitc(uint charattr, unsigned long addr)
 {
+	unsigned int fgmask, bgmask;
 	int j, idx;
 	unsigned char *font_row;
 
-#ifndef DEBUGGING_X
-	if (graphics_on)
+	if (do_accel) {
+		(*fbinfo[0].blitc)(charattr, 
+			        x_margin + (((addr - video_mem_base) % video_size_row)<<2),
+		 	        y_margin + CHAR_HEIGHT * ((addr - video_mem_base) / video_size_row));
 		return 0;
-#endif
+	}
+
+  	/* Invalidate the cursor position if necessary. */
 	idx = (addr - video_mem_base) >> 1;
 
-	/* Invalidate the cursor position if necessary. */
-	if(idx == cursor_pos)
-		cursor_pos = -1;
-	font_row = &vga_font[(charattr & 0xff) << 4];
+	font_row = &vga_font[(j = (charattr & 0xff)) << 4];
 
 	switch (con_depth){
 	case 1: {
 		register unsigned char *dst;
+		unsigned long flags;
 		
 		dst = (unsigned char *)(((unsigned long)con_fb_base) + FBUF_OFFSET(idx));
-		for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst+=CHARS_PER_LINE)
-			*dst = *font_row;
+
+		save_and_cli(flags);
+		if ((!(charattr & 0xf000)) ^ (idx == cursor_pos)) {
+			for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst+=CHARS_PER_LINE)
+				*dst = ~(*font_row);
+		} else {
+			for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst+=CHARS_PER_LINE)
+				*dst = *font_row;
+		}
+		restore_flags(flags);
 		break;
 	}
 	case 8: {
-		register unsigned long *dst;
-		unsigned long fgmask, bgmask, data, rowbits, attrib;
+#ifdef ASM_BLITC		
+		const int cpl = chars_per_line;
+		/* The register assignment is important here, do not modify without touching the assembly code as well */
+		register unsigned int x1 __asm__("g4"), x2 __asm__("g5"), x3 __asm__("g2"), x4 __asm__("g3"), flags __asm__("g7");
+		register unsigned int *dst __asm__("g1");
+#else		
 		const int ipl = ints_per_line;
+		unsigned int data2, data3, data4;
+		unsigned int data, rowbits;
+		register unsigned int *dst;
+		unsigned long flags;
+#endif		
+		const uint *fontm_bits = fontmask_bits;
 		
-		dst = (unsigned long *)(((unsigned long)con_fb_base) + COLOR_FBUF_OFFSET(idx));
-		attrib = (charattr >> 8) & 0x0ff;
-		fgmask = attrib & 0x0f;
-		bgmask = (attrib >> 4) & 0x0f;
-		fgmask = fgmask << 8 | fgmask;
-		fgmask |= fgmask << 16;
-		bgmask = bgmask << 8 | bgmask;
-		bgmask |= bgmask << 16;
-		
-		for(j = 0; j < CHAR_HEIGHT; j++, font_row++, dst += ipl) {
-			rowbits = *font_row;
-			data = fontmask_bits[(rowbits>>4)&0xf];
-			data = (data & fgmask) | (~data & bgmask);
-			*dst = data;
-			data = fontmask_bits[rowbits&0xf];
-			data = (data & fgmask) | (~data & bgmask);
-			*(dst+1) = data;
+		dst = (unsigned int *)(((unsigned long)con_fb_base) + COLOR_FBUF_OFFSET(idx));
+		if (j == ' ') /* space is quite common, so we optimize a bit */ {
+#ifdef ASM_BLITC
+#define BLITC_SPACE \
+		"\n\t std	%%g4, [%%g1]" \
+		"\n\t std	%%g4, [%%g1 + %0]" \
+		"\n\t add	%%g1, %1, %%g1"
+#define BLITC_SPC \
+		"\n\t std	%0, [%1]" \
+		"\n\t std	%0, [%1 + %2]"
+
+			x1 = (charattr >> 12) & 0x0f;
+			x1 |= x1 << 8;
+			x1 |= x1 << 16;
+			x3 = cpl << 1;
+			
+			__asm__ __volatile__ (
+				"\n\t mov	%2, %3"
+				BLITC_SPACE
+				BLITC_SPACE
+				BLITC_SPACE
+				BLITC_SPACE
+				BLITC_SPACE
+				BLITC_SPACE
+				BLITC_SPACE
+					: : "r" (cpl), "r" (x3), "r" (x1), "r" (x2));
+			save_and_cli (flags);
+			if (idx != cursor_pos)
+				__asm__ __volatile__ (BLITC_SPC : : "r" (x1), "r" (dst), "r" (cpl));
+			else
+				__asm__ __volatile__ (BLITC_SPC : : "r" (x1), "r" (under_cursor), "i" (8));
+			restore_flags (flags);
+#else
+			bgmask = (charattr >> 12) & 0x0f;
+			bgmask |= bgmask << 8;
+			bgmask |= bgmask << 16;
+			
+	                for(j = 0; j < CHAR_HEIGHT - 2; j++, font_row++, dst += ipl) {
+        	                *dst = bgmask;
+        	                *(dst+1) = bgmask;
+                	}
+                	/* Prevent cursor spots left on the screen */
+			save_and_cli(flags);
+			if (idx != cursor_pos) {
+	                	*dst = bgmask;
+        	        	*(dst+1) = bgmask;
+                		dst += ipl;
+	                	*dst = bgmask;
+        	        	*(dst+1) = bgmask;
+                	} else {
+	                	under_cursor [0] = bgmask;
+        	        	under_cursor [1] = bgmask;
+                		under_cursor [2] = bgmask;
+	                	under_cursor [3] = bgmask;
+        	        }
+	                restore_flags(flags);
+#endif
+		} else /* non-space */ {
+			fgmask = (charattr >> 8) & 0x0f;
+			bgmask = (charattr >> 12) & 0x0f;
+			fgmask |= fgmask << 8;
+			fgmask |= fgmask << 16;
+			bgmask |= bgmask << 8;
+			bgmask |= bgmask << 16;
+
+#ifdef ASM_BLITC
+#define BLITC_INIT \
+			"\n\t ld	[%0], %%g2"
+#define BLITC_BODY(ST1,SC1,ST2,SC2)  \
+			"\n\t " #ST1 "	%%g2, " #SC1 ", %%g7"  \
+			"\n\t " #ST2 "	%%g2, " #SC2 ", %7"  \
+			"\n\t and	%%g7, 0x3c, %%g7"  \
+			"\n\t and	%7, 0x3c, %7"  \
+			"\n\t ld	[%1 + %%g7], %6"  \
+			"\n\t and	%6, %2, %%g7"  \
+			"\n\t andn	%3, %6, %6"  \
+			"\n\t or	%%g7, %6, %6"  \
+			"\n\t ld	[%1 + %7], %7"  \
+			"\n\t and	%7, %2, %%g7"  \
+			"\n\t andn	%3, %7, %7"  \
+			"\n\t or	%%g7, %7, %7"
+#define BLITC_BODYEND \
+			"\n\t sll	%3, 2, %%g7"  \
+			"\n\t srl	%3, 2, %3"  \
+			"\n\t and	%%g7, 0x3c, %%g7"  \
+			"\n\t and	%3, 0x3c, %3"  \
+			"\n\t ld	[%0 + %%g7], %4"  \
+			"\n\t and	%4, %1, %%g7"  \
+			"\n\t andn	%2, %4, %4"  \
+			"\n\t or	%%g7, %4, %4"  \
+			"\n\t ld	[%0 + %3], %3"  \
+			"\n\t and	%3, %1, %%g7"  \
+			"\n\t andn	%2, %3, %3"  \
+			"\n\t or	%%g7, %3, %3"
+#define BLITC_STOREIT \
+			"\n\t std	%6, [%5]"  \
+			"\n\t add	%5, %4, %5"  \
+			"\n\t" 
+#define BLITC_STORE \
+			"\n\t std	%%g4, [%0]"  \
+			"\n\t std	%%g2, [%0 + %1]"
+	
+			for (j = 0; j < 3; j++, font_row+=4) {
+				__asm__ __volatile__ (BLITC_INIT
+					BLITC_BODY(srl, 26, srl, 22)
+					BLITC_STOREIT
+					BLITC_BODY(srl, 18, srl, 14)
+					BLITC_STOREIT
+					BLITC_BODY(srl, 10, srl, 6)
+					BLITC_STOREIT
+					BLITC_BODY(srl, 2, sll, 2)
+					BLITC_STOREIT
+					: : "r" (font_row), "r" (fontm_bits), "r" (fgmask), "r" (bgmask), "r" (cpl), "r" (dst),
+					    "r" (x1), "r" (x2));
+			}
+			__asm__ __volatile__ (BLITC_INIT
+				BLITC_BODY(srl, 26, srl, 22)
+				BLITC_STOREIT
+				BLITC_BODY(srl, 18, srl, 14)
+				BLITC_STOREIT
+				/* Now prepare date for the 15th line, but don't put it anywhere yet (leave it in g4,g5) */
+				BLITC_BODY(srl, 10, srl, 6)
+				: : "r" (font_row), "r" (fontm_bits), "r" (fgmask), "r" (bgmask), "r" (cpl), "r" (dst),
+				    "r" (x1), "r" (x2));
+			/* Prepare the data the bottom line (and put it into g2,g3) */
+			__asm__ __volatile__ (BLITC_BODYEND : : "r" (fontm_bits), "r" (fgmask), "r" (bgmask),
+								"r" (x3), "r" (x4));
+			save_and_cli(flags);
+			if (idx != cursor_pos)
+				__asm__ __volatile__ (BLITC_STORE : : "r" (dst), "r" (cpl));
+			else
+				__asm__ __volatile__ (BLITC_STORE : : "r" (under_cursor), "i" (8));
+			restore_flags (flags);
+#else
+	                for(j = 0; j < CHAR_HEIGHT - 2; j++, font_row++, dst += ipl) {
+        	                rowbits = *font_row;
+                	        data = fontm_bits[(rowbits>>4)&0xf];
+	                        data = (data & fgmask) | (~data & bgmask);
+        	                *dst = data;
+                	        data = fontm_bits[rowbits&0xf];
+	                        data = (data & fgmask) | (~data & bgmask);
+        	                *(dst+1) = data;
+                	}
+	                rowbits = *font_row;
+        	        data = fontm_bits[(rowbits>>4)&0xf];
+                	data = (data & fgmask) | (~data & bgmask);
+	                data2 = fontm_bits[rowbits&0xf];
+        	        data2 = (data2 & fgmask) | (~data2 & bgmask);
+                	rowbits = font_row[1];
+	                data3 = fontm_bits[(rowbits>>4)&0xf];
+        	        data3 = (data3 & fgmask) | (~data3 & bgmask);
+                	data4 = fontm_bits[rowbits&0xf];
+	                data4 = (data4 & fgmask) | (~data4 & bgmask);
+        	        
+                	/* Prevent cursor spots left on the screen */
+			save_and_cli(flags);
+			
+			if (idx != cursor_pos) {
+	                	*dst = data;
+        	        	*(dst+1) = data2;
+                		dst += ipl;
+	                	*dst = data3;
+        	        	*(dst+1) = data4;
+                	} else {
+	                	under_cursor [0] = data;
+        	        	under_cursor [1] = data2;
+                		under_cursor [2] = data3;
+	                	under_cursor [3] = data4;
+        	        }
+                	
+	                restore_flags(flags);
+#endif
 		}
 		break;
 	} /* case */
@@ -1576,347 +1443,234 @@
 	return (0);
 }
 
-unsigned char vga_font[cmapsz] = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 
-0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 
-0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 
-0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 
-0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
-0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 
-0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 
-0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, 
-0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 
-0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, 
-0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 
-0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, 
-0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 
-0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, 
-0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 
-0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
-0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 
-0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 
-0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 
-0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 
-0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 
-0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 
-0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 
-0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 
-0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
-0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
-0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 
-0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
-0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 
-0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
-0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 
-0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 
-0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 
-0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, 
-0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 
-0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 
-0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, 
-0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 
-0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
-0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, 
-0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 
-0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, 
-0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 
-0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 
-0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 
-0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
-0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
-0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 
-0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
-0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 
-0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
-0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 
-0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, 
-0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, 
-0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 
-0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, 
-0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 
-0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 
-0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 
-0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 
-0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 
-0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 
-0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 
-0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
-0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, 
-0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 
-0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 
-0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 
-0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 
-0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 
-0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
-0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 
-0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 
-0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, 
-0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 
-0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, 
-0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 
-0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
-0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, 
-0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
-0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 
-0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 
-0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 
-0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 
-0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
-0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
-0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
-0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 
-0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 
-0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 
-0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 
-0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, 
-0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 
-0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 
-0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 
-0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 
-0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 
-0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
-0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 
-0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 
-0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 
-0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 
-0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 
-0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 
-0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 
-0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 
-0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 
-0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 
-0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
-0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 
-0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-};
+void memsetw(void * s, unsigned short c, unsigned int count)
+{
+	unsigned short * addr = (unsigned short *) s;
+
+	count /= 2;
+	if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) {
+		while (count) {
+			count--;
+			*addr++ = c;
+		}
+		return;
+	}
+	if ((unsigned long) addr + count > video_mem_term ||
+	    (unsigned long) addr < video_mem_base) {
+	    	if ((unsigned long) addr + count <= video_mem_term ||
+	    	    (unsigned long) addr > video_mem_base) {
+			while (count) {
+				count--;
+				*addr++ = c;
+			}
+			return;
+	    	} else {
+			while (count) {
+				count--;
+				scr_writew(c, addr++);
+			}
+		}
+#define GX_SETW (*fbinfo[0].setw)(x_margin + ((xoff - (addr - last)) << 3), y_margin + CHAR_HEIGHT * yoff, c, addr - last);
+	} else if (do_accel) {
+		int yoff = (addr - (unsigned short *)video_mem_base) / video_num_columns;
+		int xoff = (addr - (unsigned short *)video_mem_base) % video_num_columns;
+		unsigned short * last = addr;
+		
+		while (count) {
+			count--;
+			if (*addr != c) {
+				if (xoff == video_num_columns) {
+					if (last != addr)
+						GX_SETW
+					xoff = 0;
+					yoff++;
+					last = addr;
+				}
+				*addr++ = c;
+				xoff++;
+			} else {
+				if (last != addr)
+					GX_SETW
+				if (xoff == video_num_columns) {
+					xoff = 0;
+					yoff++;
+				}
+				addr++;
+				xoff++;
+				last = addr;
+			}
+		}
+		if (last != addr)
+			GX_SETW
+	} else {
+		while (count) {
+			count--;
+			if (*addr != c) {
+				sun_blitc(c, (unsigned long)addr);
+				*addr++ = c;
+			} else
+				addr++;
+		}
+	}
+}
+
+void memcpyw(unsigned short *to, unsigned short *from, unsigned int count)
+{
+	if (vt_cons[fg_console]->vc_mode == KD_GRAPHICS) {
+		memcpy(to, from, count);
+		return;
+	}
+	if ((unsigned long) to + count > video_mem_term ||
+	    (unsigned long) to < video_mem_base) {
+	    	if ((unsigned long) to + count <= video_mem_term ||
+	    	    (unsigned long) to > video_mem_base)
+	    	    	memcpy(to, from, count);
+	    	else {
+	    		count /= 2;
+			while (count) {
+				count--;
+				scr_writew(scr_readw(from++), to++);
+			}
+		}
+#define GX_CPYW (*fbinfo[0].cpyw)(x_margin + ((xoff - (to - last)) << 3), y_margin + CHAR_HEIGHT * yoff, last, to - last);
+	} else if (do_accel) {
+		int yoff = (to - (unsigned short *)video_mem_base) / video_num_columns;
+		int xoff = (to - (unsigned short *)video_mem_base) % video_num_columns;
+		unsigned short * last = to;
+		
+		count /= 2;
+		while (count) {
+			count--;
+			if (*to != *from) {
+				if (xoff == video_num_columns) {
+					if (last != to)
+						GX_CPYW
+					xoff = 0;
+					yoff++;
+					last = to;
+				} else if (last != to && (*last & 0xff00) != (*from & 0xff00)) {
+					GX_CPYW
+					last = to;
+				}
+				*to++ = *from++;
+				xoff++;
+			} else {
+				if (last != to)
+					GX_CPYW
+				if (xoff == video_num_columns) {
+					xoff = 0;
+					yoff++;
+				}
+				to++;
+				xoff++;
+				last = to;
+				from++;
+			}
+		}
+		if (last != to)
+			GX_CPYW
+	} else {
+		count /= 2;
+		while (count) {
+			count--;
+			if (*to != *from) {
+				sun_blitc(*from, (unsigned long)to);
+				*to++ = *from++;
+			} else {
+				from++;
+				to++;
+			}
+		}
+	}
+}
+
+#undef pos
+int
+sun_hw_scursor (struct fbcursor *cursor, fbinfo_t *fb)
+{
+	int op = cursor->set;
+	int i, bytes = 0;
+	
+	if (op & FB_CUR_SETSHAPE){
+		if ((uint) cursor->size.fbx > fb->cursor.hwsize.fbx)
+			return -EINVAL;
+		if ((uint) cursor->size.fby > fb->cursor.hwsize.fby)
+			return -EINVAL;
+		bytes = (cursor->size.fby * 32)/8;
+		i = verify_area (VERIFY_READ, cursor->image, bytes);
+		if (i) return i;
+		i = verify_area (VERIFY_READ, cursor->mask, bytes);
+		if (i) return i;
+	}
+	if (op & FB_CUR_SETCMAP){
+		if (cursor->cmap.index && cursor->cmap.count != 2)
+			return -EINVAL;
+		i = verify_area (VERIFY_READ, cursor->cmap.red, 2);
+		if (i) return i;
+		i = verify_area (VERIFY_READ, cursor->cmap.green, 2);
+		if (i) return i;
+		i = verify_area (VERIFY_READ, cursor->cmap.blue, 2);
+		if (i) return i;
+	}
+	if (op & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)){
+		if (op & FB_CUR_SETCUR)
+			fb->cursor.enable = cursor->enable;
+		if (op & FB_CUR_SETPOS)
+			fb->cursor.cpos = cursor->pos;
+		if (op & FB_CUR_SETHOT)
+			fb->cursor.chot = cursor->hot;
+		(*fb->setcursor) (fb);
+	}
+	if (op & FB_CUR_SETCMAP)
+		(*fb->setcursormap) (fb, cursor->cmap.red, cursor->cmap.green, cursor->cmap.blue);
+	if (op & FB_CUR_SETSHAPE){
+		uint u;
+		
+		fb->cursor.size = cursor->size;
+		memset ((void *)&fb->cursor.bits, 0, sizeof (fb->cursor.bits));
+		memcpy (fb->cursor.bits [0], cursor->mask, bytes);
+		memcpy (fb->cursor.bits [1], cursor->image, bytes);
+		u = ~0;
+		if (cursor->size.fbx < fb->cursor.hwsize.fbx)
+			u = ~(u  >> cursor->size.fbx);
+		for (i = fb->cursor.size.fby - 1; i >= 0; i--) {
+			fb->cursor.bits [0][i] &= u;
+			fb->cursor.bits [1][i] &= fb->cursor.bits [0][i];
+		}
+		(*fb->setcurshape) (fb);
+	}
+	return 0;
+}
+
+static unsigned char hw_cursor_cmap[2] = { 0, 0xff };
+
+void
+sun_hw_hide_cursor (void)
+{
+	fbinfo[0].cursor.enable = 0;
+	(*fbinfo[0].setcursor)(&fbinfo[0]);
+	sun_hw_cursor_shown = 0;
+}
+
+void
+sun_hw_set_cursor (int xoff, int yoff)
+{
+	if (!sun_hw_cursor_shown) {
+		fbinfo[0].cursor.size.fbx = CHAR_WIDTH;
+		fbinfo[0].cursor.size.fby = CHAR_HEIGHT;
+		fbinfo[0].cursor.chot.fbx = 0;
+		fbinfo[0].cursor.chot.fby = 0;
+		fbinfo[0].cursor.enable = 1;
+		memset (fbinfo[0].cursor.bits, 0, sizeof (fbinfo[0].cursor.bits));
+		fbinfo[0].cursor.bits[0][CHAR_HEIGHT - 2] = 0xff000000;
+		fbinfo[0].cursor.bits[1][CHAR_HEIGHT - 2] = 0xff000000;
+		fbinfo[0].cursor.bits[0][CHAR_HEIGHT - 1] = 0xff000000;
+		fbinfo[0].cursor.bits[1][CHAR_HEIGHT - 1] = 0xff000000;
+		(*fbinfo[0].setcursormap) (&fbinfo[0], hw_cursor_cmap, hw_cursor_cmap, hw_cursor_cmap);
+		(*fbinfo[0].setcurshape) (&fbinfo[0]);
+		sun_hw_cursor_shown = 1;
+	}
+	fbinfo[0].cursor.cpos.fbx = xoff;
+	fbinfo[0].cursor.cpos.fby = yoff;
+	(*fbinfo[0].setcursor)(&fbinfo[0]);
+}
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/suncons_font.h linux/drivers/sbus/char/suncons_font.h
--- v2.1.15/linux/drivers/sbus/char/suncons_font.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/suncons_font.h	Fri Dec 13 11:37:32 1996
@@ -0,0 +1,258 @@
+unsigned char vga_font[cmapsz] = {
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x7e,0x81,0xa5,0x81,0x81,0xbd,0x99,0x81,0x81,0x7e,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x7e,0xff,0xdb,0xff,0xff,0xc3,0xe7,0xff,0xff,0x7e,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x6c,0xfe,0xfe,0xfe,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x10,0x38,0x7c,0xfe,0x7c,0x38,0x10,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x18,0x3c,0x3c,0xe7,0xe7,0xe7,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x18,0x3c,0x7e,0xff,0xff,0x7e,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3c,0x3c,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0xff,0xff,0xff,0xff,0xff,0xff,0xe7,0xc3,0xc3,0xe7,0xff,0xff,0xff,0xff,0xff,0xff,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x3c,0x66,0x42,0x42,0x66,0x3c,0x00,0x00,0x00,0x00,0x00,
+/* */ 0xff,0xff,0xff,0xff,0xff,0xc3,0x99,0xbd,0xbd,0x99,0xc3,0xff,0xff,0xff,0xff,0xff,
+/* */ 0x00,0x00,0x1e,0x0e,0x1a,0x32,0x78,0xcc,0xcc,0xcc,0xcc,0x78,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x3c,0x66,0x66,0x66,0x66,0x3c,0x18,0x7e,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x3f,0x33,0x3f,0x30,0x30,0x30,0x30,0x70,0xf0,0xe0,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x7f,0x63,0x7f,0x63,0x63,0x63,0x63,0x67,0xe7,0xe6,0xc0,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x18,0x18,0xdb,0x3c,0xe7,0x3c,0xdb,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfe,0xf8,0xf0,0xe0,0xc0,0x80,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x02,0x06,0x0e,0x1e,0x3e,0xfe,0x3e,0x1e,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x18,0x3c,0x7e,0x18,0x18,0x18,0x7e,0x3c,0x18,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x66,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x7f,0xdb,0xdb,0xdb,0x7b,0x1b,0x1b,0x1b,0x1b,0x1b,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x7c,0xc6,0x60,0x38,0x6c,0xc6,0xc6,0x6c,0x38,0x0c,0xc6,0x7c,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xfe,0xfe,0xfe,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x18,0x3c,0x7e,0x18,0x18,0x18,0x7e,0x3c,0x18,0x7e,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x18,0x3c,0x7e,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7e,0x3c,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x18,0x0c,0xfe,0x0c,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x30,0x60,0xfe,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xc0,0xc0,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x24,0x66,0xff,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x10,0x38,0x38,0x7c,0x7c,0xfe,0xfe,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0xfe,0xfe,0x7c,0x7c,0x38,0x38,0x10,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*!*/ 0x00,0x00,0x18,0x3c,0x3c,0x3c,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+/*"*/ 0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*#*/ 0x00,0x00,0x00,0x6c,0x6c,0xfe,0x6c,0x6c,0x6c,0xfe,0x6c,0x6c,0x00,0x00,0x00,0x00,
+/*$*/ 0x18,0x18,0x7c,0xc6,0xc2,0xc0,0x7c,0x06,0x06,0x86,0xc6,0x7c,0x18,0x18,0x00,0x00,
+/*%*/ 0x00,0x00,0x00,0x00,0xc2,0xc6,0x0c,0x18,0x30,0x60,0xc6,0x86,0x00,0x00,0x00,0x00,
+/*&*/ 0x00,0x00,0x38,0x6c,0x6c,0x38,0x76,0xdc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/*'*/ 0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*(*/ 0x00,0x00,0x0c,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0c,0x00,0x00,0x00,0x00,
+/*)*/ 0x00,0x00,0x30,0x18,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x18,0x30,0x00,0x00,0x00,0x00,
+/***/ 0x00,0x00,0x00,0x00,0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00,0x00,0x00,0x00,0x00,
+/*+*/ 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7e,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+/*,*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00,
+/*-*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*.*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x02,0x06,0x0c,0x18,0x30,0x60,0xc0,0x80,0x00,0x00,0x00,0x00,
+/*0*/ 0x00,0x00,0x7c,0xc6,0xc6,0xce,0xde,0xf6,0xe6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*1*/ 0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7e,0x00,0x00,0x00,0x00,
+/*2*/ 0x00,0x00,0x7c,0xc6,0x06,0x0c,0x18,0x30,0x60,0xc0,0xc6,0xfe,0x00,0x00,0x00,0x00,
+/*3*/ 0x00,0x00,0x7c,0xc6,0x06,0x06,0x3c,0x06,0x06,0x06,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*4*/ 0x00,0x00,0x0c,0x1c,0x3c,0x6c,0xcc,0xfe,0x0c,0x0c,0x0c,0x1e,0x00,0x00,0x00,0x00,
+/*5*/ 0x00,0x00,0xfe,0xc0,0xc0,0xc0,0xfc,0x06,0x06,0x06,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*6*/ 0x00,0x00,0x38,0x60,0xc0,0xc0,0xfc,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*7*/ 0x00,0x00,0xfe,0xc6,0x06,0x06,0x0c,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00,
+/*8*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0x7c,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*9*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0x7e,0x06,0x06,0x06,0x0c,0x78,0x00,0x00,0x00,0x00,
+/*:*/ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
+/*;*/ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00,
+/*<*/ 0x00,0x00,0x00,0x06,0x0c,0x18,0x30,0x60,0x30,0x18,0x0c,0x06,0x00,0x00,0x00,0x00,
+/*=*/ 0x00,0x00,0x00,0x00,0x00,0x7e,0x00,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*>*/ 0x00,0x00,0x00,0x60,0x30,0x18,0x0c,0x06,0x0c,0x18,0x30,0x60,0x00,0x00,0x00,0x00,
+/*?*/ 0x00,0x00,0x7c,0xc6,0xc6,0x0c,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,
+/*@*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xde,0xde,0xde,0xdc,0xc0,0x7c,0x00,0x00,0x00,0x00,
+/*A*/ 0x00,0x00,0x10,0x38,0x6c,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/*B*/ 0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x66,0x66,0x66,0x66,0xfc,0x00,0x00,0x00,0x00,
+/*C*/ 0x00,0x00,0x3c,0x66,0xc2,0xc0,0xc0,0xc0,0xc0,0xc2,0x66,0x3c,0x00,0x00,0x00,0x00,
+/*D*/ 0x00,0x00,0xf8,0x6c,0x66,0x66,0x66,0x66,0x66,0x66,0x6c,0xf8,0x00,0x00,0x00,0x00,
+/*E*/ 0x00,0x00,0xfe,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xfe,0x00,0x00,0x00,0x00,
+/*F*/ 0x00,0x00,0xfe,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
+/*G*/ 0x00,0x00,0x3c,0x66,0xc2,0xc0,0xc0,0xde,0xc6,0xc6,0x66,0x3a,0x00,0x00,0x00,0x00,
+/*H*/ 0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/*I*/ 0x00,0x00,0x3c,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/*J*/ 0x00,0x00,0x1e,0x0c,0x0c,0x0c,0x0c,0x0c,0xcc,0xcc,0xcc,0x78,0x00,0x00,0x00,0x00,
+/*K*/ 0x00,0x00,0xe6,0x66,0x66,0x6c,0x78,0x78,0x6c,0x66,0x66,0xe6,0x00,0x00,0x00,0x00,
+/*L*/ 0x00,0x00,0xf0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xfe,0x00,0x00,0x00,0x00,
+/*M*/ 0x00,0x00,0xc3,0xe7,0xff,0xff,0xdb,0xc3,0xc3,0xc3,0xc3,0xc3,0x00,0x00,0x00,0x00,
+/*N*/ 0x00,0x00,0xc6,0xe6,0xf6,0xfe,0xde,0xce,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/*O*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*P*/ 0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x60,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
+/*Q*/ 0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xd6,0xde,0x7c,0x0c,0x0e,0x00,0x00,
+/*R*/ 0x00,0x00,0xfc,0x66,0x66,0x66,0x7c,0x6c,0x66,0x66,0x66,0xe6,0x00,0x00,0x00,0x00,
+/*S*/ 0x00,0x00,0x7c,0xc6,0xc6,0x60,0x38,0x0c,0x06,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*T*/ 0x00,0x00,0xff,0xdb,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/*U*/ 0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*V*/ 0x00,0x00,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0xc3,0x66,0x3c,0x18,0x00,0x00,0x00,0x00,
+/*W*/ 0x00,0x00,0xc3,0xc3,0xc3,0xc3,0xc3,0xdb,0xdb,0xff,0x66,0x66,0x00,0x00,0x00,0x00,
+/*X*/ 0x00,0x00,0xc3,0xc3,0x66,0x3c,0x18,0x18,0x3c,0x66,0xc3,0xc3,0x00,0x00,0x00,0x00,
+/*Y*/ 0x00,0x00,0xc3,0xc3,0xc3,0x66,0x3c,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/*Z*/ 0x00,0x00,0xff,0xc3,0x86,0x0c,0x18,0x30,0x60,0xc1,0xc3,0xff,0x00,0x00,0x00,0x00,
+/*[*/ 0x00,0x00,0x3c,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3c,0x00,0x00,0x00,0x00,
+/*\*/ 0x00,0x00,0x00,0x80,0xc0,0xe0,0x70,0x38,0x1c,0x0e,0x06,0x02,0x00,0x00,0x00,0x00,
+/*]*/ 0x00,0x00,0x3c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x3c,0x00,0x00,0x00,0x00,
+/*^*/ 0x10,0x38,0x6c,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*_*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,
+/*`*/ 0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/*a*/ 0x00,0x00,0x00,0x00,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/*b*/ 0x00,0x00,0xe0,0x60,0x60,0x78,0x6c,0x66,0x66,0x66,0x66,0x7c,0x00,0x00,0x00,0x00,
+/*c*/ 0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0xc0,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*d*/ 0x00,0x00,0x1c,0x0c,0x0c,0x3c,0x6c,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/*e*/ 0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*f*/ 0x00,0x00,0x38,0x6c,0x64,0x60,0xf0,0x60,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
+/*g*/ 0x00,0x00,0x00,0x00,0x00,0x76,0xcc,0xcc,0xcc,0xcc,0xcc,0x7c,0x0c,0xcc,0x78,0x00,
+/*h*/ 0x00,0x00,0xe0,0x60,0x60,0x6c,0x76,0x66,0x66,0x66,0x66,0xe6,0x00,0x00,0x00,0x00,
+/*i*/ 0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/*j*/ 0x00,0x00,0x06,0x06,0x00,0x0e,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3c,0x00,
+/*k*/ 0x00,0x00,0xe0,0x60,0x60,0x66,0x6c,0x78,0x78,0x6c,0x66,0xe6,0x00,0x00,0x00,0x00,
+/*l*/ 0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/*m*/ 0x00,0x00,0x00,0x00,0x00,0xe6,0xff,0xdb,0xdb,0xdb,0xdb,0xdb,0x00,0x00,0x00,0x00,
+/*n*/ 0x00,0x00,0x00,0x00,0x00,0xdc,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,
+/*o*/ 0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*p*/ 0x00,0x00,0x00,0x00,0x00,0xdc,0x66,0x66,0x66,0x66,0x66,0x7c,0x60,0x60,0xf0,0x00,
+/*q*/ 0x00,0x00,0x00,0x00,0x00,0x76,0xcc,0xcc,0xcc,0xcc,0xcc,0x7c,0x0c,0x0c,0x1e,0x00,
+/*r*/ 0x00,0x00,0x00,0x00,0x00,0xdc,0x76,0x66,0x60,0x60,0x60,0xf0,0x00,0x00,0x00,0x00,
+/*s*/ 0x00,0x00,0x00,0x00,0x00,0x7c,0xc6,0x60,0x38,0x0c,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/*t*/ 0x00,0x00,0x10,0x30,0x30,0xfc,0x30,0x30,0x30,0x30,0x36,0x1c,0x00,0x00,0x00,0x00,
+/*u*/ 0x00,0x00,0x00,0x00,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/*v*/ 0x00,0x00,0x00,0x00,0x00,0xc3,0xc3,0xc3,0xc3,0x66,0x3c,0x18,0x00,0x00,0x00,0x00,
+/*w*/ 0x00,0x00,0x00,0x00,0x00,0xc3,0xc3,0xc3,0xdb,0xdb,0xff,0x66,0x00,0x00,0x00,0x00,
+/*x*/ 0x00,0x00,0x00,0x00,0x00,0xc3,0x66,0x3c,0x18,0x3c,0x66,0xc3,0x00,0x00,0x00,0x00,
+/*y*/ 0x00,0x00,0x00,0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7e,0x06,0x0c,0xf8,0x00,
+/*z*/ 0x00,0x00,0x00,0x00,0x00,0xfe,0xcc,0x18,0x30,0x60,0xc6,0xfe,0x00,0x00,0x00,0x00,
+/*{*/ 0x00,0x00,0x0e,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0e,0x00,0x00,0x00,0x00,
+/*|*/ 0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/*}*/ 0x00,0x00,0x70,0x18,0x18,0x18,0x0e,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00,
+/*~*/ 0x00,0x00,0x76,0xdc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x10,0x38,0x6c,0xc6,0xc6,0xc6,0xfe,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x3c,0x66,0xc2,0xc0,0xc0,0xc0,0xc2,0x66,0x3c,0x0c,0x06,0x7c,0x00,0x00,
+/* */ 0x00,0x00,0xcc,0x00,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x0c,0x18,0x30,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x10,0x38,0x6c,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0xcc,0x00,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x60,0x30,0x18,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x38,0x6c,0x38,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x3c,0x66,0x60,0x60,0x66,0x3c,0x0c,0x06,0x3c,0x00,0x00,0x00,
+/* */ 0x00,0x10,0x38,0x6c,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0xc6,0x00,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x60,0x30,0x18,0x00,0x7c,0xc6,0xfe,0xc0,0xc0,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x66,0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x18,0x3c,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x60,0x30,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0xc6,0x00,0x10,0x38,0x6c,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/* */ 0x38,0x6c,0x38,0x00,0x38,0x6c,0xc6,0xc6,0xfe,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/* */ 0x18,0x30,0x60,0x00,0xfe,0x66,0x60,0x7c,0x60,0x60,0x66,0xfe,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x6e,0x3b,0x1b,0x7e,0xd8,0xdc,0x77,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x3e,0x6c,0xcc,0xcc,0xfe,0xcc,0xcc,0xcc,0xcc,0xce,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x10,0x38,0x6c,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0xc6,0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x60,0x30,0x18,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x30,0x78,0xcc,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x60,0x30,0x18,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0xc6,0x00,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7e,0x06,0x0c,0x78,0x00,
+/* */ 0x00,0xc6,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0xc6,0x00,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x18,0x18,0x7e,0xc3,0xc0,0xc0,0xc0,0xc3,0x7e,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x38,0x6c,0x64,0x60,0xf0,0x60,0x60,0x60,0x60,0xe6,0xfc,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0xc3,0x66,0x3c,0x18,0xff,0x18,0xff,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0xfc,0x66,0x66,0x7c,0x62,0x66,0x6f,0x66,0x66,0x66,0xf3,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x0e,0x1b,0x18,0x18,0x18,0x7e,0x18,0x18,0x18,0x18,0x18,0xd8,0x70,0x00,0x00,
+/* */ 0x00,0x18,0x30,0x60,0x00,0x78,0x0c,0x7c,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x0c,0x18,0x30,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x18,0x30,0x60,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x18,0x30,0x60,0x00,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x76,0xdc,0x00,0xdc,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,
+/* */ 0x76,0xdc,0x00,0xc6,0xe6,0xf6,0xfe,0xde,0xce,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x3c,0x6c,0x6c,0x3e,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x38,0x6c,0x6c,0x38,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x60,0xc0,0xc6,0xc6,0x7c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xc0,0xc0,0xc0,0xc0,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0xc0,0xc0,0xc2,0xc6,0xcc,0x18,0x30,0x60,0xce,0x9b,0x06,0x0c,0x1f,0x00,0x00,
+/* */ 0x00,0xc0,0xc0,0xc2,0xc6,0xcc,0x18,0x30,0x66,0xce,0x96,0x3e,0x06,0x06,0x00,0x00,
+/* */ 0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x18,0x3c,0x3c,0x3c,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x36,0x6c,0xd8,0x6c,0x36,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0xd8,0x6c,0x36,0x6c,0xd8,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,
+/* */ 0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
+/* */ 0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77,0xdd,0x77,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0xf8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xf6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x00,0x00,0x00,0x00,0x00,0xf8,0x18,0xf8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x36,0x36,0x36,0x36,0x36,0xf6,0x06,0xf6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x00,0x00,0x00,0x00,0x00,0xfe,0x06,0xf6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0xf6,0x06,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x18,0x18,0x18,0x18,0x18,0xf8,0x18,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x1f,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x3f,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0xf7,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xf7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x36,0x36,0x36,0x36,0x36,0xf7,0x00,0xf7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x18,0x18,0x18,0x18,0x18,0xff,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x1f,0x18,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x1f,0x18,0x1f,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xff,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
+/* */ 0x18,0x18,0x18,0x18,0x18,0xff,0x18,0xff,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+/* */ 0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,
+/* */ 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,
+/* */ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x76,0xdc,0xd8,0xd8,0xd8,0xdc,0x76,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x78,0xcc,0xcc,0xcc,0xd8,0xcc,0xc6,0xc6,0xc6,0xcc,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0xfe,0xc6,0xc6,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0xfe,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x6c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0xfe,0xc6,0x60,0x30,0x18,0x30,0x60,0xc6,0xfe,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x7e,0xd8,0xd8,0xd8,0xd8,0xd8,0x70,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7c,0x60,0x60,0xc0,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x76,0xdc,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x7e,0x18,0x3c,0x66,0x66,0x66,0x3c,0x18,0x7e,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x38,0x6c,0xc6,0xc6,0xfe,0xc6,0xc6,0x6c,0x38,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x38,0x6c,0xc6,0xc6,0xc6,0x6c,0x6c,0x6c,0x6c,0xee,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x1e,0x30,0x18,0x0c,0x3e,0x66,0x66,0x66,0x66,0x3c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x7e,0xdb,0xdb,0xdb,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x03,0x06,0x7e,0xdb,0xdb,0xf3,0x7e,0x60,0xc0,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x1c,0x30,0x60,0x60,0x7c,0x60,0x60,0x60,0x30,0x1c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x7c,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0xc6,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0xfe,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x18,0x18,0x7e,0x18,0x18,0x00,0x00,0xff,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x30,0x18,0x0c,0x06,0x0c,0x18,0x30,0x00,0x7e,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x0c,0x18,0x30,0x60,0x30,0x18,0x0c,0x00,0x7e,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x0e,0x1b,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+/* */ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xd8,0xd8,0xd8,0x70,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x7e,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x76,0xdc,0x00,0x76,0xdc,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x38,0x6c,0x6c,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x0f,0x0c,0x0c,0x0c,0x0c,0x0c,0xec,0x6c,0x6c,0x3c,0x1c,0x00,0x00,0x00,0x00,
+/* */ 0x00,0xd8,0x6c,0x6c,0x6c,0x6c,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x70,0xd8,0x30,0x60,0xc8,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x7c,0x00,0x00,0x00,0x00,0x00,
+/* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+};
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/sunfb.c linux/drivers/sbus/char/sunfb.c
--- v2.1.15/linux/drivers/sbus/char/sunfb.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/sunfb.c	Fri Dec 13 11:37:33 1996
@@ -0,0 +1,316 @@
+/* $Id: sunfb.c,v 1.18 1996/11/22 11:57:07 ecd Exp $
+ * sunfb.c: Sun generic frame buffer support.
+ *
+ * Copyright (C) 1995, 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * 
+ * Added getcmap ioctl, may, 96
+ * Support for multiple fbs, sep, 96
+ */
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kd.h>
+#include <linux/malloc.h>
+#include <linux/major.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/oplib.h>
+#include <asm/sbus.h>
+#include <asm/fbio.h>
+#include <asm/io.h>
+#include <asm/pgtsun4c.h>	/* for the sun4c_nocache */
+
+#include "../../char/kbd_kern.h"
+#include "../../char/vt_kern.h"
+#include "../../char/consolemap.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+
+#include "fb.h"
+
+extern void set_other_palette (int);
+extern void sun_clear_fb(int);
+extern void set_cursor (int);
+
+#define FB_SETUP(err) \
+	int minor = FB_DEV (inode->i_rdev); \
+\
+	if (minor >= fbinfos || \
+	    fbinfo [minor].type.fb_type == FBTYPE_NOTYPE) \
+		return -(err);
+
+static int
+fb_open (struct inode * inode, struct file * file)
+{
+	FB_SETUP(EBADF)
+	if (fbinfo [minor].open)
+		return -EBUSY;
+	fbinfo [minor].mmaped = 0;
+	fbinfo [minor].open = 1;
+	return 0;
+}
+
+static int
+fb_ioctl (struct inode *inode, struct file *file, uint cmd, unsigned long arg)
+{
+	fbinfo_t *fb;
+	struct fbcmap *cmap;
+	int i;
+	FB_SETUP(EBADF)
+	
+	fb = &fbinfo [minor];
+	
+	switch (cmd){
+	case FBIOGTYPE:		/* return frame buffer type */
+		copy_to_user_ret((struct fbtype *)arg, &fb->type, sizeof(struct fbtype), -EFAULT);
+		break;
+	case FBIOGATTR:{
+		struct fbgattr *fba = (struct fbgattr *) arg;
+		
+		i = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct fbgattr));
+		if (i) return i;
+		__put_user_ret(fb->real_type, &fba->real_type, -EFAULT);
+		__put_user_ret(0, &fba->owner, -EFAULT);
+		__copy_to_user_ret(&fba->fbtype, &fb->type,
+				   sizeof(struct fbtype), -EFAULT);
+		__put_user_ret(0, &fba->sattr.flags, -EFAULT);
+		__put_user_ret(fb->type.fb_type, &fba->sattr.emu_type, -EFAULT);
+		__put_user_ret(-1, &fba->sattr.dev_specific[0], -EFAULT);
+		__put_user_ret(fb->type.fb_type, &fba->emu_types[0], -EFAULT);
+		for (i = 1; i < 4; i++)
+			put_user_ret(fb->emulations[i], &fba->emu_types[i], -EFAULT);
+		break;
+	}
+	case FBIOSATTR:
+		i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbsattr));
+		if (i) return i;
+		return -EINVAL;
+	case FBIOSVIDEO:
+ 		if (fb == fbinfo && vt_cons[fg_console]->vc_mode == KD_TEXT)
+ 			break;
+		get_user_ret(i, (int *)arg, -EFAULT);
+		if (i){
+			if (!fb->blanked || !fb->unblank)
+				break;
+			if (!minor || (fb->open && fb->mmaped))
+				(*fb->unblank)(fb);
+			fb->blanked = 0;
+		} else {
+			if (fb->blanked || !fb->blank)
+				break;
+			(*fb->blank)(fb);
+			fb->blanked = 1;
+		}
+		break;
+	case FBIOGVIDEO:
+		put_user_ret(fb->blanked, (int *) arg, -EFAULT);
+		break;
+	case FBIOGETCMAP: {
+		char *rp, *gp, *bp;
+		int end, count, index;
+
+		if (!fb->loadcmap)
+			return -EINVAL;
+		i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcmap));
+		if (i) return i;
+		cmap = (struct fbcmap *) arg;
+		__get_user_ret(count, &cmap->count, -EFAULT);
+		__get_user_ret(index, &cmap->index, -EFAULT);
+		if ((index < 0) || (index > 255))
+			return -EINVAL;
+		if (index + count > 256)
+			count = 256 - cmap->index;
+		__get_user_ret(rp, &cmap->red, -EFAULT);
+		__get_user_ret(gp, &cmap->green, -EFAULT);
+		__get_user_ret(bp, &cmap->blue, -EFAULT);
+		if(verify_area (VERIFY_WRITE, rp, count))  return -EFAULT;
+		if(verify_area (VERIFY_WRITE, gp, count))  return -EFAULT;
+		if(verify_area (VERIFY_WRITE, bp, count))  return -EFAULT;
+		end = index + count;
+		for (i = index; i < end; i++){
+			__put_user_ret(fb->color_map CM(i,0), rp, -EFAULT);
+			__put_user_ret(fb->color_map CM(i,1), gp, -EFAULT);
+			__put_user_ret(fb->color_map CM(i,2), bp, -EFAULT);
+			rp++; gp++; bp++;
+		}
+		(*fb->loadcmap)(fb, cmap->index, count);
+                break;			
+
+	}
+	case FBIOPUTCMAP: {	/* load color map entries */
+		char *rp, *gp, *bp;
+		int end, count, index;
+		
+		if (!fb->loadcmap)
+			return -EINVAL;
+		i = verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcmap));
+		if (i) return i;
+		cmap = (struct fbcmap *) arg;
+		__get_user_ret(count, &cmap->count, -EFAULT);
+		__get_user_ret(index, &cmap->index, -EFAULT);
+		if ((index < 0) || (index > 255))
+			return -EINVAL;
+		if (index + count > 256)
+			count = 256 - cmap->index;
+		__get_user_ret(rp, &cmap->red, -EFAULT);
+		__get_user_ret(gp, &cmap->green, -EFAULT);
+		__get_user_ret(bp, &cmap->blue, -EFAULT);
+		if(verify_area (VERIFY_READ, rp, cmap->count)) return -EFAULT;
+		if(verify_area (VERIFY_READ, gp, cmap->count)) return -EFAULT;
+		if(verify_area (VERIFY_READ, bp, cmap->count)) return -EFAULT;
+
+		end = index + count;
+		for (i = index; i < end; i++){
+			__get_user_ret(fb->color_map CM(i,0), rp, -EFAULT);
+			__get_user_ret(fb->color_map CM(i,1), gp, -EFAULT);
+			__get_user_ret(fb->color_map CM(i,2), bp, -EFAULT);
+			rp++; gp++; bp++;
+		}
+		(*fb->loadcmap)(fb, cmap->index, count);
+                break;			
+	}
+
+	case FBIOGCURMAX: {
+		struct fbcurpos *p = (struct fbcurpos *) arg;
+		if (!fb->setcursor) return -EINVAL;
+		if(verify_area (VERIFY_WRITE, p, sizeof (struct fbcurpos)))
+			return -EFAULT;
+		__put_user_ret(fb->cursor.hwsize.fbx, &p->fbx, -EFAULT);
+		__put_user_ret(fb->cursor.hwsize.fby, &p->fby, -EFAULT);
+		break;
+	}
+	case FBIOSCURSOR:
+		if (!fb->setcursor) return -EINVAL;
+ 		if (fb == fbinfo) {
+ 			if (vt_cons[fg_console]->vc_mode == KD_TEXT)
+ 				return -EINVAL; /* Don't let graphics programs hide our nice text cursor */
+ 			sun_hw_cursor_shown = 0; /* Forget state of our text cursor */
+		}
+		return sun_hw_scursor ((struct fbcursor *) arg, fb);
+
+	case FBIOSCURPOS:
+		if (!fb->setcursor) return -EINVAL;
+                /* Don't let graphics programs move our nice text cursor */
+ 		if (fb == fbinfo) {
+ 			if (vt_cons[fg_console]->vc_mode == KD_TEXT)
+ 				return -EINVAL; /* Don't let graphics programs move our nice text cursor */
+ 		}
+		i= verify_area (VERIFY_READ, (void *) arg, sizeof (struct fbcurpos));
+		if (i) return i;
+		fb->cursor.cpos = *(struct fbcurpos *)arg;
+		(*fb->setcursor) (fb);
+		break;
+		
+	default:
+		if (fb->ioctl){
+			i = fb->ioctl (inode, file, cmd, arg, fb);
+			if (i == -ENOSYS) {
+				printk ("[[FBIO: %8.8x]]\n", cmd);
+				return -EINVAL;
+			}
+			return i;
+		}
+		printk ("[[FBIO: %8.8x]]\n", cmd);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int
+fb_close (struct inode * inode, struct file *filp)
+{
+	fbinfo_t *fb;
+	struct fbcursor cursor;
+	FB_SETUP(EBADF)	
+
+	fb = &fbinfo[minor];
+	
+	if (!minor)
+		vt_cons [fb->vtconsole]->vc_mode = KD_TEXT;
+
+	/* Leaving graphics mode, turn off the cursor */
+	if (fb->mmaped)
+		sun_clear_fb (minor);
+	cursor.set    = FB_CUR_SETCUR;
+	cursor.enable = 0;
+	
+	/* Reset the driver */
+	if (fb->reset)
+		fb->reset(fb);
+
+	if (fb->open)
+		fb->open = 0;
+	fb_ioctl (inode, filp, FBIOSCURPOS, (unsigned long) &cursor);
+	set_other_palette (minor);
+	if (!minor) {
+		render_screen ();
+		set_cursor (fg_console);
+	} else if (fb->blank)
+		(*fb->blank)(fb);
+	return 0;
+}
+
+static int
+fb_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma)
+{
+	fbinfo_t *fb;
+	FB_SETUP(ENXIO)
+
+	fb = &fbinfo [minor];
+
+	if (fb->mmap){
+		int v;
+		
+		v = (*fb->mmap)(inode, file, vma, fb->base, fb);
+		if (v) return v;
+		if (!fb->mmaped) {
+			fb->mmaped = 1;
+			if (!minor) {
+				fb->vtconsole = fg_console;
+				vt_cons [fg_console]->vc_mode = KD_GRAPHICS;
+			} else {
+				if (fb->unblank && !fb->blanked)
+					(*fb->unblank)(fb);
+			}
+		}
+		return 0;
+	} else
+		return -ENXIO;
+}
+
+static struct file_operations graphdev_fops =
+{
+	NULL,			/* lseek */
+	NULL,			/* read */
+	NULL,			/* write */
+	NULL,			/* readdir */
+	NULL,			/* select */
+	fb_ioctl,
+	fb_mmap,
+	fb_open,		/* open */
+	(void(*)(struct inode *, struct file *))
+	fb_close,		/* close */
+};
+
+__initfunc(int fb_init (void))
+{
+	/* Register the frame buffer device */
+	if (register_chrdev (GRAPHDEV_MAJOR, "graphics", &graphdev_fops)){
+		printk ("Could not register graphics device\n");
+		return -EIO;
+	}
+	return 0; /* success */
+}    
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c
--- v2.1.15/linux/drivers/sbus/char/sunkbd.c	Sun Nov 10 20:12:12 1996
+++ linux/drivers/sbus/char/sunkbd.c	Fri Dec 13 11:37:33 1996
@@ -14,11 +14,15 @@
 #include <linux/signal.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
+#include <linux/random.h>
+#include <linux/init.h>
+
 #include <asm/kbio.h>
 #include <asm/vuid_event.h>
 #include <asm/delay.h>
 #include <asm/bitops.h>
 #include <asm/oplib.h>
+#include <asm/uaccess.h>
 
 #include "../../char/kbd_kern.h"
 #include "../../char/diacr.h"
@@ -89,6 +93,7 @@
 static struct tty_struct **ttytab;
 static struct kbd_struct * kbd = kbd_table;
 static struct tty_struct * tty = NULL;
+static int compose_led_on = 0;
 
 extern void compute_shiftstate(void);
 
@@ -141,8 +146,8 @@
 #define SUNKBD_TYPE3        0x03
 #define SUNKBD_TYPE4        0x04
 
-#define SUNKBD_LOUT_TYP4    0x00
-#define SUNKBD_LOUT_TYP5    0x22
+#define SUNKBD_LOUT_TYP4    	0x00
+#define SUNKBD_LOUT_TYP5_MASK   0x20
 
 volatile int kbd_reset_pending;
 volatile int kbd_layout_pending;
@@ -213,6 +218,8 @@
 		retval |= LED_NLOCK;
 	if(vcleds & (1<<VC_CAPSLOCK))
 		retval |= LED_CLOCK;
+	if(compose_led_on)
+		retval |= LED_CMPOSE;
 	return retval;
 }
 
@@ -331,6 +338,21 @@
   0, 0, 0, 0, 0, 0, 0, 0			      /* 0x78-0x7f */
 };
 
+/* we use this map to determine if a particular key should not be
+   autorepeated. We don't autorepeat CONTROL, LSHIFT, CAPS,
+   ALT, LMETA, RSHIFT, RMETA, ALTG and COMPOSE */
+static unsigned char norepeat_keys[128] = {
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,  /* 0x00-0x0f */
+	0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x10-0x1f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x20-0x2f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x30-0x3f */
+	0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,  /* 0x40-0x4f */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /* 0x50-0x5f */
+	0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,  /* 0x60-0x6f */
+	0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0,  /* 0x70-0x7f */
+};
+
+
 int setkeycode(unsigned int scancode, unsigned int keycode)
 {
 	if (scancode < SC_LIM || scancode > 255 || keycode > 127)
@@ -401,7 +423,9 @@
 		kbd_layout_pending = 0;
 		return;
 	} else if(ch == SKBD_ALLUP) {
-		/* eat it */
+		del_timer (&auto_repeat_timer);
+		memset(key_down, 0, sizeof(key_down));
+		compute_shiftstate();
 		return;
 	}
 #ifdef SKBD_DEBUG
@@ -413,11 +437,13 @@
 #endif
 
 	/* Whee, a real character. */
-	if (regs){
+	if(regs) {
 		pt_regs = regs;
 		last_keycode = keycode = ch;
-	} else
+	} else {
 		keycode = ch;
+	}
+	add_keyboard_randomness(keycode);
 	
 	mark_bh(KEYBOARD_BH);
 	do_poke_blanked_console = 1;
@@ -441,8 +467,10 @@
 		rep = 0;
 		clear_bit(keycode, key_down);
 	} else {
-		auto_repeat_timer.expires = jiffies+HZ/5;
-		add_timer (&auto_repeat_timer);
+		if (!norepeat_keys[keycode]) {
+			auto_repeat_timer.expires = jiffies+HZ/5;
+			add_timer (&auto_repeat_timer);
+		}
 		rep = set_bit(keycode, key_down);
 	}
 
@@ -661,6 +689,8 @@
 static void compose(void)
 {
 	dead_key_next = 1;
+	compose_led_on = 1;
+	set_leds();
 }
 
 int spawnpid, spawnsig;
@@ -718,8 +748,11 @@
 	if (up_flag)
 		return;		/* no action, if this is a key release */
 
-	if (diacr)
+	if (diacr) {
 		value = handle_diacr(value);
+		compose_led_on = 0;
+		set_leds();
+	}
 
 	if (dead_key_next) {
 		dead_key_next = 0;
@@ -782,7 +815,7 @@
 {
 	if (up_flag)
 		return;
-	want_console = value;
+	set_console(value);
 }
 
 static void do_fn(unsigned char value, char up_flag)
@@ -971,6 +1004,7 @@
  */
 
 static unsigned char ledstate = 0xff; /* undefined */
+static unsigned char sunkbd_ledstate = 0xff; /* undefined */
 static unsigned char ledioctl;
 
 unsigned char getledstate(void) {
@@ -1050,14 +1084,55 @@
 static void kbd_bh(void)
 {
 	unsigned char leds = getleds();
+	unsigned char kbd_leds = vcleds_to_sunkbd(leds);
 
-	if (leds != ledstate) {
+	if (kbd_leds != sunkbd_ledstate) {
 		ledstate = leds;
+		sunkbd_ledstate = kbd_leds;
 		send_cmd(SKBDCMD_SETLED);
-		send_cmd(vcleds_to_sunkbd(leds));
+		send_cmd(kbd_leds);
 	}
 }
 
+/* Support for keyboard "beeps". */ 
+
+/* Timer routine to turn off the beep after the interval expires. */
+static void sunkbd_kd_nosound(unsigned long __unused)
+{
+	send_cmd(SKBDCMD_BELLOFF);
+}
+
+/*
+ * Initiate a keyboard beep. If the frequency is zero, then we stop
+ * the beep. Any other frequency will start a monotone beep. The beep
+ * will be stopped by a timer after "ticks" jiffies. If ticks is 0,
+ * then we do not start a timer.
+ */
+static void sunkbd_kd_mksound(unsigned int hz, unsigned int ticks)
+{
+	unsigned long flags;
+	static struct timer_list sound_timer = { NULL, NULL, 0, 0,
+						 sunkbd_kd_nosound };
+
+	save_flags(flags);
+	cli();
+
+	del_timer(&sound_timer);
+
+	if (hz) {
+		send_cmd(SKBDCMD_BELLON);
+		if (ticks) {
+			sound_timer.expires = jiffies + ticks;
+			add_timer(&sound_timer);
+		}
+	} else
+		send_cmd(SKBDCMD_BELLOFF);
+
+	restore_flags(flags);
+}
+
+extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);
+
 int kbd_init(void)
 {
 	int i, opt_node;
@@ -1075,6 +1150,8 @@
 
 	ttytab = console_driver.table;
 
+	kd_mksound = sunkbd_kd_mksound;
+
 	/* XXX Check keyboard-click? property in 'options' PROM node XXX */
 	if(sparc_cpu_model != sun4) {
 		opt_node = prom_getchild(prom_root_node);
@@ -1119,8 +1196,8 @@
 	wake_up_interruptible (&kbd_wait);
 }
 
-static int
-kbd_read (struct inode *inode, struct file *f, char *buffer, int count)
+static long
+kbd_read (struct inode *inode, struct file *f, char *buffer, unsigned long count)
 {
 	struct wait_queue wait = { current, NULL };
 	char *end, *p;
@@ -1141,7 +1218,7 @@
 	end = buffer+count;
 	p = buffer;
 	for (; p < end && kbd_head != kbd_tail; p += sizeof (Firm_event)){
-		*(Firm_event *)p = kbd_queue [kbd_tail];
+		copy_to_user_ret((Firm_event *)p, &kbd_queue [kbd_tail], sizeof(Firm_event), -EFAULT);
 #ifdef KBD_DEBUG
 		printk ("[%s]", kbd_queue [kbd_tail].value == VKEY_UP ? "UP" : "DOWN");
 #endif
@@ -1177,33 +1254,29 @@
 static int
 kbd_ioctl (struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
 {
+	unsigned char c;
+	unsigned char leds = 0;
+	int value;
+
 	switch (cmd){
-	case KIOCTYPE:	          /* return keyboard type */
-		if (verify_area (VERIFY_WRITE, (void *)arg, sizeof (int)))
-			return -EFAULT;
-	        *(int *) arg = sunkbd_type;
+	case KIOCTYPE:		  /* return keyboard type */
+		put_user_ret(sunkbd_type, (int *) arg, -EFAULT);
 		break;
 	case KIOCGTRANS:
-		if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int)))
-			return -EFAULT;
-	        *(int *) arg = TR_UNTRANS_EVENT;
+		put_user_ret(TR_UNTRANS_EVENT, (int *) arg, -EFAULT);
 		break;
 	case KIOCTRANS:
-		if (verify_area (VERIFY_READ, (void *) arg, sizeof (int)))
-			return -EFAULT;
-	        if (*(int *) arg != TR_UNTRANS_EVENT)
+		get_user_ret(value, (int *) arg, -EFAULT);
+		if (value != TR_UNTRANS_EVENT)
 			return -EINVAL;
 		break;
 	case KIOCLAYOUT:
-		if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int)))
-			return -EFAULT;
-	        *(int *) arg = sunkbd_layout;
+		put_user_ret(sunkbd_layout, (int *) arg, -EFAULT);
 		break;
 	case KIOCSDIRECT:
-		if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int)))
-			return -EFAULT;
 #ifndef CODING_NEW_DRIVER
-		if (*(int *) arg)
+		get_user_ret(value, (int *) arg, -EFAULT);
+		if(value)
 			kbd_redirected = fg_console + 1;
 		else
 			kbd_redirected = 0;
@@ -1211,16 +1284,40 @@
 #endif
 		break;
 	case KIOCCMD:
-		/* Need to support beep on/off, keyclick on/off */
-		return 0;
+		get_user_ret(value, (int *) arg, -EFAULT);
+		c = (unsigned char) value;
+		switch (c) {
+			case SKBDCMD_CLICK:
+			case SKBDCMD_NOCLICK:
+				send_cmd(c);
+				return 0;
+			case SKBDCMD_BELLON:
+				kd_mksound(1,0);
+				return 0;
+			case SKBDCMD_BELLOFF:
+				kd_mksound(0,0);
+				return 0;
+			default:
+				return -EINVAL;
+		}
+	case KIOCSLED:
+		get_user_ret(c, (unsigned char *) arg, -EFAULT);
+			
+		if (c & LED_SCRLCK) leds |= (1 << VC_SCROLLOCK);
+		if (c & LED_NLOCK) leds |= (1 << VC_NUMLOCK);
+		if (c & LED_CLOCK) leds |= (1 << VC_CAPSLOCK);
+		compose_led_on = !!(c & LED_CMPOSE);
+		setledstate(kbd_table + fg_console, leds);
+		break;
+	case KIOCGLED:
+		put_user_ret(vcleds_to_sunkbd(getleds()), (unsigned char *) arg, -EFAULT);
+		break;
 	case FIONREAD:		/* return number of bytes in kbd queue */
 	{
 		int count;
 		
-		if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int)))
-			return -EFAULT;
 		count = kbd_head - kbd_tail;
-		* (int *)arg = (count < 0) ? KBD_QSIZE - count : count;
+		put_user_ret((count < 0) ? KBD_QSIZE - count : count, (int *) arg, -EFAULT);
 		return 0;
 	}
 	default:
@@ -1269,8 +1366,7 @@
 	NULL,			/* revalidate */
 };
 
-void
-keyboard_zsinit(void)
+__initfunc(void keyboard_zsinit(void))
 {
 	int timeout = 0;
 
@@ -1295,15 +1391,18 @@
 		while(timeout++ < 500000)
 			barrier();
 		printk("Sun TYPE %d keyboard detected ",
-		       ((sunkbd_layout==SUNKBD_LOUT_TYP5) ? 5 : 4));
+		       ((sunkbd_layout & SUNKBD_LOUT_TYP5_MASK) ? 5 : 4));
 	}
 	if(sunkbd_type == SUNKBD_TYPE2)
 		sunkbd_clickp = 0;
 
-	if(sunkbd_clickp)
+	if(sunkbd_clickp) {
+		send_cmd(SKBDCMD_CLICK);
 		printk("with keyclick\n");
-	else
+	} else {
+		send_cmd(SKBDCMD_NOCLICK);
 		printk("without keyclick\n");
+	}
 
 	/* Dork with led lights, then turn them all off */
 	send_cmd(SKBDCMD_SETLED); send_cmd(0xf); /* All on */
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/sunkeymap.c linux/drivers/sbus/char/sunkeymap.c
--- v2.1.15/linux/drivers/sbus/char/sunkeymap.c	Thu Apr 25 13:27:42 1996
+++ linux/drivers/sbus/char/sunkeymap.c	Fri Dec 13 11:37:33 1996
@@ -26,8 +26,8 @@
 
 u_short shift_map[NR_KEYS] = {
 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf10a,	0xf10b,	0xf113,
-	0xf10c,	0xf10a,	0xf10d,	0xf10b,	0xf10e,	0xf701,	0xf105,	0xf200,
-	0xf110,	0xf107,	0xf112,	0xf703,	0xf603,	0xf11d,	0xf200,	0xf203,
+	0xf10c,	0xf10a,	0xf10d,	0xf10b,	0xf10e,	0xf701,	0xf10f,	0xf200,
+	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,
@@ -45,7 +45,7 @@
 
 u_short altgr_map[NR_KEYS] = {
 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf50c,	0xf50d,	0xf515,
-	0xf50e,	0xf516,	0xf50f,	0xf517,	0xf510,	0xf701,	0xf200,	0xf200,
+	0xf50e,	0xf516,	0xf50f,	0xf517,	0xf510,	0xf701,	0xf511,	0xf200,
 	0xf512,	0xf513,	0xf514,	0xf703,	0xf603,	0xf11d,	0xf200,	0xf202,
 	0xf601,	0xf200,	0xf200,	0xf600,	0xf602,	0xf200,	0xf200,	0xf040,
 	0xf200,	0xf024,	0xf200,	0xf200,	0xf07b,	0xf05b,	0xf05d,	0xf07d,
@@ -64,7 +64,7 @@
 
 u_short ctrl_map[NR_KEYS] = {
 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf100,	0xf101,	0xf109,
-	0xf102,	0xf10a,	0xf103,	0xf10b,	0xf104,	0xf701,	0xf200,	0xf200,
+	0xf102,	0xf10a,	0xf103,	0xf10b,	0xf104,	0xf701,	0xf105,	0xf200,
 	0xf107,	0xf200,	0xf108,	0xf703,	0xf603,	0xf11d,	0xf200,	0xf204,
 	0xf601,	0xf200,	0xf200,	0xf600,	0xf602,	0xf200,	0xf200,	0xf000,
 	0xf01b,	0xf01c,	0xf01d,	0xf01e,	0xf01f,	0xf07f,	0xf200,	0xf200,
@@ -121,14 +121,14 @@
 
 u_short ctrl_alt_map[NR_KEYS] = {
 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf500,	0xf501,	0xf509,
-	0xf502,	0xf50a,	0xf503,	0xf50b,	0xf504,	0xf701,	0xf200,	0xf200,
+	0xf502,	0xf50a,	0xf503,	0xf50b,	0xf504,	0xf701,	0xf505,	0xf200,
 	0xf507,	0xf200,	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,	0xf20c,	0xf200,	0xf114,	0xf200,	0xf811,	0xf817,
 	0xf805,	0xf812,	0xf814,	0xf819,	0xf815,	0xf809,	0xf80f,	0xf810,
-	0xf200,	0xf200,	0xf200,	0xf20e,	0xf307,	0xf308,	0xf309,	0xf30b,
+	0xf200,	0xf200,	0xf20c,	0xf20e,	0xf307,	0xf308,	0xf309,	0xf30b,
 	0xf200,	0xf200,	0xf117,	0xf200,	0xf702,	0xf801,	0xf813,	0xf804,
 	0xf806,	0xf807,	0xf808,	0xf80a,	0xf80b,	0xf80c,	0xf200,	0xf200,
 	0xf200,	0xf201,	0xf30e,	0xf304,	0xf305,	0xf306,	0xf300,	0xf200,
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/sunkeymap.map linux/drivers/sbus/char/sunkeymap.map
--- v2.1.15/linux/drivers/sbus/char/sunkeymap.map	Mon May  6 12:26:09 1996
+++ linux/drivers/sbus/char/sunkeymap.map	Fri Dec 13 11:37:33 1996
@@ -44,15 +44,17 @@
 	alt	keycode			0x0c = Console_5
 	control	alt	keycode		0x0c = Console_5
 keycode	0x0d = AltGr
-keycode 0x0e = F6			F6
+keycode 0x0e = F6			F16	Console_18
+	control	keycode			0x0e = F6
 	alt	keycode			0x0e = Console_6
+	control	alt	keycode		0x0e = Console_6
 # BLANK KEY on type 5 keyboards
 keycode 0x0f =
 keycode 0x10 = F7			F17	Console_19
 	control	Keycode			0x10 = F7
 	alt	keycode			0x10 = Console_7
 	control	alt	keycode		0x10 = Console_7
-keycode 0x11 = F8			F8	Console_20
+keycode 0x11 = F8			F18	Console_20
 	control	keycode			0x10 = F8
 	alt	keycode			0x10 = Console_8
 	control	alt	keycode		0x10 = Console_8
@@ -159,6 +161,7 @@
 keycode 0x42 = Delete		Delete
 	control	keycode				0x42 = BackSpace
 	alt	keycode				0x43 = Meta_Delete
+	control	alt	keycode			0x42 = Boot
 keycode 0x43 = Compose
 keycode 0x44 = KP_7
 	alt	keycode				0x44 = Ascii_7
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/sunmouse.c linux/drivers/sbus/char/sunmouse.c
--- v2.1.15/linux/drivers/sbus/char/sunmouse.c	Thu Apr 25 13:27:42 1996
+++ linux/drivers/sbus/char/sunmouse.c	Fri Dec 13 11:37:33 1996
@@ -9,6 +9,7 @@
  * Dec/19/95 Added SunOS mouse ioctls - miguel.
  * Jan/5/96  Added VUID support, sigio support - miguel.
  * Mar/5/96  Added proper mouse stream support - miguel.
+ * Sep/96    Allow more than one reader -miguel.
  */
 
 /* The mouse is run off of one of the Zilog serial ports.  On
@@ -31,7 +32,9 @@
  * set when the device is opened and allows the application to see the
  * mouse character stream as we get it from the serial (for gpm for
  * example).  The second method, VUID_FIRM_EVENT will provide cooked
- * events in Firm_event records.
+ * events in Firm_event records as expected by SunOS/Solaris applications.
+ *
+ * FIXME: We need to support more than one mouse.
  * */
 
 #include <linux/kernel.h>
@@ -42,7 +45,8 @@
 #include <linux/errno.h>
 #include <linux/miscdevice.h>
 #include <linux/mm.h>
-#include <asm/segment.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/vuid_event.h>
 #include <linux/random.h>
@@ -259,11 +263,10 @@
 static int
 sun_mouse_open(struct inode * inode, struct file * file)
 {
+	if(sunmouse.active++)
+		return 0;
 	if(!sunmouse.present)
 		return -EINVAL;
-	if(sunmouse.active)
-		return -EBUSY;
-	sunmouse.active = 1;
 	sunmouse.ready = sunmouse.delta_x = sunmouse.delta_y = 0;
 	sunmouse.button_state = 0x80;
 	sunmouse.vuid_mode = VUID_NATIVE;
@@ -284,20 +287,22 @@
 static void
 sun_mouse_close(struct inode *inode, struct file *file)
 {
-	sunmouse.active = sunmouse.ready = 0;
 	sun_mouse_fasync (inode, file, 0);
+	if (--sunmouse.active)
+		return;
+	sunmouse.ready = 0;
 }
 
-static int
+static long
 sun_mouse_write(struct inode *inode, struct file *file, const char *buffer,
-		int count)
+		unsigned long count)
 {
 	return -EINVAL;  /* foo on you */
 }
 
-static int
+static long
 sun_mouse_read(struct inode *inode, struct file *file, char *buffer,
-	       int count)
+	       unsigned long count)
 {
 	struct wait_queue wait = { current, NULL };
 
@@ -316,7 +321,8 @@
 		char *p = buffer, *end = buffer+count;
 		
 		while (p < end && !queue_empty ()){
-			*(Firm_event *)p = *get_from_queue ();
+			copy_to_user_ret((Firm_event *)p, get_from_queue(),
+				     sizeof(Firm_event), -EFAULT);
 			p += sizeof (Firm_event);
 		}
 		sunmouse.ready = !queue_empty ();
@@ -325,11 +331,12 @@
 	} else {
 		int c;
 		
-		for (c = count; !queue_empty () && c; c--){
-			*buffer++ = sunmouse.queue.stream [sunmouse.tail];
+		for (c = count; !queue_empty() && c; c--){
+			put_user_ret(sunmouse.queue.stream[sunmouse.tail], buffer, -EFAULT);
+			buffer++;
 			sunmouse.tail = (sunmouse.tail + 1) % STREAM_SIZE;
 		}
-		sunmouse.ready = !queue_empty ();
+		sunmouse.ready = !queue_empty();
 		inode->i_atime = CURRENT_TIME;
 		return count-c;
 	}
@@ -358,22 +365,28 @@
 	switch (cmd){
 		/* VUIDGFORMAT - Get input device byte stream format */
 	case _IOR('v', 2, int):
-		i = verify_area (VERIFY_WRITE, (void *)arg, sizeof (int));
-		if (i) return i;
-		*(int *)arg = sunmouse.vuid_mode;
+		put_user_ret(sunmouse.vuid_mode, (int *) arg, -EFAULT);
 		break;
 
 		/* VUIDSFORMAT - Set input device byte stream format*/
 	case _IOW('v', 1, int):
-		i = verify_area (VERIFY_READ, (void *)arg, sizeof (int));
-	        if (i) return i;
-		i = *(int *) arg;
+		get_user_ret(i, (int *) arg, -EFAULT);
 		if (i == VUID_NATIVE || i == VUID_FIRM_EVENT){
-			sunmouse.vuid_mode = *(int *)arg;
+			int value;
+
+			get_user_ret(value, (int *)arg, -EFAULT);
+			sunmouse.vuid_mode = value;
 			sunmouse.head = sunmouse.tail = 0;
 		} else
 			return -EINVAL;
 		break;
+
+	case 0x8024540b:
+	case 0x40245408:
+		/* This is a buggy application doing termios on the mouse driver */
+		/* we ignore it.  I keep this check here so that we will notice   */
+		/* future mouse vuid ioctls */
+		break;
 		
 	default:
 		printk ("[MOUSE-ioctl: %8.8x]\n", cmd);
@@ -400,8 +413,7 @@
 	SUN_MOUSE_MINOR, "sunmouse", &sun_mouse_fops
 };
 
-int
-sun_mouse_init(void)
+__initfunc(int sun_mouse_init(void))
 {
 	printk("Sun Mouse-Systems mouse driver version 1.00\n");
 	sunmouse.present = 1;
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/sunserial.c linux/drivers/sbus/char/sunserial.c
--- v2.1.15/linux/drivers/sbus/char/sunserial.c	Thu Dec 12 17:02:44 1996
+++ linux/drivers/sbus/char/sunserial.c	Fri Dec 13 11:37:37 1996
@@ -1,6 +1,8 @@
-/* serial.c: Serial port driver for the Sparc.
+/* $Id: sunserial.c,v 1.24 1996/11/21 16:57:56 jj Exp $
+ * serial.c: Serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Eddie C. Dost   (ecd@skynet.be)
  */
 
 #include <linux/errno.h>
@@ -16,37 +18,39 @@
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/kernel.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/oplib.h>
 #include <asm/system.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
 #include <asm/bitops.h>
 #include <asm/delay.h>
 #include <asm/kdebug.h>
 
 #include "sunserial.h"
 
-#define NUM_SERIAL 2     /* Two chips on board. */
+static int num_serial = 2; /* sun4/sun4c/sun4m - Two chips on board. */
+#define NUM_SERIAL num_serial
 #define NUM_CHANNELS (NUM_SERIAL * 2)
 
 #define KEYBOARD_LINE 0x2
 #define MOUSE_LINE    0x3
 
-struct sun_zslayout *zs_chips[NUM_SERIAL] = { 0, 0, };
-struct sun_zschannel *zs_channels[NUM_CHANNELS] = { 0, 0, 0, 0, };
+struct sun_zslayout **zs_chips;
+struct sun_zschannel **zs_channels;
 struct sun_zschannel *zs_conschan;
 struct sun_zschannel *zs_mousechan;
 struct sun_zschannel *zs_kbdchan;
 struct sun_zschannel *zs_kgdbchan;
-int zs_nodes[NUM_SERIAL] = { 0, 0, };
+int *zs_nodes;
 
-struct sun_serial zs_soft[NUM_CHANNELS];
+struct sun_serial *zs_soft;
 struct sun_serial *zs_chain;  /* IRQ servicing chain */
 int zilog_irq;
 
-struct tty_struct zs_ttys[NUM_CHANNELS];
+struct tty_struct *zs_ttys;
 /** struct tty_struct *zs_constty; **/
 
 /* Console hooks... */
@@ -66,18 +70,34 @@
 
 static unsigned char kgdb_regs[16] = {
 	0, 0, 0,                     /* write 0, 1, 2 */
-	(Rx8 | RxENABLE),            /* write 3 */
+	(Rx8 | RxENAB),              /* write 3 */
 	(X16CLK | SB1 | PAR_EVEN),   /* write 4 */
-	(Tx8 | TxENAB),              /* write 5 */
+	(DTR | Tx8 | TxENAB),        /* write 5 */
 	0, 0, 0,                     /* write 6, 7, 8 */
 	(NV),                        /* write 9 */
 	(NRZ),                       /* write 10 */
 	(TCBR | RCBR),               /* write 11 */
 	0, 0,                        /* BRG time constant, write 12 + 13 */
-	(BRSRC | BRENABL),           /* write 14 */
+	(BRSRC | BRENAB),            /* write 14 */
 	(DCDIE)                      /* write 15 */
 };
 
+static unsigned char zscons_regs[16] = {
+	0,                           /* write 0 */
+	(EXT_INT_ENAB | INT_ALL_Rx), /* write 1 */
+	0,                           /* write 2 */
+	(Rx8 | RxENAB),              /* write 3 */
+	(X16CLK),                    /* write 4 */
+	(DTR | Tx8 | TxENAB),        /* write 5 */
+	0, 0, 0,                     /* write 6, 7, 8 */
+	(NV | MIE),                  /* write 9 */
+	(NRZ),                       /* write 10 */
+	(TCBR | RCBR),               /* write 11 */
+	0, 0,                        /* BRG time constant, write 12 + 13 */
+	(BRSRC | BRENAB),            /* write 14 */
+	(DCDIE | CTSIE | TxUIE | BRKIE) /* write 15 */
+};
+
 #define ZS_CLOCK         4915200   /* Zilog input clock rate */
 
 DECLARE_TASK_QUEUE(tq_serial);
@@ -106,9 +126,9 @@
 
 static void change_speed(struct sun_serial *info);
 
-static struct tty_struct *serial_table[NUM_CHANNELS];
-static struct termios *serial_termios[NUM_CHANNELS];
-static struct termios *serial_termios_locked[NUM_CHANNELS];
+static struct tty_struct **serial_table;
+static struct termios **serial_termios;
+static struct termios **serial_termios_locked;
 
 #ifndef MIN
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
@@ -160,7 +180,8 @@
  * register access, other machines handle this in hardware via auxiliary
  * flip-flops which implement the settle time we do in software.
  */
-static inline unsigned char read_zsreg(struct sun_zschannel *channel, unsigned char reg)
+static inline unsigned char read_zsreg(struct sun_zschannel *channel,
+				       unsigned char reg)
 {
 	unsigned char retval;
 
@@ -171,48 +192,76 @@
 	return retval;
 }
 
-static inline void write_zsreg(struct sun_zschannel *channel, unsigned char reg, unsigned char value)
+static inline void write_zsreg(struct sun_zschannel *channel,
+			       unsigned char reg, unsigned char value)
 {
 	channel->control = reg;
 	udelay(5);
 	channel->control = value;
 	udelay(5);
-	return;
 }
 
-static inline void load_zsregs(struct sun_zschannel *channel, unsigned char *regs)
+static inline void load_zsregs(struct sun_serial *info, unsigned char *regs)
 {
+	unsigned long flags;
+	struct sun_zschannel *channel = info->zs_channel;
+
 	ZS_CLEARERR(channel);
 	ZS_CLEARFIFO(channel);
 	/* Load 'em up */
+	save_flags(flags); cli();
+	if (info->channelA)
+		write_zsreg(channel, R9, CHRA);
+	else
+		write_zsreg(channel, R9, CHRB);
+	udelay(20);	/* wait for some old sun4's */
 	write_zsreg(channel, R4, regs[R4]);
-	write_zsreg(channel, R10, regs[R10]);
-	write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
+	write_zsreg(channel, R3, regs[R3] & ~RxENAB);
 	write_zsreg(channel, R5, regs[R5] & ~TxENAB);
-	write_zsreg(channel, R1, regs[R1]);
-	write_zsreg(channel, R9, regs[R9]);
+	write_zsreg(channel, R9, regs[R9] & ~MIE);
+	write_zsreg(channel, R10, regs[R10]);
 	write_zsreg(channel, R11, regs[R11]);
 	write_zsreg(channel, R12, regs[R12]);
 	write_zsreg(channel, R13, regs[R13]);
+	write_zsreg(channel, R14, regs[R14] & ~BRENAB);
 	write_zsreg(channel, R14, regs[R14]);
-	write_zsreg(channel, R15, regs[R15]);
+	write_zsreg(channel, R14, (regs[R14] & ~SNRZI) | BRENAB);
 	write_zsreg(channel, R3, regs[R3]);
 	write_zsreg(channel, R5, regs[R5]);
-	return;
+	write_zsreg(channel, R15, regs[R15]);
+	write_zsreg(channel, R0, RES_EXT_INT);
+	write_zsreg(channel, R0, RES_EXT_INT);
+	write_zsreg(channel, R1, regs[R1]);
+	write_zsreg(channel, R9, regs[R9]);
+	restore_flags(flags);
+}
+
+static inline void zs_put_char(struct sun_zschannel *channel, char ch)
+{
+	int loops = 0;
+
+	while((channel->control & Tx_BUF_EMP) == 0 && loops < 10000) {
+		loops++;
+		udelay(5);
+	}
+	channel->data = ch;
+	udelay(5);
 }
 
 /* Sets or clears DTR/RTS on the requested line */
 static inline void zs_rtsdtr(struct sun_serial *ss, int set)
 {
+	unsigned long flags;
+
+	save_flags(flags); cli();
 	if(set) {
 		ss->curregs[5] |= (RTS | DTR);
-		ss->pendregs[5] = ss->curregs[5];
 		write_zsreg(ss->zs_channel, 5, ss->curregs[5]);
 	} else {
 		ss->curregs[5] &= ~(RTS | DTR);
-		ss->pendregs[5] = ss->curregs[5];
 		write_zsreg(ss->zs_channel, 5, ss->curregs[5]);
 	}
+	restore_flags(flags);
 	return;
 }
 
@@ -230,23 +279,7 @@
 	brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
 	kgdb_regs[R12] = (brg & 255);
 	kgdb_regs[R13] = ((brg >> 8) & 255);
-	load_zsregs(ss->zs_channel, kgdb_regs);
-}
-
-/* Utility routines for the Zilog */
-static inline int get_zsbaud(struct sun_serial *ss)
-{
-	struct sun_zschannel *channel = ss->zs_channel;
-	int brg;
-
-	/* The baud rate is split up between two 8-bit registers in
-	 * what is termed 'BRG time constant' format in my docs for
-	 * the chip, it is a function of the clk rate the chip is
-	 * receiving which happens to be constant.
-	 */
-	brg = ((read_zsreg(channel, 13)&0xff) << 8);
-	brg |= (read_zsreg(channel, 12)&0xff);
-	return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor)));
+	load_zsregs(ss, kgdb_regs);
 }
 
 /*
@@ -268,7 +301,6 @@
 	save_flags(flags); cli();
 	if (info->curregs[5] & TxENAB) {
 		info->curregs[5] &= ~TxENAB;
-		info->pendregs[5] &= ~TxENAB;
 		write_zsreg(info->zs_channel, 5, info->curregs[5]);
 	}
 	restore_flags(flags);
@@ -285,7 +317,6 @@
 	save_flags(flags); cli();
 	if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) {
 		info->curregs[5] |= TxENAB;
-		info->pendregs[5] = info->curregs[5];
 		write_zsreg(info->zs_channel, 5, info->curregs[5]);
 	}
 	restore_flags(flags);
@@ -307,7 +338,7 @@
 	   (((unsigned long)linux_dbvec)<=DEBUG_LASTVADDR))
 		sp_enter_debugger();
 	else
-		prom_halt();
+		prom_cmdline();
 
 	/* XXX We want to notify the keyboard driver that all
 	 * XXX keys are in the up state or else weird things
@@ -320,10 +351,14 @@
 /* On receive, this clears errors and the receiver interrupts */
 static inline void rs_recv_clear(struct sun_zschannel *zsc)
 {
+	unsigned long flags;
+
+	save_flags(flags); cli();
 	zsc->control = ERR_RES;
 	udelay(5);
 	zsc->control = RES_H_IUS;
 	udelay(5);
+	restore_flags(flags);
 }
 
 /*
@@ -366,7 +401,7 @@
 	struct tty_struct *tty = info->tty;
 	unsigned char ch, stat;
 
-	ch = info->zs_channel->data;
+	ch = (info->zs_channel->data) & info->parity_mask;
 	udelay(5);
 	stat = read_zsreg(info->zs_channel, R1);
 	udelay(5);
@@ -408,12 +443,14 @@
 			batten_down_hatches();
 			rs_recv_clear(info->zs_channel);
 			return;
+#if 0
 		} else if (ch == 1) {
 			show_state();
 			return;
 		} else if (ch == 2) {
 			show_buffers();
 			return;
+#endif
 		}
 		/* It is a 'keyboard interrupt' ;-) */
 		wake_up(&keypress_wait);
@@ -452,16 +489,9 @@
 
 static _INLINE_ void transmit_chars(struct sun_serial *info)
 {
-	/* P3: In theory we have to test readiness here because a
-	 * serial console can clog the chip through rs_put_char().
-	 * David did not do this. I think he relies on 3-chars FIFO in 8530.
-	 * Let's watch for lost _output_ characters. XXX
-	 */
-
 	if (info->x_char) {
 		/* Send next char */
-		info->zs_channel->data = info->x_char;
-		udelay(5);
+		zs_put_char(info->zs_channel, info->x_char);
 		info->x_char = 0;
 		goto clear_and_return;
 	}
@@ -474,8 +504,7 @@
 	}
 
 	/* Send char */
-	info->zs_channel->data = info->xmit_buf[info->xmit_tail++];
-	udelay(5);
+	zs_put_char(info->zs_channel, info->xmit_buf[info->xmit_tail++]);
 	info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
 	info->xmit_cnt--;
 
@@ -514,13 +543,11 @@
 		if((info->tty->termios->c_cflag & CRTSCTS) &&
 		   ((info->curregs[3] & AUTO_ENAB)==0)) {
 			info->curregs[3] |= AUTO_ENAB;
-			info->pendregs[3] |= AUTO_ENAB;
 			write_zsreg(info->zs_channel, 3, info->curregs[3]);
 		}
 	} else {
 		if((info->curregs[3] & AUTO_ENAB)) {
 			info->curregs[3] &= ~AUTO_ENAB;
-			info->pendregs[3] &= ~AUTO_ENAB;
 			write_zsreg(info->zs_channel, 3, info->curregs[3]);
 		}
 	}
@@ -543,74 +570,46 @@
  */
 void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
-	struct sun_serial * info;
+	struct sun_serial * info = (struct sun_serial *)dev_id;
 	unsigned char zs_intreg;
+	int i;
 
-	info = zs_chain;
-	if (!info)
-		return;
-
-	zs_intreg = read_zsreg(info->zs_channel, 3);
+	for (i = 0; i < NUM_SERIAL; i++) {
+		zs_intreg = read_zsreg(info->zs_channel, 3);
 
-	/* 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
-	 *       channel and is only valid when read from channel A.
-	 *       Yes... broken hardware...
-	 */
+		/* 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
+		 *       channel and is only valid when read from channel A.
+		 *       Yes... broken hardware...
+		 */
 #define CHAN_A_IRQMASK (CHARxIP | CHATxIP | CHAEXT)
 #define CHAN_B_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
 
-	/* *** Chip 1 *** */
-	/* Channel A -- /dev/ttya, could be the console */
-	if(zs_intreg & CHAN_A_IRQMASK) {
-		if (zs_intreg & CHARxIP)
-			receive_chars(info, regs);
-		if (zs_intreg & CHATxIP)
-			transmit_chars(info);
-		if (zs_intreg & CHAEXT)
-			status_handle(info);
-	}
-
-	info=info->zs_next;
-
-	/* Channel B -- /dev/ttyb, could be the console */
-	if(zs_intreg & CHAN_B_IRQMASK) {
-		if (zs_intreg & CHBRxIP)
-			receive_chars(info, regs);
-		if (zs_intreg & CHBTxIP)
-			transmit_chars(info);
-		if (zs_intreg & CHBEXT)
-			status_handle(info);
-	}
-
-	info = info->zs_next;
-
-	zs_intreg = read_zsreg(info->zs_channel, 3);
-	/* *** Chip 2 *** */
-	/* Channel A -- /dev/kbd, pass communication to keyboard driver */
-	if(zs_intreg & CHAN_A_IRQMASK) {
-		if (zs_intreg & CHARxIP)
-			receive_chars(info, regs);
-		if (zs_intreg & CHATxIP)
-			transmit_chars(info);
-		if (zs_intreg & CHAEXT)
-			status_handle(info);
-	}
-
-	info=info->zs_next;
-
-	/* Channel B -- /dev/mouse, pass communication to mouse driver */
-	if(zs_intreg & CHAN_B_IRQMASK) {
-		if (zs_intreg & CHBRxIP)
-			receive_chars(info, regs);
-		if (zs_intreg & CHBTxIP)
-			transmit_chars(info);
-		if (zs_intreg & CHBEXT)
-			status_handle(info);
-	}
+		/* Channel A -- /dev/ttya or /dev/kbd, could be the console */
+		if(zs_intreg & CHAN_A_IRQMASK) {
+			if (zs_intreg & CHARxIP)
+				receive_chars(info, regs);
+			if (zs_intreg & CHATxIP)
+				transmit_chars(info);
+			if (zs_intreg & CHAEXT)
+				status_handle(info);
+		}
 
-	return;
+		info=info->zs_next;
+
+		/* Channel B -- /dev/ttyb or /dev/mouse, could be the console */
+		if(zs_intreg & CHAN_B_IRQMASK) {
+			if (zs_intreg & CHBRxIP)
+				receive_chars(info, regs);
+			if (zs_intreg & CHBTxIP)
+				transmit_chars(info);
+			if (zs_intreg & CHBEXT)
+				status_handle(info);
+		}
+
+		info = info->zs_next;
+	}
 }
 
 /*
@@ -727,15 +726,12 @@
 	/*
 	 * Finally, enable sequencing and interrupts
 	 */
-	info->curregs[1] |= (info->curregs[1] & ~0x18) | (EXT_INT_ENAB|INT_ALL_Rx);
-	info->pendregs[1] = info->curregs[1];
-	info->curregs[3] |= (RxENABLE | Rx8);
-	info->pendregs[3] = info->curregs[3];
+	info->curregs[1] |= (info->curregs[1] & ~(RxINT_MASK)) |
+				(EXT_INT_ENAB | INT_ALL_Rx);
+	info->curregs[3] |= (RxENAB | Rx8);
 	/* We enable Tx interrupts as needed. */
 	info->curregs[5] |= (TxENAB | Tx8);
-	info->pendregs[5] = info->curregs[5];
 	info->curregs[9] |= (NV | MIE);
-	info->pendregs[9] = info->curregs[9];
 	write_zsreg(info->zs_channel, 3, info->curregs[3]);
 	write_zsreg(info->zs_channel, 5, info->curregs[5]);
 	write_zsreg(info->zs_channel, 9, info->curregs[9]);
@@ -817,57 +813,58 @@
 	if (!(port = info->port))
 		return;
 	i = cflag & CBAUD;
-	if (i & CBAUDEX) {
+	if (cflag & CBAUDEX) {
 		/* XXX CBAUDEX is not obeyed.
 		 * It is impossible at a 32bits SPARC.
 		 * But we have to report this to user ... someday.
 		 */
 		i = B9600;
 	}
-	info->zs_baud = baud_table[i];
-	info->clk_divisor = 16;
-
-	info->curregs[4] = X16CLK;
-	info->curregs[11] = TCBR | RCBR;
-	brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
-	info->curregs[12] = (brg & 255);
-	info->curregs[13] = ((brg >> 8) & 255);
-	info->curregs[14] = BRSRC | BRENABL;
+	if (i == 0) {
+		/* XXX B0, hangup the line. */
+		do_serial_hangup(info);
+	} else if (baud_table[i]) {
+		info->zs_baud = baud_table[i];
+		info->clk_divisor = 16;
+
+		info->curregs[4] = X16CLK;
+		info->curregs[11] = TCBR | RCBR;
+		brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
+		info->curregs[12] = (brg & 255);
+		info->curregs[13] = ((brg >> 8) & 255);
+		info->curregs[14] = BRSRC | BRENAB;
+	}
 
 	/* byte size and parity */
 	switch (cflag & CSIZE) {
 	case CS5:
-		info->curregs[3] &= ~(0xc0);
+		info->curregs[3] &= ~(RxN_MASK);
 		info->curregs[3] |= Rx5;
-		info->pendregs[3] = info->curregs[3];
-		info->curregs[5] &= ~(0xe0);
+		info->curregs[5] &= ~(TxN_MASK);
 		info->curregs[5] |= Tx5;
-		info->pendregs[5] = info->curregs[5];
+		info->parity_mask = 0x1f;
 		break;
 	case CS6:
-		info->curregs[3] &= ~(0xc0);
+		info->curregs[3] &= ~(RxN_MASK);
 		info->curregs[3] |= Rx6;
-		info->pendregs[3] = info->curregs[3];
-		info->curregs[5] &= ~(0xe0);
+		info->curregs[5] &= ~(TxN_MASK);
 		info->curregs[5] |= Tx6;
-		info->pendregs[5] = info->curregs[5];
+		info->parity_mask = 0x3f;
 		break;
 	case CS7:
-		info->curregs[3] &= ~(0xc0);
+		info->curregs[3] &= ~(RxN_MASK);
 		info->curregs[3] |= Rx7;
-		info->pendregs[3] = info->curregs[3];
-		info->curregs[5] &= ~(0xe0);
+		info->curregs[5] &= ~(TxN_MASK);
 		info->curregs[5] |= Tx7;
-		info->pendregs[5] = info->curregs[5];
+		info->parity_mask = 0x7f;
 		break;
 	case CS8:
 	default: /* defaults to 8 bits */
-		info->curregs[3] &= ~(0xc0);
+		info->curregs[3] &= ~(RxN_MASK);
 		info->curregs[3] |= Rx8;
-		info->pendregs[3] = info->curregs[3];
-		info->curregs[5] &= ~(0xe0);
+		info->curregs[5] &= ~(TxN_MASK);
 		info->curregs[5] |= Tx8;
-		info->pendregs[5] = info->curregs[5];
+		info->parity_mask = 0xff;
 		break;
 	}
 	info->curregs[4] &= ~(0x0c);
@@ -876,24 +873,19 @@
 	} else {
 		info->curregs[4] |= SB1;
 	}
-	info->pendregs[4] = info->curregs[4];
 	if (cflag & PARENB) {
-		info->curregs[4] |= PAR_ENA;
-		info->pendregs[4] |= PAR_ENA;
+		info->curregs[4] |= PAR_ENAB;
 	} else {
-		info->curregs[4] &= ~PAR_ENA;
-		info->pendregs[4] &= ~PAR_ENA;
+		info->curregs[4] &= ~PAR_ENAB;
 	}
 	if (!(cflag & PARODD)) {
 		info->curregs[4] |= PAR_EVEN;
-		info->pendregs[4] |= PAR_EVEN;
 	} else {
 		info->curregs[4] &= ~PAR_EVEN;
-		info->pendregs[4] &= ~PAR_EVEN;
 	}
 
 	/* Load up the new values */
-	load_zsregs(info->zs_channel, info->curregs);
+	load_zsregs(info, info->curregs);
 
 	return;
 }
@@ -904,38 +896,26 @@
 void kbd_put_char(unsigned char ch)
 {
 	struct sun_zschannel *chan = zs_kbdchan;
-	int flags, loops = 0;
+	int flags;
 
 	if(!chan)
 		return;
 
 	save_flags(flags); cli();
-	while((chan->control & Tx_BUF_EMP)==0 && loops < 10000) {
-		loops++;
-		udelay(5);
-	}
-
-	chan->data = ch;
-	udelay(5);
+	zs_put_char(chan, ch);
 	restore_flags(flags);
 }
 
 void mouse_put_char(char ch)
 {
 	struct sun_zschannel *chan = zs_mousechan;
-	int flags, loops = 0;
+	int flags;
 
 	if(!chan)
 		return;
 
 	save_flags(flags); cli();
-	while((chan->control & Tx_BUF_EMP)==0 && loops < 10000) {
-		loops++;
-		udelay(5);
-	}
-
-	chan->data = ch;
-	udelay(5);
+	zs_put_char(chan, ch);
 	restore_flags(flags);
 }
 
@@ -944,19 +924,13 @@
 static void rs_put_char(char ch)
 {
 	struct sun_zschannel *chan = zs_conschan;
-	int flags, loops = 0;
+	int flags;
 
 	if(!chan)
 		return;
 
 	save_flags(flags); cli();
-	while((chan->control & Tx_BUF_EMP)==0 && loops < 10000) {
-		loops++;
-		udelay(5);
-	}
-
-	chan->data = ch;
-	udelay(5);
+	zs_put_char(chan, ch);
 	restore_flags(flags);
 }
 
@@ -969,7 +943,6 @@
 
 	while((chan->control & Tx_BUF_EMP)==0)
 		udelay(5);
-
 	chan->data = kgdb_char;
 }
 
@@ -1051,10 +1024,8 @@
 	/* Enable transmitter */
 	save_flags(flags); cli();
 	info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
-	info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
 	write_zsreg(info->zs_channel, 1, info->curregs[1]);
 	info->curregs[5] |= TxENAB;
-	info->pendregs[5] |= TxENAB;
 	write_zsreg(info->zs_channel, 5, info->curregs[5]);
 
 	/*
@@ -1064,13 +1035,10 @@
 	 * but resets interrupts also what we do not desire here.
 	 * XXX Discuss with David.
 	 */
-	if (info->zs_channel->control & Tx_BUF_EMP) {
-		/* Send char */
-		info->zs_channel->data = info->xmit_buf[info->xmit_tail++];
-		udelay(5);
-		info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
-		info->xmit_cnt--;
-	}
+	zs_put_char(info->zs_channel, info->xmit_buf[info->xmit_tail++]);
+	info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+	info->xmit_cnt--;
+
 	restore_flags(flags);
 }
 
@@ -1084,7 +1052,7 @@
 	if (serial_paranoia_check(info, tty->device, "rs_write"))
 		return 0;
 
-	if (!tty || !info->xmit_buf)
+	if (!info || !info->xmit_buf)
 		return 0;
 
 	save_flags(flags);
@@ -1097,7 +1065,7 @@
 
 		if (from_user) {
 			down(&tmp_buf_sem);
-			memcpy_fromfs(tmp_buf, buf, c);
+			copy_from_user(tmp_buf, buf, c);
 			c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
 				       SERIAL_XMIT_SIZE - info->xmit_head));
 			memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
@@ -1111,16 +1079,22 @@
 		count -= c;
 		total += c;
 	}
-	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
-	    !(info->curregs[5] & TxENAB)) {
+
+	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
 		/* Enable transmitter */
 		info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
-		info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB;
 		write_zsreg(info->zs_channel, 1, info->curregs[1]);
 		info->curregs[5] |= TxENAB;
-		info->pendregs[5] |= TxENAB;
 		write_zsreg(info->zs_channel, 5, info->curregs[5]);
 	}
+#if 1
+	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
+		zs_put_char(info->zs_channel,
+			    info->xmit_buf[info->xmit_tail++]);
+		info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+		info->xmit_cnt--;
+	}
+#endif
 	restore_flags(flags);
 	return total;
 }
@@ -1189,7 +1163,6 @@
 	/* Turn off RTS line */
 	cli();
 	info->curregs[5] &= ~RTS;
-	info->pendregs[5] &= ~RTS;
 	write_zsreg(info->zs_channel, 5, info->curregs[5]);
 	sti();
 }
@@ -1217,7 +1190,6 @@
 	/* Assert RTS line */
 	cli();
 	info->curregs[5] |= RTS;
-	info->pendregs[5] |= RTS;
 	write_zsreg(info->zs_channel, 5, info->curregs[5]);
 	sti();
 }
@@ -1245,7 +1217,7 @@
 	tmp.close_delay = info->close_delay;
 	tmp.closing_wait = info->closing_wait;
 	tmp.custom_divisor = info->custom_divisor;
-	memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
+	copy_to_user_ret(retinfo,&tmp,sizeof(*retinfo), -EFAULT);
 	return 0;
 }
 
@@ -1256,9 +1228,8 @@
 	struct sun_serial old_info;
 	int 			retval = 0;
 
-	if (!new_info)
+	if (!new_info || copy_from_user(&new_serial,new_info,sizeof(new_serial)))
 		return -EFAULT;
-	memcpy_fromfs(&new_serial,new_info,sizeof(new_serial));
 	old_info = *info;
 
 	if (!suser()) {
@@ -1311,7 +1282,7 @@
 	cli();
 	status = info->zs_channel->control;
 	sti();
-	put_user(status,value);
+	put_user_ret(status,value, -EFAULT);
 	return 0;
 }
 
@@ -1334,7 +1305,6 @@
 static int rs_ioctl(struct tty_struct *tty, struct file * file,
 		    unsigned int cmd, unsigned long arg)
 {
-	int error;
 	struct sun_serial * info = (struct sun_serial *)tty->driver_data;
 	int retval;
 
@@ -1365,44 +1335,26 @@
 			send_break(info, arg ? arg*(HZ/10) : HZ/4);
 			return 0;
 		case TIOCGSOFTCAR:
-			return put_user(C_CLOCAL(tty) ? 1 : 0,
-			    (unsigned int *) arg);
+			put_user_ret(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg, -EFAULT);
+			return 0;
 		case TIOCSSOFTCAR:
-			{
-			    unsigned int value;
-			    retval = get_user(value, (unsigned int *) arg);
-			    if (retval)
-				return retval;
-			    tty->termios->c_cflag =
-				    ((tty->termios->c_cflag & ~CLOCAL) |
-				     (value ? CLOCAL : 0));
-			}
+			get_user_ret(arg, (unsigned long *) arg, -EFAULT);
+			tty->termios->c_cflag =
+				((tty->termios->c_cflag & ~CLOCAL) |
+				 (arg ? CLOCAL : 0));
 			return 0;
 		case TIOCGSERIAL:
-			error = verify_area(VERIFY_WRITE, (void *) arg,
-						sizeof(struct serial_struct));
-			if (error)
-				return error;
 			return get_serial_info(info,
 					       (struct serial_struct *) arg);
 		case TIOCSSERIAL:
 			return set_serial_info(info,
 					       (struct serial_struct *) arg);
 		case TIOCSERGETLSR: /* Get line status register */
-			error = verify_area(VERIFY_WRITE, (void *) arg,
-				sizeof(unsigned int));
-			if (error)
-				return error;
-			else
-			    return get_lsr_info(info, (unsigned int *) arg);
+			return get_lsr_info(info, (unsigned int *) arg);
 
 		case TIOCSERGSTRUCT:
-			error = verify_area(VERIFY_WRITE, (void *) arg,
-						sizeof(struct sun_serial));
-			if (error)
-				return error;
-			memcpy_tofs((struct sun_serial *) arg,
-				    info, sizeof(struct sun_serial));
+			copy_to_user_ret((struct sun_serial *) arg,
+				    info, sizeof(struct sun_serial), -EFAULT);
 			return 0;
 			
 		default:
@@ -1499,11 +1451,9 @@
 	 * line status register.
 	 */
 	/** if (!info->iscons) ... **/
-	info->curregs[3] &= ~RxENABLE;
-	info->pendregs[3] = info->curregs[3];
+	info->curregs[3] &= ~RxENAB;
 	write_zsreg(info->zs_channel, 3, info->curregs[3]);
-	info->curregs[1] &= ~(0x18);
-	info->pendregs[1] = info->curregs[1];
+	info->curregs[1] &= ~(RxINT_MASK);
 	write_zsreg(info->zs_channel, 1, info->curregs[1]);
 	ZS_CLEARFIFO(info->zs_channel);
 
@@ -1636,7 +1586,10 @@
 	printk("block_til_ready before block: ttys%d, count = %d\n",
 	       info->line, info->count);
 #endif
-	info->count--;
+	cli();
+	if(!tty_hung_up_p(filp))
+		info->count--;
+	sti();
 	info->blocked_open++;
 	while (1) {
 		cli();
@@ -1656,8 +1609,10 @@
 #endif
 			break;
 		}
+
 		if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
-		    !(info->flags & ZILOG_CLOSING) && do_clocal)
+		    !(info->flags & ZILOG_CLOSING) &&
+		    (do_clocal || (DCD & read_zsreg(info->zs_channel, R0))))
 			break;
 		if (current->signal & ~current->blocked) {
 			retval = -ERESTARTSYS;
@@ -1754,16 +1709,28 @@
 
 static void show_serial_version(void)
 {
-	printk("Sparc Zilog8530 serial driver version 1.00\n");
+	char *revision = "$Revision: 1.24 $";
+	char *version, *p;
+
+	version = strchr(revision, ' ');
+	p = strchr(++version, ' ');
+	*p = '\0';
+	printk("Sparc Zilog8530 serial driver version %s\n", version);
+	*p = ' ';
 }
 
-/* Probe the PROM for the request zs chip number. */
+/* Probe the PROM for the request zs chip number.
+ *
+ * Note: The Sun Voyager shows two addresses and two intr for it's
+ *       Zilogs, what the second does, I don't know. It does work
+ *       with using only the first number of each property.
+ */
 static inline struct sun_zslayout *get_zs(int chip)
 {
-	struct linux_prom_irqs tmp_irq;
+	struct linux_prom_irqs tmp_irq[2];
 	unsigned long paddr = 0;
-	unsigned long vaddr = 0;
-	int zsnode, tmpnode, iospace, slave;
+	unsigned long vaddr[2] = { 0, 0 };
+	int zsnode, tmpnode, iospace, slave, len;
 	static int irq = 0;
 
 #if CONFIG_AP1000
@@ -1789,15 +1756,34 @@
 		zs_nodes[chip] = 0;
 		if(!irq)
 			zilog_irq = irq = 12;
-		vaddr = (unsigned long)
-			sparc_alloc_io((char *) paddr, 0, 8,
-				       "Zilog Serial", iospace, 0);
+		vaddr[0] = (unsigned long)
+				sparc_alloc_io((char *) paddr, 0, 8,
+					       "Zilog Serial", iospace, 0);
 	} else {
 		/* Can use the prom for other machine types */
 		zsnode = prom_getchild(prom_root_node);
-		tmpnode = prom_searchsiblings(zsnode, "obio");
-		if(tmpnode)
-			zsnode = prom_getchild(tmpnode);
+		if (sparc_cpu_model == sun4d) {
+			int board, node;
+			
+			tmpnode = zsnode;
+			while (tmpnode && (tmpnode = prom_searchsiblings(tmpnode, "cpu-unit"))) {
+				board = prom_getintdefault (tmpnode, "board#", -1);
+				if (board == (chip >> 1)) {
+					node = prom_getchild(tmpnode);
+					if (node && (node = prom_searchsiblings(node, "bootbus"))) {
+						zsnode = node;
+						break;
+					}
+				}
+				tmpnode = prom_getsibling(tmpnode);
+			}
+			if (!tmpnode)
+				panic ("get_zs: couldn't find board%d's bootbus\n", chip >> 1);
+		} else {
+			tmpnode = prom_searchsiblings(zsnode, "obio");
+			if(tmpnode)
+				zsnode = prom_getchild(tmpnode);
+		}
 		if(!zsnode)
 			panic("get_zs no zs serial prom node");
 		while(zsnode) {
@@ -1805,22 +1791,34 @@
 			slave = prom_getintdefault(zsnode, "slave", -1);
 			if(slave==chip) {
 				/* The one we want */
-				vaddr = (unsigned long)
-					prom_getintdefault(zsnode, "address",
-							       0xdeadbeef);
-				if(vaddr == 0xdeadbeef)
-					prom_halt();
+				len = prom_getproperty(zsnode, "address",
+						       (void *) vaddr,
+						       sizeof(vaddr));
+        			if (len % sizeof(unsigned long)) {
+					prom_printf("WHOOPS:  proplen for %s "
+						"was %d, need multiple of "
+						"%d\n", "address", len,
+						sizeof(unsigned long));
+					panic("zilog: address property");
+				}
 				zs_nodes[chip] = zsnode;
-				prom_getproperty(zsnode, "intr",
-						 (char *) &tmp_irq,
-						 sizeof(tmp_irq));
+				len = prom_getproperty(zsnode, "intr",
+						       (char *) tmp_irq,
+						       sizeof(tmp_irq));
+        			if (len % sizeof(struct linux_prom_irqs)) {
+					prom_printf("WHOOPS:  proplen for %s "
+						"was %d, need multiple of "
+						"%d\n", "address", len,
+						sizeof(struct linux_prom_irqs));
+					panic("zilog: address property");
+				}
 #ifdef OLD_STYLE_IRQ
-				tmp_irq.pri &= 0xf;
+				tmp_irq[0].pri &= 0xf;
 #endif
 				if(!irq) {
-					irq = zilog_irq = tmp_irq.pri;
+					irq = zilog_irq = tmp_irq[0].pri;
 				} else {
-					if(tmp_irq.pri != irq)
+					if(tmp_irq[0].pri != irq)
 						panic("zilog: bogon irqs");
 				}
 				break;
@@ -1830,13 +1828,181 @@
 		if(!zsnode)
 			panic("get_zs whee chip not found");
 	}
-	if(!vaddr)
+	if(!vaddr[0])
 		panic("get_zs whee no serial chip mappable");
 
-	return (struct sun_zslayout *) vaddr;
-
+	return (struct sun_zslayout *) vaddr[0];
 }
 
+static inline void
+init_zscons_termios(struct termios *termios)
+{
+	char mode[16], buf[16];
+	char *mode_prop = "ttyX-mode";
+	char *cd_prop = "ttyX-ignore-cd";
+	char *dtr_prop = "ttyX-rts-dtr-off";
+	char *s;
+	int baud, bits, cflag;
+	char parity;
+	int topnd, nd;
+	int channel, stop;
+	int carrier = 0;
+	int rtsdtr = 1;
+	extern int serial_console;
+
+	if (!serial_console)
+		return;
+
+	if (serial_console == 1) {
+		mode_prop[3] = 'a';
+		cd_prop[3] = 'a';
+		dtr_prop[3] = 'a';
+	} else {
+		mode_prop[3] = 'b';
+		cd_prop[3] = 'b';
+		dtr_prop[3] = 'b';
+	}
+
+	topnd = prom_getchild(prom_root_node);
+	nd = prom_searchsiblings(topnd, "options");
+	if (!nd) {
+		strcpy(mode, "9600,8,n,1,-");
+		goto no_options;
+	}
+
+	if (!prom_node_has_property(nd, mode_prop)) {
+		strcpy(mode, "9600,8,n,1,-");
+		goto no_options;
+	}
+
+	memset(mode, 0, sizeof(mode));
+	prom_getstring(nd, mode_prop, mode, sizeof(mode));
+
+	if (prom_node_has_property(nd, cd_prop)) {
+		memset(buf, 0, sizeof(buf));
+		prom_getstring(nd, cd_prop, buf, sizeof(buf));
+		if (!strcmp(buf, "false"))
+			carrier = 1;
+
+		/* XXX this is unused below. */
+	}
+
+	if (prom_node_has_property(nd, cd_prop)) {
+		memset(buf, 0, sizeof(buf));
+		prom_getstring(nd, cd_prop, buf, sizeof(buf));
+		if (!strcmp(buf, "false"))
+			rtsdtr = 0;
+
+		/* XXX this is unused below. */
+	}
+
+no_options:
+	cflag = CREAD | HUPCL | CLOCAL;
+
+	s = mode;
+	baud = simple_strtoul(s, 0, 0);
+	s = strchr(s, ',');
+	bits = simple_strtoul(++s, 0, 0);
+	s = strchr(s, ',');
+	parity = *(++s);
+	s = strchr(s, ',');
+	stop = simple_strtoul(++s, 0, 0);
+	s = strchr(s, ',');
+	/* XXX handshake is not handled here. */
+
+	for (channel = 0; channel < NUM_CHANNELS; channel++)
+		if (zs_soft[channel].is_cons)
+			break;
+
+	switch (baud) {
+		case 150:
+			cflag |= B150;
+			break;
+		case 300:
+			cflag |= B300;
+			break;
+		case 600:
+			cflag |= B600;
+			break;
+		case 1200:
+			cflag |= B1200;
+			break;
+		case 2400:
+			cflag |= B2400;
+			break;
+		case 4800:
+			cflag |= B4800;
+			break;
+		default:
+			baud = 9600;
+		case 9600:
+			cflag |= B9600;
+			break;
+		case 19200:
+			cflag |= B19200;
+			break;
+		case 38400:
+			cflag |= B38400;
+			break;
+	}
+	zs_soft[channel].zs_baud = baud;
+
+	switch (bits) {
+		case 5:
+			zscons_regs[3] = Rx5 | RxENAB;
+			zscons_regs[5] = Tx5 | TxENAB;
+			zs_soft[channel].parity_mask = 0x1f;
+			cflag |= CS5;
+			break;
+		case 6:
+			zscons_regs[3] = Rx6 | RxENAB;
+			zscons_regs[5] = Tx6 | TxENAB;
+			zs_soft[channel].parity_mask = 0x3f;
+			cflag |= CS6;
+			break;
+		case 7:
+			zscons_regs[3] = Rx7 | RxENAB;
+			zscons_regs[5] = Tx7 | TxENAB;
+			zs_soft[channel].parity_mask = 0x7f;
+			cflag |= CS7;
+			break;
+		default:
+		case 8:
+			zscons_regs[3] = Rx8 | RxENAB;
+			zscons_regs[5] = Tx8 | TxENAB;
+			zs_soft[channel].parity_mask = 0xff;
+			cflag |= CS8;
+			break;
+	}
+	zscons_regs[5] |= DTR;
+
+	switch (parity) {
+		case 'o':
+			zscons_regs[4] |= PAR_ENAB;
+			cflag |= (PARENB | PARODD);
+			break;
+		case 'e':
+			zscons_regs[4] |= (PAR_ENAB | PAR_EVEN);
+			cflag |= PARENB;
+			break;
+		default:
+		case 'n':
+			break;
+	}
+
+	switch (stop) {
+		default:
+		case 1:
+			zscons_regs[4] |= SB1;
+			break;
+		case 2:
+			cflag |= CSTOPB;
+			zscons_regs[4] |= SB2;
+			break;
+	}
+
+	termios->c_cflag = cflag;
+}
 
 extern void register_console(void (*proc)(const char *));
 
@@ -1861,6 +2027,9 @@
 		o = 1;
 		/* double whee.. */
 		if(!consout_registered) {
+			extern void serial_finish_init (void (*)(const char *));
+
+			serial_finish_init (zs_console_print);
 			register_console(zs_console_print);
 			consout_registered = 1;
 		}
@@ -1875,8 +2044,6 @@
 	}
 	if(o && i)
 		io = 1;
-	if(ss->zs_baud != 9600)
-		panic("Console baud rate weirdness");
 
 	/* Set flag variable for this port so that it cannot be
 	 * opened for other uses by accident.
@@ -1894,15 +2061,52 @@
 	}
 }
 
-volatile int test_done;
 extern void keyboard_zsinit(void);
 extern void sun_mouse_zsinit(void);
 
-/* rs_init inits the driver */
-int rs_init(void)
+__initfunc(unsigned long sun_serial_setup (unsigned long memory_start))
+{
+	char *p;
+	int i;
+	
+	if (sparc_cpu_model == sun4d) {
+		int node = prom_searchsiblings(prom_getchild(prom_root_node), "boards");
+		NUM_SERIAL = 0;
+		if (!node)
+			panic ("Cannot find out count of boards");
+		else
+			node = prom_getchild(node);
+		while (node && (node = prom_searchsiblings(node, "bif"))) {
+			NUM_SERIAL += 2;
+			node = prom_getsibling(node);
+		}
+	}
+	p = (char *)((memory_start + 7) & ~7);
+	zs_chips = (struct sun_zslayout **)(p);
+	i = NUM_SERIAL * sizeof (struct sun_zslayout *);
+	zs_channels = (struct sun_zschannel **)(p + i);
+	i += NUM_CHANNELS * sizeof (struct sun_zschannel *);
+	zs_nodes = (int *)(p + i);
+	i += NUM_SERIAL * sizeof (int);
+	zs_soft = (struct sun_serial *)(p + i);
+	i += NUM_CHANNELS * sizeof (struct sun_serial);
+	zs_ttys = (struct tty_struct *)(p + i);
+	i += NUM_CHANNELS * sizeof (struct tty_struct);
+	serial_table = (struct tty_struct **)(p + i);
+	i += NUM_CHANNELS * sizeof (struct tty_struct *);
+	serial_termios = (struct termios **)(p + i);
+	i += NUM_CHANNELS * sizeof (struct termios *);
+	serial_termios_locked = (struct termios **)(p + i);
+	i += NUM_CHANNELS * sizeof (struct termios *);
+	memset (p, 0, i);
+	return (((unsigned long)p) + i + 7) & ~7;
+}
+
+__initfunc(int rs_init(void))
 {
-	int chip, channel, i, flags;
+	int chip, channel, brg, i, flags;
 	struct sun_serial *info;
+	char dummy;
 
 #if CONFIG_AP1000
         printk("not doing rs_init()\n");
@@ -1952,6 +2156,8 @@
 	serial_driver.start = rs_start;
 	serial_driver.hangup = rs_hangup;
 
+	init_zscons_termios(&serial_driver.init_termios);
+
 	/*
 	 * The callout device is just like normal device except for
 	 * major number and the subtype code.
@@ -1970,11 +2176,11 @@
 
 	/* Set up our interrupt linked list */
 	zs_chain = &zs_soft[0];
-	zs_soft[0].zs_next = &zs_soft[1];
-	zs_soft[1].zs_next = &zs_soft[2];
-	zs_soft[2].zs_next = &zs_soft[3];
-	zs_soft[3].zs_next = 0;
+	for(channel = 0; channel < NUM_CHANNELS - 1; channel++)
+		zs_soft[channel].zs_next = &zs_soft[channel + 1];
+	zs_soft[channel + 1].zs_next = 0;
 
+	/* Initialize Softinfo */
 	for(chip = 0; chip < NUM_SERIAL; chip++) {
 		/* If we are doing kgdb over one of the channels on
 		 * chip zero, kgdb_channel will be set to 1 by the
@@ -1988,103 +2194,173 @@
 			zs_soft[(chip*2)].kgdb_channel = 0;
 			zs_soft[(chip*2)+1].kgdb_channel = 0;
 		}
+
 		/* First, set up channel A on this chip. */
 		channel = chip * 2;
 		zs_soft[channel].zs_channel = zs_channels[channel];
 		zs_soft[channel].change_needed = 0;
 		zs_soft[channel].clk_divisor = 16;
-		zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+		zs_soft[channel].cons_keyb = 0;
 		zs_soft[channel].cons_mouse = 0;
-		/* If not keyboard/mouse and is console serial
-		 * line, then enable receiver interrupts.
-		 */
-		if((channel<KEYBOARD_LINE) && (zs_soft[channel].is_cons)) {
-			write_zsreg(zs_soft[channel].zs_channel, R1,
-				    (EXT_INT_ENAB | INT_ALL_Rx));
-			write_zsreg(zs_soft[channel].zs_channel, R9, (NV | MIE));
-			write_zsreg(zs_soft[channel].zs_channel, R10, (NRZ));
-			write_zsreg(zs_soft[channel].zs_channel, R3, (Rx8|RxENABLE));
-			write_zsreg(zs_soft[channel].zs_channel, R5, (Tx8 | TxENAB));
+		zs_soft[channel].channelA = 1;
+
+		/* Now, channel B */
+		channel++;
+		zs_soft[channel].zs_channel = zs_channels[channel];
+		zs_soft[channel].change_needed = 0;
+		zs_soft[channel].clk_divisor = 16;
+		zs_soft[channel].cons_keyb = 0;
+		zs_soft[channel].cons_mouse = 0;
+		zs_soft[channel].channelA = 0;
+	}
+
+	/* Initialize Hardware */
+	for(channel = 0; channel < NUM_CHANNELS; channel++) {
+
+		/* Hardware reset each chip */
+		if (!(channel & 1)) {
+			write_zsreg(zs_soft[channel].zs_channel, R9, FHWRES);
+			udelay(20);	/* wait for some old sun4's */
+			dummy = read_zsreg(zs_soft[channel].zs_channel, R0);
 		}
-		/* If this is the kgdb line, enable interrupts because we
-		 * now want to receive the 'control-c' character from the
-		 * client attached to us asynchronously.
-		 */
-		if(zs_soft[channel].kgdb_channel)
-			kgdb_chaninit(&zs_soft[channel], 1, zs_soft[channel].zs_baud);
 
 		if(channel == KEYBOARD_LINE) {
-			/* Tell keyboard driver about our presence. */
-			if(zs_soft[channel].zs_baud != 1200)
-				panic("Weird keyboard serial baud rate");
 			zs_soft[channel].cons_keyb = 1;
+			zs_soft[channel].parity_mask = 0xff;
 			zs_kbdchan = zs_soft[channel].zs_channel;
-			/* Enable Rx/Tx, IRQs, and inform kbd driver */
-			write_zsreg(zs_soft[channel].zs_channel, R1,
-				    (EXT_INT_ENAB | INT_ALL_Rx));
+
 			write_zsreg(zs_soft[channel].zs_channel, R4,
 				    (PAR_EVEN | X16CLK | SB1));
-			write_zsreg(zs_soft[channel].zs_channel, R9, (NV|MIE));
-			write_zsreg(zs_soft[channel].zs_channel, R10, (NRZ));
+			write_zsreg(zs_soft[channel].zs_channel, R3, Rx8);
+			write_zsreg(zs_soft[channel].zs_channel, R5, Tx8);
+			write_zsreg(zs_soft[channel].zs_channel, R9, NV);
+			write_zsreg(zs_soft[channel].zs_channel, R10, NRZ);
 			write_zsreg(zs_soft[channel].zs_channel, R11,
 				    (TCBR | RCBR));
+			zs_soft[channel].zs_baud = 1200;
+			brg = BPS_TO_BRG(zs_soft[channel].zs_baud,
+					 ZS_CLOCK/zs_soft[channel].clk_divisor);
+			write_zsreg(zs_soft[channel].zs_channel, R12,
+				    (brg & 0xff));
+			write_zsreg(zs_soft[channel].zs_channel, R13,
+				    ((brg >> 8) & 0xff));
+			write_zsreg(zs_soft[channel].zs_channel, R14, BRSRC);
+
+			/* Enable Rx/Tx, IRQs, and inform kbd driver */
 			write_zsreg(zs_soft[channel].zs_channel, R14,
-				    (BRSRC | BRENABL));
-			write_zsreg(zs_soft[channel].zs_channel, R3, (Rx8|RxENABLE));
+				    (BRSRC | BRENAB));
+			write_zsreg(zs_soft[channel].zs_channel, R3,
+				    (Rx8 | RxENAB));
 			write_zsreg(zs_soft[channel].zs_channel, R5,
 				    (Tx8 | TxENAB | DTR | RTS));
-#if 0
+
 			write_zsreg(zs_soft[channel].zs_channel, R15,
 				    (DCDIE | CTSIE | TxUIE | BRKIE));
-#endif
-			ZS_CLEARERR(zs_soft[channel].zs_channel);
-			ZS_CLEARFIFO(zs_soft[channel].zs_channel);
-		}
+			write_zsreg(zs_soft[channel].zs_channel, R0,
+				    RES_EXT_INT);
+			write_zsreg(zs_soft[channel].zs_channel, R0,
+				    RES_EXT_INT);
 
-		/* Now, channel B */
-		channel++;
-		zs_soft[channel].zs_channel = zs_channels[channel];
-		zs_soft[channel].change_needed = 0;
-		zs_soft[channel].clk_divisor = 16;
-		zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
-		zs_soft[channel].cons_keyb = 0;
-		/* If not keyboard/mouse and is console serial
-		 * line, then enable receiver interrupts.
-		 */
-		if(channel<KEYBOARD_LINE && zs_soft[channel].is_cons) {
 			write_zsreg(zs_soft[channel].zs_channel, R1,
 				    (EXT_INT_ENAB | INT_ALL_Rx));
 			write_zsreg(zs_soft[channel].zs_channel, R9,
 				    (NV | MIE));
-			write_zsreg(zs_soft[channel].zs_channel, R10,
-				    (NRZ));
-			write_zsreg(zs_soft[channel].zs_channel, R3,
-				    (Rx8|RxENABLE));
-			write_zsreg(zs_soft[channel].zs_channel, R5,
-				    (Tx8 | TxENAB | RTS | DTR));
-		}
-		if(channel == MOUSE_LINE) {
-			/* Tell mouse driver about our presence. */
-			if(zs_soft[channel].zs_baud != 1200)
-				panic("Weird mouse serial baud rate");
+			ZS_CLEARERR(zs_soft[channel].zs_channel);
+			ZS_CLEARFIFO(zs_soft[channel].zs_channel);
+		} else if(channel == MOUSE_LINE) {
 			zs_soft[channel].cons_mouse = 1;
+			zs_soft[channel].parity_mask = 0xff;
 			zs_mousechan = zs_soft[channel].zs_channel;
+
+			write_zsreg(zs_soft[channel].zs_channel, R4,
+				    (PAR_EVEN | X16CLK | SB1));
+			write_zsreg(zs_soft[channel].zs_channel, R3, Rx8);
+			write_zsreg(zs_soft[channel].zs_channel, R5, Tx8);
+			write_zsreg(zs_soft[channel].zs_channel, R9, NV);
+			write_zsreg(zs_soft[channel].zs_channel, R10, NRZ);
+			write_zsreg(zs_soft[channel].zs_channel, R11,
+				    (TCBR | RCBR));
+
+			zs_soft[channel].zs_baud = 1200;
+			brg = BPS_TO_BRG(zs_soft[channel].zs_baud,
+					 ZS_CLOCK/zs_soft[channel].clk_divisor);
+			write_zsreg(zs_soft[channel].zs_channel, R12,
+				    (brg & 0xff));
+			write_zsreg(zs_soft[channel].zs_channel, R13,
+				    ((brg >> 8) & 0xff));
+			write_zsreg(zs_soft[channel].zs_channel, R14, BRSRC);
+
 			/* Enable Rx, IRQs, and inform mouse driver */
-			write_zsreg(zs_soft[channel].zs_channel, R1, (INT_ALL_Rx));
-			write_zsreg(zs_soft[channel].zs_channel, R9, (NV|MIE));
-			write_zsreg(zs_soft[channel].zs_channel, R3, (Rx8|RxENABLE));
-#if 0 /* XXX hangs sun4c's sometimes */
+			write_zsreg(zs_soft[channel].zs_channel, R14,
+				    (BRSRC | BRENAB));
+			write_zsreg(zs_soft[channel].zs_channel, R3,
+				    (Rx8 | RxENAB));
+			write_zsreg(zs_soft[channel].zs_channel, R5, Tx8);
+
 			write_zsreg(zs_soft[channel].zs_channel, R15,
 				    (DCDIE | CTSIE | TxUIE | BRKIE));
-#endif
+			write_zsreg(zs_soft[channel].zs_channel, R0,
+				    RES_EXT_INT);
+			write_zsreg(zs_soft[channel].zs_channel, R0,
+				    RES_EXT_INT);
+
+			write_zsreg(zs_soft[channel].zs_channel, R1,
+				    (EXT_INT_ENAB | INT_ALL_Rx));
+			write_zsreg(zs_soft[channel].zs_channel, R9,
+				    (NV | MIE));
+
 			sun_mouse_zsinit();
+		} else if (zs_soft[channel].is_cons) {
+			brg = BPS_TO_BRG(zs_soft[channel].zs_baud,
+					 ZS_CLOCK/zs_soft[channel].clk_divisor);
+			zscons_regs[12] = brg & 0xff;
+			zscons_regs[13] = (brg >> 8) & 0xff;
+
+			memcpy(zs_soft[channel].curregs, zscons_regs, sizeof(zscons_regs));
+			load_zsregs(&zs_soft[channel], zscons_regs);
+
+			ZS_CLEARERR(zs_soft[channel].zs_channel);
+			ZS_CLEARFIFO(zs_soft[channel].zs_channel);
+		} else if (zs_soft[channel].kgdb_channel) {
+			/* If this is the kgdb line, enable interrupts because
+			 * we now want to receive the 'control-c' character
+			 * from the client attached to us asynchronously.
+			 */
+			zs_soft[channel].parity_mask = 0xff;
+        		kgdb_chaninit(&zs_soft[channel], 1,
+				      zs_soft[channel].zs_baud);
 		} else {
-			zs_soft[channel].cons_mouse = 0;
+			zs_soft[channel].parity_mask = 0xff;
+			write_zsreg(zs_soft[channel].zs_channel, R4,
+				    (PAR_EVEN | X16CLK | SB1));
+			write_zsreg(zs_soft[channel].zs_channel, R3, Rx8);
+			write_zsreg(zs_soft[channel].zs_channel, R5, Tx8);
+			write_zsreg(zs_soft[channel].zs_channel, R9, NV);
+			write_zsreg(zs_soft[channel].zs_channel, R10, NRZ);
+			write_zsreg(zs_soft[channel].zs_channel, R11,
+				    (RCBR | TCBR));
+			zs_soft[channel].zs_baud = 9600;
+			brg = BPS_TO_BRG(zs_soft[channel].zs_baud,
+					 ZS_CLOCK/zs_soft[channel].clk_divisor);
+			write_zsreg(zs_soft[channel].zs_channel, R12,
+				    (brg & 0xff));
+			write_zsreg(zs_soft[channel].zs_channel, R13,
+				    ((brg >> 8) & 0xff));
+			write_zsreg(zs_soft[channel].zs_channel, R14, BRSRC);
+			write_zsreg(zs_soft[channel].zs_channel, R14,
+				    (BRSRC | BRENAB));
+			write_zsreg(zs_soft[channel].zs_channel, R3, Rx8);
+			write_zsreg(zs_soft[channel].zs_channel, R5, Tx8);
+			write_zsreg(zs_soft[channel].zs_channel, R15, DCDIE);
+			write_zsreg(zs_soft[channel].zs_channel, R9, NV | MIE);
+			write_zsreg(zs_soft[channel].zs_channel, R0,
+				    RES_EXT_INT);
+			write_zsreg(zs_soft[channel].zs_channel, R0,
+				    RES_EXT_INT);
 		}
 	}
 
-	for(info=zs_chain, i=0; info; info = info->zs_next, i++)
-	{
+	for (info = zs_chain, i=0; info; info = info->zs_next, i++) {
 		info->magic = SERIAL_MAGIC;
 		info->port = (int) info->zs_channel;
 		info->line = i;
@@ -2101,7 +2377,7 @@
 		info->tqueue.data = info;
 		info->tqueue_hangup.routine = do_serial_hangup;
 		info->tqueue_hangup.data = info;
-		info->callout_termios =callout_driver.init_termios;
+		info->callout_termios = callout_driver.init_termios;
 		info->normal_termios = serial_driver.init_termios;
 		info->open_wait = 0;
 		info->close_wait = 0;
@@ -2110,15 +2386,13 @@
 		printk(" is a Zilog8530\n");
 	}
 
-	if (request_irq(zilog_irq,
-			rs_interrupt,
+	if (request_irq(zilog_irq, rs_interrupt,
 			(SA_INTERRUPT | SA_STATIC_ALLOC),
-			"Zilog8530", NULL))
+			"Zilog8530", zs_chain))
 		panic("Unable to attach zs intr\n");
 	restore_flags(flags);
 
 	keyboard_zsinit();
-
 	return 0;
 }
 
@@ -2144,10 +2418,15 @@
  * are addressed backwards, channel B is first, then channel A.
  */
 void
-rs_cons_hook(int chip, int out, int channel)
+rs_cons_hook(int chip, int out, int line)
 {
+	int channel;
+
 	if(chip)
 		panic("rs_cons_hook called with chip not zero");
+	if(line != 1 && line != 2)
+		panic("rs_cons_hook called with line not ttya or ttyb");
+	channel = line - 1;
 	if(!zs_chips[chip]) {
 		zs_chips[chip] = get_zs(chip);
 		/* Two channels per chip */
@@ -2157,13 +2436,11 @@
 	zs_soft[channel].zs_channel = zs_channels[channel];
 	zs_soft[channel].change_needed = 0;
 	zs_soft[channel].clk_divisor = 16;
-	zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
-	rs_cons_check(&zs_soft[channel], channel);
 	if(out)
 		zs_cons_chanout = ((chip * 2) + channel);
 	else
 		zs_cons_chanin = ((chip * 2) + channel);
-
+	rs_cons_check(&zs_soft[channel], channel);
 }
 
 /* This is called at boot time to prime the kgdb serial debugging
@@ -2186,12 +2463,11 @@
 	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 = get_zsbaud(&zs_soft[tty_num]);
+	zs_soft[tty_num].zs_baud = 9600;
 	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], 0, 9600);
-	ZS_CLEARERR(zs_kgdbchan);
-	udelay(5);
-	ZS_CLEARFIFO(zs_kgdbchan);
+        kgdb_chaninit(&zs_soft[tty_num], 0, 9600);
+        ZS_CLEARERR(zs_kgdbchan);
+        ZS_CLEARFIFO(zs_kgdbchan);
 }
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/sunserial.h linux/drivers/sbus/char/sunserial.h
--- v2.1.15/linux/drivers/sbus/char/sunserial.h	Thu Apr 25 13:27:43 1996
+++ linux/drivers/sbus/char/sunserial.h	Fri Dec 13 11:37:37 1996
@@ -1,6 +1,8 @@
-/* serial.h: Definitions for the Sparc Zilog serial driver.
+/* $Id: sunserial.h,v 1.5 1996/10/16 13:13:41 zaitcev Exp $
+ * serial.h: Definitions for the Sparc Zilog serial driver.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Eddie C. Dost   (ecd@skynet.be)
  */
 #ifndef _SPARC_SERIAL_H
 #define _SPARC_SERIAL_H
@@ -114,6 +116,9 @@
 	char kgdb_channel;  /* Kgdb is running on this channel */
 	char is_cons;       /* Is this our console. */
 
+	char channelA;      /* This is channel A. */
+	char parity_mask;   /* Mask out parity bits in data register. */
+
 	/* We need to know the current clock divisor
 	 * to read the bps rate the chip has currently
 	 * loaded.
@@ -124,9 +129,6 @@
 	/* Current write register values */
 	unsigned char curregs[NUM_ZSREGS];
 
-	/* Values we need to set next opportunity */
-	unsigned char pendregs[NUM_ZSREGS];
-
 	char change_needed;
 
 	int			magic;
@@ -231,6 +233,7 @@
 #define	RxINT_FCERR	0x8	/* Rx Int on First Character Only or Error */
 #define	INT_ALL_Rx	0x10	/* Int on all Rx Characters or error */
 #define	INT_ERR_Rx	0x18	/* Int on error only */
+#define RxINT_MASK	0x18
 
 #define	WT_RDY_RT	0x20	/* Wait/Ready on R/T */
 #define	WT_FN_RDYFN	0x40	/* Wait/FN/Ready FN */
@@ -240,7 +243,7 @@
 
 /* Write Register 3 */
 
-#define	RxENABLE	0x1	/* Rx Enable */
+#define	RxENAB  	0x1	/* Rx Enable */
 #define	SYNC_L_INH	0x2	/* Sync Character Load Inhibit */
 #define	ADD_SM		0x4	/* Address Search Mode (SDLC) */
 #define	RxCRC_ENAB	0x8	/* Rx CRC Enable */
@@ -250,10 +253,11 @@
 #define	Rx7		0x40	/* Rx 7 Bits/Character */
 #define	Rx6		0x80	/* Rx 6 Bits/Character */
 #define	Rx8		0xc0	/* Rx 8 Bits/Character */
+#define RxN_MASK	0xc0
 
 /* Write Register 4 */
 
-#define	PAR_ENA		0x1	/* Parity Enable */
+#define	PAR_ENAB	0x1	/* Parity Enable */
 #define	PAR_EVEN	0x2	/* Parity Even/Odd* */
 
 #define	SYNC_ENAB	0	/* Sync Modes Enable */
@@ -282,6 +286,7 @@
 #define	Tx7		0x20	/* Tx 7 bits/character */
 #define	Tx6		0x40	/* Tx 6 bits/character */
 #define	Tx8		0x60	/* Tx 8 bits/character */
+#define TxN_MASK	0x60
 #define	DTR		0x80	/* DTR */
 
 /* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
@@ -334,7 +339,7 @@
 /* Write Register 13 (upper byte of baud rate generator time constant) */
 
 /* Write Register 14 (Misc control bits) */
-#define	BRENABL	1	/* Baud rate generator enable */
+#define	BRENAB 	1	/* Baud rate generator enable */
 #define	BRSRC	2	/* Baud rate generator source */
 #define	DTRREQ	4	/* DTR/Request function */
 #define	AUTOECHO 8	/* Auto Echo */
@@ -408,7 +413,9 @@
 /* Read Register 15 (value of WR 15) */
 
 /* Misc macros */
-#define ZS_CLEARERR(channel)    (channel->control = ERR_RES)
+#define ZS_CLEARERR(channel)    do { channel->control = ERR_RES; \
+				     udelay(5); } while(0)
+
 #define ZS_CLEARFIFO(channel)   do { volatile unsigned char garbage; \
 				     garbage = channel->data; \
 				     udelay(2); \
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/tcx.c linux/drivers/sbus/char/tcx.c
--- v2.1.15/linux/drivers/sbus/char/tcx.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/tcx.c	Fri Dec 13 11:37:37 1996
@@ -0,0 +1,365 @@
+/* $Id: tcx.c,v 1.8 1996/11/21 16:57:57 jj Exp $
+ * tcx.c: SUNW,tcx 24/8bit frame buffer driver
+ *
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ */
+
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/fbio.h>
+#include <asm/pgtable.h>
+
+#include "../../char/vt_kern.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+#include "fb.h"
+#include "cg_common.h"
+
+/* Offset of interesting structures in the tcx registers */
+#define TCX_RAM8BIT_OFFSET	0
+#define TCX_CONTROLPLANE_OFFSET 4
+#define TCX_BROOKTREE_OFFSET 	8
+#define TCX_THC_OFFSET		9
+#define TCX_TEC_OFFSET		7
+
+/* THC definitions */
+#define TCX_THC_MISC_REV_SHIFT       16
+#define TCX_THC_MISC_REV_MASK        15
+#define TCX_THC_MISC_RESET           (1 << 12)
+#define TCX_THC_MISC_VIDEO           (1 << 10)
+#define TCX_THC_MISC_SYNC            (1 << 9)
+#define TCX_THC_MISC_VSYNC           (1 << 8)
+#define TCX_THC_MISC_SYNC_ENAB       (1 << 7)
+#define TCX_THC_MISC_CURS_RES        (1 << 6)
+#define TCX_THC_MISC_INT_ENAB        (1 << 5)
+#define TCX_THC_MISC_INT             (1 << 4)
+#define TCX_THC_MISC_INIT            0x9f
+#define TCX_THC_REV_REV_SHIFT        20
+#define TCX_THC_REV_REV_MASK         15
+#define TCX_THC_REV_MINREV_SHIFT     28
+#define TCX_THC_REV_MINREV_MASK      15
+
+/* The contents are unknown */
+struct tcx_tec {
+	volatile int tec_matrix;
+	volatile int tec_clip;
+	volatile int tec_vdc;
+};
+
+struct tcx_thc {
+	volatile uint thc_rev;
+        uint thc_pad0[511];
+	volatile uint thc_hs;		/* hsync timing */
+	volatile uint thc_hsdvs;
+	volatile uint thc_hd;
+	volatile uint thc_vs;		/* vsync timing */
+	volatile uint thc_vd;
+	volatile uint thc_refresh;
+	volatile uint thc_misc;
+	uint thc_pad1[56];
+	volatile uint thc_cursxy;	/* cursor x,y position (16 bits each) */
+	volatile uint thc_cursmask[32];	/* cursor mask bits */
+	volatile uint thc_cursbits[32];	/* what to show where mask enabled */
+};
+
+static void
+tcx_restore_palette (fbinfo_t *fbinfo)
+{
+	volatile struct bt_regs *bt;
+
+	bt = fbinfo->info.tcx.bt;
+	bt->addr = 0;
+	bt->color_map = 0xffffffff;
+	bt->color_map = 0xffffffff;
+	bt->color_map = 0xffffffff;
+}
+
+static void
+tcx_set_control_plane (fbinfo_t *fb)
+{
+	register uint *p, *pend;
+	
+	p = fb->info.tcx.tcx_cplane;
+	if (!p) return;
+	for (pend = p + (fb->info.tcx.tcx_sizes [TCX_CONTROLPLANE_OFFSET] >> 2); p < pend; p++)
+		*p &= 0xffffff;
+}
+
+static void
+tcx_switch_from_graph (void)
+{
+	fbinfo_t *fb = &(fbinfo [0]);
+
+	/* Reset control plane to 8bit mode if necessary */
+	if (fb->open && fb->mmaped)
+		tcx_set_control_plane (fb);
+}
+
+/* Ugh: X wants to mmap a bunch of cute stuff at the same time :-( */
+/* So, we just mmap the things that are being asked for */
+static int
+tcx_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
+	  long base, fbinfo_t *fb)
+{
+	uint size, page, r, map_size;
+	uint map_offset = 0, i;
+	long offsets[13] = { -1, TCX_RAM24BIT, TCX_UNK3, TCX_UNK4,
+			     -1, TCX_UNK6, TCX_UNK7,
+			     -1, -1, -1, TCX_UNK2, TCX_DHC, TCX_ALT };
+			     
+	size = vma->vm_end - vma->vm_start;
+        if (vma->vm_offset & ~PAGE_MASK)
+                return -ENXIO;
+
+	/* To stop the swapper from even considering these pages */
+	vma->vm_flags |= FB_MMAP_VM_FLAGS;
+	
+	/* Each page, see which map applies */
+	for (page = 0; page < size; ){
+		switch (vma->vm_offset+page){
+		case TCX_RAM8BIT:
+			map_size = fb->type.fb_size;
+			map_offset = get_phys ((uint) fb->base);
+			break;
+		case TCX_TEC:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.tcx.tec);
+			break;
+		case TCX_BTREGS:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.tcx.bt);
+			break;
+		case TCX_THC:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.tcx.thc);
+			break;
+		case TCX_CONTROLPLANE:
+			if (fb->info.tcx.tcx_cplane) {
+				map_size = fb->info.tcx.tcx_sizes [TCX_CONTROLPLANE_OFFSET];
+				map_offset = get_phys ((uint)fb->info.tcx.tcx_cplane);
+			} else
+				map_size = 0;
+			break;
+		default:
+			map_size = 0;
+			for (i = 0; i < 13; i++)
+				if (offsets [i] == vma->vm_offset+page) {
+					if ((map_size = fb->info.tcx.tcx_sizes [i]))
+						map_offset = fb->info.tcx.tcx_offsets [i];
+					break;
+				}
+			break;
+		}
+		if (!map_size){
+			page += PAGE_SIZE;
+			continue;
+		}
+		if (page + map_size > size)
+			map_size = size - page;
+		r = io_remap_page_range (vma->vm_start+page,
+					 map_offset,
+					 map_size, vma->vm_page_prot,
+					 fb->space);
+		if (r) return -EAGAIN;
+		page += map_size;
+	}
+        vma->vm_inode = inode;
+        inode->i_count++;
+        return 0;
+}
+
+static void
+tcx_loadcmap (fbinfo_t *fb, int index, int count)
+{
+	struct bt_regs *bt = fb->info.tcx.bt;
+	int i;
+	
+	bt->addr = index << 24;
+	for (i = index; count--; i++){
+		bt->color_map = fb->color_map CM(i,0) << 24;
+		bt->color_map = fb->color_map CM(i,1) << 24;
+		bt->color_map = fb->color_map CM(i,2) << 24;
+	}
+	bt->addr = 0;
+}
+
+static void
+tcx_setcursormap (fbinfo_t *fb, unsigned char *red,
+				 unsigned char *green,
+				 unsigned char *blue)
+{
+	struct bt_regs *bt = fb->info.tcx.bt;
+
+	/* Note the 2 << 24 is different from cg6's 1 << 24 */
+	bt->addr = 2 << 24;
+	bt->cursor = red[0] << 24;
+	bt->cursor = green[0] << 24;
+	bt->cursor = blue[0] << 24;
+	bt->addr = 3 << 24;
+	bt->cursor = red[1] << 24;
+	bt->cursor = green[1] << 24;
+	bt->cursor = blue[1] << 24;
+	bt->addr = 0;
+}
+
+/* Load cursor information */
+static void
+tcx_setcursor (fbinfo_t *fb)
+{
+	uint v;
+	struct cg_cursor *c = &fb->cursor;
+
+	if (c->enable){
+		v = ((c->cpos.fbx - c->chot.fbx) << 16)
+		   |((c->cpos.fby - c->chot.fby) & 0xffff);
+	} else {
+		/* Magic constant to turn off the cursor */
+		v = ((65536-32) << 16) | (65536-32);
+	}
+	fb->info.tcx.thc->thc_cursxy = v;
+}
+
+/* Set cursor shape */
+static void
+tcx_setcurshape (fbinfo_t *fb)
+{
+	struct tcx_thc *thc = fb->info.tcx.thc;
+	int i;
+	
+	for (i = 0; i < 32; i++){
+		thc->thc_cursmask [i] = fb->cursor.bits[0][i];
+		thc->thc_cursbits [i] = fb->cursor.bits[1][i];
+	}
+}
+
+static void
+tcx_blank (fbinfo_t *fb)
+{
+	fb->info.tcx.thc->thc_misc &= ~TCX_THC_MISC_VIDEO;
+}
+
+static void
+tcx_unblank (fbinfo_t *fb)
+{
+	fb->info.tcx.thc->thc_misc |= TCX_THC_MISC_VIDEO;
+}
+
+void
+tcx_reset (fbinfo_t *fb)
+{
+	struct tcx_info *tcx = &(fb->info.tcx);
+
+	if (fb->setcursor)
+		sun_hw_hide_cursor ();
+	/* Reset control plane to 8bit mode if necessary */
+	if (fb->open && fb->mmaped)
+		tcx_set_control_plane (fb);
+
+	/* Turn off stuff in the Transform Engine. */
+	tcx->tec->tec_matrix = 0;
+	tcx->tec->tec_clip = 0;
+	tcx->tec->tec_vdc = 0;
+
+	/* Enable cursor in Brooktree DAC. */
+	tcx->bt->addr = 0x06 << 24;
+	tcx->bt->control |= 0x03 << 24;
+}
+
+__initfunc(void tcx_setup (fbinfo_t *fb, int slot, int node, uint tcx, struct linux_sbus_device *sbdp))
+{
+	struct tcx_info *tcxinfo;
+	int i;
+
+	printk ("tcx%d at 0x%8.8x ", slot, (uint) tcx);
+	
+	/* Fill in parameters we left out */
+	fb->type.fb_cmsize = 256;
+	fb->mmap = tcx_mmap;
+	fb->loadcmap = tcx_loadcmap;
+	fb->reset = tcx_reset;
+	fb->blank = tcx_blank;
+	fb->unblank = tcx_unblank;
+	fb->emulations [1] = FBTYPE_SUN3COLOR;
+	fb->emulations [2] = FBTYPE_MEMCOLOR;
+	fb->switch_from_graph = tcx_switch_from_graph;
+	fb->postsetup = sun_cg_postsetup;
+	
+	tcxinfo = (struct tcx_info *) &fb->info.tcx;
+	
+	memset (tcxinfo, 0, sizeof(struct tcx_info));
+	
+	for (i = 0; i < 13; i++)
+		tcxinfo->tcx_offsets [i] = (long)(sbdp->reg_addrs [i].phys_addr);
+		
+	/* Map the hardware registers */
+	tcxinfo->bt = sparc_alloc_io ((void *) tcxinfo->tcx_offsets [TCX_BROOKTREE_OFFSET], 0,
+		 sizeof (struct bt_regs),"tcx_dac", fb->space, 0);
+	tcxinfo->thc = sparc_alloc_io ((void *) tcxinfo->tcx_offsets [TCX_THC_OFFSET], 0,
+		 sizeof (struct tcx_thc), "tcx_thc", fb->space, 0);
+	tcxinfo->tec = sparc_alloc_io ((void *) tcxinfo->tcx_offsets [TCX_TEC_OFFSET], 0,
+		 sizeof (struct tcx_tec), "tcx_tec", fb->space, 0);
+	if (!fb->base){
+		fb->base = (uint) sparc_alloc_io ((void *) tcxinfo->tcx_offsets [TCX_RAM8BIT_OFFSET], 0,
+                    fb->type.fb_size, "tcx_ram", fb->space, 0);
+	}
+	
+	if (prom_getbool (node, "hw-cursor")) {
+		fb->setcursor = tcx_setcursor;
+		fb->setcursormap = tcx_setcursormap;
+		fb->setcurshape = tcx_setcurshape;
+	}
+		
+	if (!slot) {
+		fb_restore_palette = tcx_restore_palette;
+	}
+	
+	i = fb->type.fb_size;
+	tcxinfo->tcx_sizes[2] = i << 3;
+	tcxinfo->tcx_sizes[3] = i << 3;
+	tcxinfo->tcx_sizes[10] = 0x20000;
+	tcxinfo->tcx_sizes[11] = PAGE_SIZE;
+	tcxinfo->tcx_sizes[12] = PAGE_SIZE;
+	
+	if (prom_getbool (node, "tcx-8-bit"))
+		tcxinfo->lowdepth = 1;
+		
+	if (!tcxinfo->lowdepth) {
+		tcxinfo->tcx_sizes[1] = i << 2;
+		tcxinfo->tcx_sizes[4] = i << 2;
+		tcxinfo->tcx_sizes[5] = i << 3;
+		tcxinfo->tcx_sizes[6] = i << 3;
+		fb->type.fb_depth = 24;
+		tcxinfo->tcx_cplane = sparc_alloc_io ((void *) tcxinfo->tcx_offsets [TCX_CONTROLPLANE_OFFSET], 0,
+		 	tcxinfo->tcx_sizes [TCX_CONTROLPLANE_OFFSET], "tcx_cplane", fb->space, 0);
+	}
+	
+	/* Initialize Brooktree DAC */
+	tcxinfo->bt->addr = 0x04 << 24;		/* color planes */
+	tcxinfo->bt->control = 0xff << 24;
+	tcxinfo->bt->addr = 0x05 << 24;
+	tcxinfo->bt->control = 0x00 << 24;
+	tcxinfo->bt->addr = 0x06 << 24;		/* overlay plane */
+	tcxinfo->bt->control = 0x73 << 24;
+	tcxinfo->bt->addr = 0x07 << 24;
+	tcxinfo->bt->control = 0x00 << 24;
+
+	printk("Rev %d.%d %s\n",
+		(tcxinfo->thc->thc_rev >> TCX_THC_REV_REV_SHIFT) & TCX_THC_REV_REV_MASK,
+		(tcxinfo->thc->thc_rev >> TCX_THC_REV_MINREV_SHIFT) & TCX_THC_REV_MINREV_MASK,
+		tcxinfo->lowdepth ? "8-bit only" : "24-bit depth");
+	
+	/* Reset the tcx */
+	tcx_reset(fb);
+
+	if (!slot)	
+	/* Enable Video */
+		tcx_unblank (fb);
+	else
+		tcx_blank (fb);
+}
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/weitek.c linux/drivers/sbus/char/weitek.c
--- v2.1.15/linux/drivers/sbus/char/weitek.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/sbus/char/weitek.c	Fri Dec 13 11:37:37 1996
@@ -0,0 +1,116 @@
+/* $Id: weitek.c,v 1.6 1996/11/13 05:10:51 davem Exp $
+ * weitek.c: Tadpole P9100/P9000 console driver
+ *
+ * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
+ */
+
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+
+#include <asm/openprom.h>
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/fbio.h>
+#include <asm/pgtable.h>
+
+#include "../../char/vt_kern.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+#include "fb.h"
+#include "cg_common.h"
+
+/*
+ * mmap info
+ */
+#define WEITEK_VRAM_OFFSET	0
+#define WEITEK_VRAM_SIZE	(2*1024*1024)	/* maximum */
+#define WEITEK_GX_REG_OFFSET	WEITEK_VRAM_SIZE
+#define WEITEK_GX_REG_SIZE	8192
+#define WEITEK_VID_REG_OFFSET	(WEITEK_GX_REG_OFFSET+WEITEK_GX_REG_SIZE)
+#define WEITEK_VID_REG_SIZE	0x1000
+
+#define CONTROL_OFFSET	0
+#define RAMDAC_OFFSET	(CONTROL_OFFSET+0x200)
+
+#if 0
+static int
+weitek_mmap(struct inode *inode, struct file *file, struct vm_area_struct *vma,
+	    long base, fbinfo_t *fb)
+{
+	unsigned int size, page, r, map_size;
+	unsigned int map_offset = 0;
+	
+	size = vma->vm_end - vma->vm_start;
+	if (vma->vm_offset & ~PAGE_MASK)
+		return -ENXIO;
+	
+	/* To stop the swapper from even considering these pages */
+	vma->vm_flags |= FB_MMAP_VM_FLAGS; 
+	
+	/* Each page, see which map applies */
+	for (page = 0; page < size; ){
+		switch (vma->vm_offset+page){
+		case WEITEK_VRAM_OFFSET:
+			map_size = size-page;
+			map_offset = get_phys ((uint) fb->base);
+			if (map_size > fb->type.fb_size)
+				map_size = fb->type.fb_size;
+			break;
+		case WEITEK_GX_REG_OFFSET:
+			map_size = size-page;
+			map_offset = get_phys ((uint) fb->base);
+			if (map_size > fb->type.fb_size)
+				map_size = fb->type.fb_size;
+			break;
+		default:
+			map_size = 0;
+			break;
+		}
+		if (!map_size){
+			page += PAGE_SIZE;
+			continue;
+		}
+		if (page + map_size > size)
+			map_size = size - page;
+		r = io_remap_page_range (vma->vm_start+page,
+					 map_offset,
+					 map_size, vma->vm_page_prot,
+					 fb->space);
+		if (r) return -EAGAIN;
+		page += map_size;
+	}
+	vma->vm_inode = inode;
+	inode->i_count++;
+	return 0;
+}
+#endif
+
+#if 0
+static void
+weitek_loadcmap (void *fbinfo, int index, int count)
+{
+	printk("weitek_cmap: unimplemented!\n");
+}
+#endif
+
+__initfunc(void weitek_setup(fbinfo_t *fb, int slot, uint addr, int io))
+{
+	extern struct screen_info screen_info;
+	
+	printk ("weitek%d at 0x%8.8x\n", slot, addr);
+	
+	/* Fill in parameters we left out */
+	fb->type.fb_type	= FBTYPE_NOTSUN1;
+	fb->type.fb_cmsize	= 256;
+	fb->mmap		= 0; /* weitek_mmap; */
+	fb->loadcmap		= 0; /* unimplemented */
+	fb->ioctl		= 0; /* no special ioctls */
+	fb->reset		= 0; /* no special reset */
+	
+	/* Map the card registers */
+	if (!fb->base){
+	    prom_printf ("Missing mapping routine and no address found\n");
+	}
+}
+
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/dvma.c linux/drivers/sbus/dvma.c
--- v2.1.15/linux/drivers/sbus/dvma.c	Tue Apr 23 12:31:35 1996
+++ linux/drivers/sbus/dvma.c	Fri Dec 13 11:37:37 1996
@@ -5,12 +5,12 @@
 
 #include <linux/kernel.h>
 #include <linux/malloc.h>
+#include <linux/init.h>
 
 #include <asm/oplib.h>
 #include <asm/contregs.h>
 #include <asm/sysen.h>
 #include <asm/delay.h>
-#include <asm/idprom.h>
 #include <asm/machines.h>
 #include <asm/io.h>
 #include <asm/dma.h>
@@ -34,8 +34,8 @@
 
 
 /* Probe this SBus DMA module(s) */
-unsigned long
-dvma_init(struct linux_sbus *sbus, unsigned long memory_start)
+__initfunc(unsigned long
+dvma_init(struct linux_sbus *sbus, unsigned long memory_start))
 {
 	struct linux_sbus_device *this_dev;
 	struct Linux_SBus_DMA *dma;
@@ -43,9 +43,13 @@
 	static int num_dma=0;
 
 	for_each_sbusdev(this_dev, sbus) {
-		if(strcmp(this_dev->prom_name, "dma") &&
-		   strcmp(this_dev->prom_name, "ledma") &&
-		   strcmp(this_dev->prom_name, "espdma"))
+		int hme = 0;
+
+		if(!strcmp(this_dev->prom_name, "SUNW,fas")) {
+			hme = 1;
+		} else if(strcmp(this_dev->prom_name, "dma") &&
+			  strcmp(this_dev->prom_name, "ledma") &&
+			  strcmp(this_dev->prom_name, "espdma"))
 			continue;
 
 		/* Found one... */
@@ -71,7 +75,10 @@
 		/* The constant PAGE_SIZE that is passed to sparc_alloc_io makes the
 		 * routine only alloc 1 page, that was what the original code did
 		 */
-		prom_apply_sbus_ranges(dma->SBus_dev->reg_addrs, 0x1);
+		if(hme) /* On HME cards, dvma lives with esp, 2 reg sets. */
+			prom_apply_sbus_ranges(sbus, dma->SBus_dev->reg_addrs, 0x2);
+		else    /* All others have only 1 reg set. */
+			prom_apply_sbus_ranges(sbus, dma->SBus_dev->reg_addrs, 0x1);
 		dma->regs = (struct sparc_dma_registers *)
 			sparc_alloc_io (dma->SBus_dev->reg_addrs[0].phys_addr, 0,
 					PAGE_SIZE, "dma",
@@ -96,6 +103,10 @@
 		case DMA_VERS2:
 			dma->revision=dvmarev2;
 			printk("Revision 2 ");
+			break;
+		case DMA_VERHME:
+			dma->revision=dvmahme;
+			printk("HME DVMA gate array ");
 			break;
 		case DMA_VERSPLUS:
 			dma->revision=dvmarevplus;
diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/sbus.c linux/drivers/sbus/sbus.c
--- v2.1.15/linux/drivers/sbus/sbus.c	Sun Apr 21 17:32:02 1996
+++ linux/drivers/sbus/sbus.c	Fri Dec 13 11:37:37 1996
@@ -5,6 +5,8 @@
 
 #include <linux/kernel.h>
 #include <linux/malloc.h>
+#include <linux/config.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/sbus.h>
@@ -19,6 +21,8 @@
 
 static char lbuf[128];
 
+extern void prom_sbus_ranges_init (int, struct linux_sbus *);
+
 /* Perhaps when I figure out more about the iommu we'll put a
  * device registration routine here that probe_sbus() calls to
  * setup the iommu for each Sbus.
@@ -30,8 +34,8 @@
  */
 
 /* #define DEBUG_FILL */
-void
-fill_sbus_device(int nd, struct linux_sbus_device *sbus_dev)
+__initfunc(static void
+fill_sbus_device(int nd, struct linux_sbus_device *sbus_dev))
 {
 	int grrr, len;
 	unsigned long dev_base_addr, base;
@@ -46,6 +50,8 @@
 
 	len = prom_getproperty(nd, "reg", (void *) sbus_dev->reg_addrs,
 			       sizeof(sbus_dev->reg_addrs));
+	if(len == -1)
+		goto no_regs;
 	if(len%sizeof(struct linux_prom_registers)) {
 		prom_printf("WHOOPS:  proplen for %s was %d, need multiple of %d\n",
 		       sbus_dev->prom_name, len,
@@ -79,6 +85,7 @@
 		panic("sbus device register overflow");
 	}
 
+no_regs:
 	len = prom_getproperty(nd, "address", (void *) sbus_dev->sbus_vaddrs,
 			       sizeof(sbus_dev->sbus_vaddrs));
 	if(len == -1) len=0;
@@ -130,12 +137,53 @@
  * devices.
  */
 
-extern void sun_console_init(void);
+extern unsigned long sun_console_init(unsigned long);
 extern unsigned long iommu_init(int iommu_node, unsigned long memstart,
 				unsigned long memend, struct linux_sbus *sbus);
+extern void iommu_sun4d_init(int sbi_node, struct linux_sbus *sbus);
+#ifdef CONFIG_SUN_OPENPROMIO
+extern int openprom_init(void);
+#endif
+#ifdef CONFIG_SUN_MOSTEK_RTC
+extern int rtc_init(void);
+#endif
+
+__initfunc(static unsigned long 
+sbus_do_child_siblings(unsigned long memory_start, int start_node,
+		       struct linux_sbus_device *child,
+		       struct linux_sbus *sbus))
+{
+	struct linux_sbus_device *this_dev = child;
+	int this_node = start_node;
+
+	/* Child already filled in, just need to traverse siblings. */
+	while((this_node = prom_getsibling(this_node)) != 0) {
+		this_dev->next = (struct linux_sbus_device *) memory_start;
+		memory_start += sizeof(struct linux_sbus_device);
+		this_dev = this_dev->next;
+		this_dev->next = 0;
+
+		fill_sbus_device(this_node, this_dev);
+		this_dev->my_bus = sbus;
+
+		if(prom_getchild(this_node)) {
+			this_dev->child = (struct linux_sbus_device *) memory_start;
+			memory_start += sizeof(struct linux_sbus_device);
+			fill_sbus_device(prom_getchild(this_node), this_dev->child);
+			this_dev->child->my_bus = sbus;
+			memory_start = sbus_do_child_siblings(memory_start,
+							      prom_getchild(this_node),
+							      this_dev->child,
+							      sbus);
+		} else {
+			this_dev->child = 0;
+		}
+	}
+	return memory_start;
+}
 
-unsigned long
-sbus_init(unsigned long memory_start, unsigned long memory_end)
+__initfunc(unsigned long
+sbus_init(unsigned long memory_start, unsigned long memory_end))
 {
 	register int nd, this_sbus, sbus_devs, topnd, iommund;
 	unsigned int sbus_clock;
@@ -149,7 +197,13 @@
 
 	/* Finding the first sbus is a special case... */
 	iommund = 0;
-	if((nd = prom_searchsiblings(topnd, "sbus")) == 0) {
+	if (sparc_cpu_model == sun4d) {
+		if((iommund = prom_searchsiblings(topnd, "io-unit")) == 0 ||
+		   (nd = prom_getchild(iommund)) == 0 ||
+		   (nd = prom_searchsiblings(nd, "sbi")) == 0) {
+		   	panic("sbi not found");
+		}
+	} else if((nd = prom_searchsiblings(topnd, "sbus")) == 0) {
 		if((iommund = prom_searchsiblings(topnd, "iommu")) == 0 ||
 		   (nd = prom_getchild(iommund)) == 0 ||
 		   (nd = prom_searchsiblings(nd, "sbus")) == 0) {
@@ -167,8 +221,12 @@
 	this_sbus=nd;
 
 	/* Have IOMMU will travel. XXX grrr - this should be per sbus... */
-	if(iommund)
-		memory_start = iommu_init(iommund, memory_start, memory_end, sbus);
+	if(iommund) {
+		if (sparc_cpu_model == sun4d)
+			iommu_sun4d_init(this_sbus, sbus);
+		else
+			memory_start = iommu_init(iommund, memory_start, memory_end, sbus);
+	}
 
 	/* Loop until we find no more SBUS's */
 	while(this_sbus) {
@@ -183,6 +241,8 @@
 		sbus->prom_node = this_sbus;
 		strcpy(sbus->prom_name, lbuf);
 		sbus->clock_freq = sbus_clock;
+		
+		prom_sbus_ranges_init (iommund, sbus);
 
 		sbus_devs = prom_getchild(this_sbus);
 
@@ -196,14 +256,17 @@
 		this_dev->my_bus = sbus;
 
 		/* Should we traverse for children? */
-		if(strcmp(this_dev->prom_name, "espdma")==0 ||
-		   strcmp(this_dev->prom_name, "ledma")==0) {
+		if(prom_getchild(sbus_devs)) {
 			/* Allocate device node */
 			this_dev->child = (struct linux_sbus_device *) memory_start;
 			memory_start += sizeof(struct linux_sbus_device);
 			/* Fill it */
 			fill_sbus_device(prom_getchild(sbus_devs), this_dev->child);
 			this_dev->child->my_bus = sbus;
+			memory_start = sbus_do_child_siblings(memory_start,
+							      prom_getchild(sbus_devs),
+							      this_dev->child,
+							      sbus);
 		} else {
 			this_dev->child = 0;
 		}
@@ -220,8 +283,7 @@
 			this_dev->my_bus = sbus;
 
 			/* Is there a child node hanging off of us? */
-			if(strcmp(this_dev->prom_name, "espdma")==0 ||
-			   strcmp(this_dev->prom_name, "ledma")==0) {
+			if(prom_getchild(sbus_devs)) {
 				/* Get new device struct */
 				this_dev->child =
 					(struct linux_sbus_device *) memory_start;
@@ -231,6 +293,11 @@
 				fill_sbus_device(prom_getchild(sbus_devs),
 						 this_dev->child);
 				this_dev->child->my_bus = sbus;
+				memory_start = sbus_do_child_siblings(
+						     memory_start,
+						     prom_getchild(sbus_devs),
+						     this_dev->child,
+						     sbus);
 			} else {
 				this_dev->child = 0;
 			}
@@ -239,9 +306,17 @@
 		memory_start = dvma_init(sbus, memory_start);
 
 		num_sbus++;
-		this_sbus = prom_getsibling(this_sbus);
-		if(!this_sbus) break;
-		this_sbus = prom_searchsiblings(this_sbus, "sbus");
+		if (sparc_cpu_model == sun4d) {
+			iommund = prom_getsibling(iommund);
+			if(!iommund) break;
+			iommund = prom_searchsiblings(iommund, "io-unit");
+			if(!iommund) break;
+			this_sbus = prom_searchsiblings(prom_getchild(iommund), "sbi");
+		} else {
+			this_sbus = prom_getsibling(this_sbus);
+			if(!this_sbus) break;
+			this_sbus = prom_searchsiblings(this_sbus, "sbus");
+		}
 		if(this_sbus) {
 			sbus->next = (struct linux_sbus *) memory_start;
 			memory_start += sizeof(struct linux_sbus);
@@ -251,6 +326,12 @@
 			break;
 		}
 	} /* while(this_sbus) */
-	sun_console_init(); /* whee... */
+	memory_start = sun_console_init(memory_start); /* whee... */
+#ifdef CONFIG_SUN_OPENPROMIO
+	openprom_init();
+#endif
+#ifdef CONFIG_SUN_MOSTEK_RTC
+	rtc_init();
+#endif
 	return memory_start;
 }
diff -u --recursive --new-file v2.1.15/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v2.1.15/linux/drivers/scsi/Makefile	Thu Dec 12 19:37:07 1996
+++ linux/drivers/scsi/Makefile	Fri Dec 13 11:37:37 1996
@@ -224,6 +224,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_SCSI_QLOGICPTI),y)
+L_OBJS += qlogicpti.o
+else
+  ifeq ($(CONFIG_SCSI_QLOGICPTI),m)
+  M_OBJS += qlogicpti.o
+  endif
+endif
+
 ifeq ($(CONFIG_SCSI_DEBUG),y)
 L_OBJS += scsi_debug.o
 else
diff -u --recursive --new-file v2.1.15/linux/drivers/scsi/esp.c linux/drivers/scsi/esp.c
--- v2.1.15/linux/drivers/scsi/esp.c	Sun Apr 21 12:42:05 1996
+++ linux/drivers/scsi/esp.c	Fri Dec 13 11:37:37 1996
@@ -3,6 +3,15 @@
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  */
 
+/* TODO:
+ *
+ * 1) Maybe disable parity checking in config register one for SCSI1
+ *    targets.  (Gilmore says parity error on the SBus can lock up
+ *    old sun4c's)
+ * 2) Add support for DMA2 pipelining.
+ * 3) Add tagged queueing.
+ */
+
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/types.h>
@@ -19,39 +28,135 @@
 #include <asm/sbus.h>
 #include <asm/dma.h>
 #include <asm/system.h>
-#include <asm/idprom.h>
 #include <asm/machines.h>
 #include <asm/ptrace.h>
 #include <asm/pgtable.h>
 #include <asm/oplib.h>
 #include <asm/vaddrs.h>
 #include <asm/io.h>
+#include <asm/idprom.h>
 
 #define DEBUG_ESP
+/* #define DEBUG_ESP_HME */
+/* #define DEBUG_ESP_DATA */
+/* #define DEBUG_ESP_QUEUE */
+/* #define DEBUG_ESP_DISCONNECT */
+/* #define DEBUG_ESP_STATUS */
+/* #define DEBUG_ESP_PHASES */
+/* #define DEBUG_ESP_WORKBUS */
+/* #define DEBUG_STATE_MACHINE */
+/* #define DEBUG_ESP_CMDS */
+/* #define DEBUG_ESP_IRQS */
+/* #define DEBUG_SDTR */
 /* #define DEBUG_ESP_SG */
 
+/* Use the following to sprinkle debugging messages in a way which
+ * suits you if combinations of the above become too verbose when
+ * trying to track down a specific problem.
+ */
+/* #define DEBUG_ESP_MISC */
+
 #if defined(DEBUG_ESP)
 #define ESPLOG(foo)  printk foo
 #else
 #define ESPLOG(foo)
 #endif /* (DEBUG_ESP) */
 
-#define INTERNAL_ESP_ERROR \
-        (panic ("Internal ESP driver error in file %s, line %d\n", \
-		__FILE__, __LINE__))
-
-#define INTERNAL_ESP_ERROR_NOPANIC \
-        (printk ("Internal ESP driver error in file %s, line %d\n", \
-		 __FILE__, __LINE__))
+#if defined(DEBUG_ESP_HME)
+#define ESPHME(foo)  printk foo
+#else
+#define ESPHME(foo)
+#endif
+
+#if defined(DEBUG_ESP_DATA)
+#define ESPDATA(foo)  printk foo
+#else
+#define ESPDATA(foo)
+#endif
+
+#if defined(DEBUG_ESP_QUEUE)
+#define ESPQUEUE(foo)  printk foo
+#else
+#define ESPQUEUE(foo)
+#endif
+
+#if defined(DEBUG_ESP_DISCONNECT)
+#define ESPDISC(foo)  printk foo
+#else
+#define ESPDISC(foo)
+#endif
+
+#if defined(DEBUG_ESP_STATUS)
+#define ESPSTAT(foo)  printk foo
+#else
+#define ESPSTAT(foo)
+#endif
+
+#if defined(DEBUG_ESP_PHASES)
+#define ESPPHASE(foo)  printk foo
+#else
+#define ESPPHASE(foo)
+#endif
+
+#if defined(DEBUG_ESP_WORKBUS)
+#define ESPBUS(foo)  printk foo
+#else
+#define ESPBUS(foo)
+#endif
+
+#if defined(DEBUG_ESP_IRQS)
+#define ESPIRQ(foo)  printk foo
+#else
+#define ESPIRQ(foo)
+#endif
+
+#if defined(DEBUG_SDTR)
+#define ESPSDTR(foo)  printk foo
+#else
+#define ESPSDTR(foo)
+#endif
+
+#if defined(DEBUG_ESP_MISC)
+#define ESPMISC(foo)  printk foo
+#else
+#define ESPMISC(foo)
+#endif
 
-/* This enum will be expanded when we have sync code written. */
+/* Command phase enumeration. */
 enum {
-	not_issued   = 0x01,  /* Still in the issue_SC queue.          */
-	in_selection = 0x02,  /* ESP is arbitrating, awaiting IRQ      */
-	in_datain    = 0x04,  /* Data is transferring over the bus     */
-	in_dataout   = 0x08,  /* Data is transferring over the bus     */
-	in_status    = 0x10,  /* Awaiting status/msg bytes from target */
-	in_finale    = 0x11,  /* Sent Msg ack, awaiting disconnect     */
+	not_issued    = 0x00,  /* Still in the issue_SC queue.          */
+
+	/* Various forms of selecting a target. */
+#define in_slct_mask    0x10
+	in_slct_norm  = 0x10,  /* ESP is arbitrating, normal selection  */
+	in_slct_stop  = 0x11,  /* ESP will select, then stop with IRQ   */
+	in_slct_msg   = 0x12,  /* select, then send a message           */
+	in_slct_tag   = 0x13,  /* select and send tagged queue msg      */
+	in_slct_sneg  = 0x14,  /* select and acquire sync capabilities  */
+
+	/* Any post selection activity. */
+#define in_phases_mask  0x20
+	in_datain     = 0x20,  /* Data is transferring from the bus     */
+	in_dataout    = 0x21,  /* Data is transferring to the bus       */
+	in_data_done  = 0x22,  /* Last DMA data operation done (maybe)  */
+	in_msgin      = 0x23,  /* Eating message from target            */
+	in_msgincont  = 0x24,  /* Eating more msg bytes from target     */
+	in_msgindone  = 0x25,  /* Decide what to do with what we got    */
+	in_msgout     = 0x26,  /* Sending message to target             */
+	in_msgoutdone = 0x27,  /* Done sending msg out                  */
+	in_cmdbegin   = 0x28,  /* Sending cmd after abnormal selection  */
+	in_cmdend     = 0x29,  /* Done sending slow cmd                 */
+	in_status     = 0x2a,  /* Was in status phase, finishing cmd    */
+	in_freeing    = 0x2b,  /* freeing the bus for cmd cmplt or disc */
+	in_the_dark   = 0x2c,  /* Don't know what bus phase we are in   */
+
+	/* Special states, ie. not normal bus transitions... */
+#define in_spec_mask    0x80
+	in_abortone   = 0x80,  /* Aborting one command currently        */
+	in_abortall   = 0x81,  /* Blowing away all commands we have     */
+	in_resetdev   = 0x82,  /* SCSI target reset in progress         */
+	in_resetbus   = 0x83,  /* SCSI bus reset in progress            */
+	in_tgterror   = 0x84,  /* Target did something stupid           */
 };
 
 struct proc_dir_entry proc_scsi_esp = {
@@ -59,8 +164,11 @@
 	S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
 
-struct Sparc_ESP *espchain;
+/* The master ring of all esp hosts we are managing in this driver. */
+static struct Sparc_ESP *espchain;
+static int esps_running = 0;
 
+/* Forward declarations. */
 static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
 static void esp_done(struct Sparc_ESP *esp, int error);
 
@@ -181,10 +289,102 @@
 		(stepreg == ESP_STEP_SID ? "1BYTE_MSG_SENT" :
 		 (stepreg == ESP_STEP_NCMD ? "NOT_IN_CMD_PHASE" :
 		  (stepreg == ESP_STEP_PPC ? "CMD_BYTES_LOST" :
-		   (stepreg == ESP_STEP_FINI ? "CMD_SENT_OK" :
+		   (stepreg == ESP_STEP_FINI4 ? "CMD_SENT_OK" :
 		    "UNKNOWN"))))));
 }
 
+static char *phase_string(int phase)
+{
+	switch(phase) {
+	case not_issued:
+		return "UNISSUED";
+	case in_slct_norm:
+		return "SLCTNORM";
+	case in_slct_stop:
+		return "SLCTSTOP";
+	case in_slct_msg:
+		return "SLCTMSG";
+	case in_slct_tag:
+		return "SLCTTAG";
+	case in_slct_sneg:
+		return "SLCTSNEG";
+	case in_datain:
+		return "DATAIN";
+	case in_dataout:
+		return "DATAOUT";
+	case in_data_done:
+		return "DATADONE";
+	case in_msgin:
+		return "MSGIN";
+	case in_msgincont:
+		return "MSGINCONT";
+	case in_msgindone:
+		return "MSGINDONE";
+	case in_msgout:
+		return "MSGOUT";
+	case in_msgoutdone:
+		return "MSGOUTDONE";
+	case in_cmdbegin:
+		return "CMDBEGIN";
+	case in_cmdend:
+		return "CMDEND";
+	case in_status:
+		return "STATUS";
+	case in_freeing:
+		return "FREEING";
+	case in_the_dark:
+		return "CLUELESS";
+	case in_abortone:
+		return "ABORTONE";
+	case in_abortall:
+		return "ABORTALL";
+	case in_resetdev:
+		return "RESETDEV";
+	case in_resetbus:
+		return "RESETBUS";
+	case in_tgterror:
+		return "TGTERROR";
+	default:
+		return "UNKNOWN";
+	};
+}
+
+static inline void esp_advance_phase(Scsi_Cmnd *s, int newphase)
+{
+#ifdef DEBUG_STATE_MACHINE
+	ESPLOG(("<%s>", phase_string(newphase)));
+#endif
+	s->SCp.sent_command = s->SCp.phase;
+	s->SCp.phase = newphase;
+}
+
+extern inline void esp_cmd(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+			   unchar cmd)
+{
+#ifdef DEBUG_ESP_CMDS
+	esp->espcmdlog[esp->espcmdent] = cmd;
+	esp->espcmdent = (esp->espcmdent + 1) & 31;
+#endif
+	eregs->esp_cmd = cmd;
+}
+
+/* How we use the various Linux SCSI data structures for operation.
+ *
+ * struct scsi_cmnd:
+ *
+ *   We keep track of the syncronous capabilities of a target
+ *   in the device member, using sync_min_period and
+ *   sync_max_offset.  These are the values we directly write
+ *   into the ESP registers while running a command.  If offset
+ *   is zero the ESP will use asynchronous transfers.
+ *   If the borken flag is set we assume we shouldn't even bother
+ *   trying to negotiate for synchronous transfer as this target
+ *   is really stupid.  If we notice the target is dropping the
+ *   bus, and we have been allowing it to disconnect, we clear
+ *   the disconnect flag.
+ */
+
+
 /* Manipulation of the ESP command queues.  Thanks to the aha152x driver
  * and its author, Juergen E. Fischer, for the methods used here.
  * Note that these are per-ESP queues, not global queues like
@@ -207,6 +407,16 @@
 	restore_flags(flags);
 }
 
+static inline void prepend_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
+{
+	unsigned long flags;
+
+	save_flags(flags); cli();
+	new_SC->host_scribble = (unsigned char *) *SC;
+	*SC = new_SC;
+	restore_flags(flags);
+}
+
 static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd **SC)
 {
 	Scsi_Cmnd *ptr;
@@ -240,58 +450,188 @@
 	return ptr;
 }
 
-static inline void do_pause(unsigned amount)
-{
-	unsigned long the_time = jiffies + amount;
-
-	while(jiffies < the_time)
-		barrier(); /* Not really needed, but... */
-}
-
-/* This places the ESP into a known state at boot time. */
-static inline void esp_bootup_reset(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs)
+/* Resetting various pieces of the ESP scsi driver chipset/buses. */
+static inline void esp_reset_dma(struct Sparc_ESP *esp)
 {
 	struct sparc_dma_registers *dregs = esp->dregs;
-	volatile unchar trash;
+	unsigned long tmp, flags;
+	int can_do_burst16, can_do_burst32;
+
+	can_do_burst16 = esp->bursts & DMA_BURST16;
+	can_do_burst32 = esp->bursts & DMA_BURST32;
 
 	/* Punt the DVMA into a known state. */
-	dregs->cond_reg |= DMA_RST_SCSI;
-	do_pause(100);
-	dregs->cond_reg &= ~(DMA_RST_SCSI);
-	if(esp->dma->revision == dvmarev2)
+	if(esp->dma->revision != dvmahme) {
+		dregs->cond_reg |= DMA_RST_SCSI;
+		dregs->cond_reg &= ~(DMA_RST_SCSI);
+	}
+	switch(esp->dma->revision) {
+	case dvmahme:
+		/* This is the HME DVMA gate array. */
+
+		save_flags(flags); cli(); /* I really hate this chip. */
+
+		dregs->cond_reg = 0x08000000;   /* Reset interface to FAS */
+		dregs->cond_reg = DMA_RST_SCSI; /* Reset DVMA itself */
+
+		tmp = (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB|DMA_INT_ENAB);
+		tmp &= ~(DMA_ENABLE|DMA_ST_WRITE|DMA_BRST_SZ);
+
+		if(can_do_burst32)
+			tmp |= DMA_BRST32;
+
+		/* This chip is horrible. */
+		while(dregs->cond_reg & DMA_PEND_READ)
+			udelay(1);
+
+		dregs->cond_reg = 0;
+
+		dregs->cond_reg = tmp;        /* bite me */
+		restore_flags(flags);         /* ugh...  */
+		break;
+	case dvmarev2:
+		/* This is the gate array found in the sun4m
+		 * NCR SBUS I/O subsystem.
+		 */
 		if(esp->erev != esp100)
 			dregs->cond_reg |= DMA_3CLKS;
-	else if(esp->dma->revision == dvmarev3)
-		if(esp->erev == fas236 || esp->erev == fas100a) {
-			dregs->cond_reg &= ~(DMA_3CLKS);
-			dregs->cond_reg |= DMA_2CLKS;
+		break;
+	case dvmarev3:
+		dregs->cond_reg &= ~(DMA_3CLKS);
+		dregs->cond_reg |= DMA_2CLKS;
+		if(can_do_burst32) {
+			dregs->cond_reg &= ~(DMA_BRST_SZ);
+			dregs->cond_reg |= DMA_BRST32;
 		}
-	else if(esp->dma->revision == dvmaesc1)
+		break;
+	case dvmaesc1:
+		/* This is the DMA unit found on SCSI/Ether cards. */
 		dregs->cond_reg |= DMA_ADD_ENABLE;
+		dregs->cond_reg &= ~DMA_BCNT_ENAB;
+		if(!can_do_burst32 && can_do_burst16) {
+			dregs->cond_reg |= DMA_ESC_BURST;
+		} else {
+			dregs->cond_reg &= ~(DMA_ESC_BURST);
+		}
+		break;
+	default:
+		break;
+	};
 	DMA_INTSON(dregs);
+}
+
+/* Reset the ESP chip, _not_ the SCSI bus. */
+static inline void esp_reset_esp(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs)
+{
+	int family_code, version, i;
+	volatile int trash;
 
 	/* Now reset the ESP chip */
-	eregs->esp_cmd = ESP_CMD_RC;
-	eregs->esp_cmd = (ESP_CMD_NULL | ESP_CMD_DMA);
-	eregs->esp_cmd = (ESP_CMD_NULL | ESP_CMD_DMA); /* borken hardware... */
+	esp_cmd(esp, eregs, ESP_CMD_RC);
+	esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA);
+	esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA);
 
 	/* Reload the configuration registers */
-	eregs->esp_cfg1  = esp->config1;
 	eregs->esp_cfact = esp->cfact;
 	eregs->esp_stp   = 0;
 	eregs->esp_soff  = 0;
-	eregs->esp_timeo = esp->sync_defp;
-	if(esp->erev == esp100a || esp->erev == esp236)
+	eregs->esp_timeo = esp->neg_defp;
+
+	/* This is the only point at which it is reliable to read
+	 * the ID-code for a fast ESP chip variants.
+	 */
+	esp->max_period = ((35 * esp->ccycle) / 1000);
+	if(esp->erev == fast) {
+		version = eregs->esp_uid;
+		family_code = (version & 0xf8) >> 3;
+		if(family_code == 0x02)
+			esp->erev = fas236;
+		else if(family_code == 0x0a)
+			esp->erev = fashme; /* Version is usually '5'. */
+		else
+			esp->erev = fas100a;
+		printk("esp%d: FAST chip is %s (family=%d, version=%d)\n",
+		       esp->esp_id,
+		       (esp->erev == fas236) ? "fas236" :
+		       ((esp->erev == fas100a) ? "fas100a" :
+		       "fasHME"), family_code, (version & 7));
+
+		esp->min_period = ((4 * esp->ccycle) / 1000);
+	} else {
+		esp->min_period = ((5 * esp->ccycle) / 1000);
+	}
+	esp->max_period = (esp->max_period + 3)>>2;
+	esp->min_period = (esp->min_period + 3)>>2;
+
+	eregs->esp_cfg1  = esp->config1;
+	switch(esp->erev) {
+	case esp100:
+		/* nothing to do */
+		break;
+	case esp100a:
+		eregs->esp_cfg2 = esp->config2;
+		break;
+	case esp236:
+		/* Slow 236 */
+		eregs->esp_cfg2 = esp->config2;
+		eregs->esp_cfg3 = esp->config3[0];
+		break;
+	case fashme:
+		esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB);
+		/* fallthrough... */
+	case fas236:
+		/* Fast 236 or HME */
+		eregs->esp_cfg2 = esp->config2;
+		for(i=0; i<8; i++) {
+			if(esp->erev == fashme)
+				esp->config3[i] |=
+					(ESP_CONFIG3_FCLOCK | ESP_CONFIG3_BIGID | ESP_CONFIG3_OBPUSH);
+			else
+				esp->config3[i] |= ESP_CONFIG3_FCLK;
+		}
+		eregs->esp_cfg3 = esp->config3[0];
+		if(esp->erev == fashme) {
+			esp->radelay = 80;
+		} else {
+			if(esp->diff)
+				esp->radelay = 0;
+			else
+				esp->radelay = 96;
+		}
+		break;
+	case fas100a:
+		/* Fast 100a */
 		eregs->esp_cfg2 = esp->config2;
-	if(esp->erev == esp236)
+		for(i=0; i<8; i++)
+			esp->config3[i] |= ESP_CONFIG3_FCLOCK;
 		eregs->esp_cfg3 = esp->config3[0];
+		esp->radelay = 32;
+		break;
+	default:
+		panic("esp: what could it be... I wonder...");
+		break;
+	};
+
 	/* Eat any bitrot in the chip */
 	trash = eregs->esp_intrpt;
+	udelay(100);
+}
+
+/* This places the ESP into a known state at boot time. */
+static inline void esp_bootup_reset(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs)
+{
+	volatile unchar trash;
+
+	/* Reset the DMA */
+	esp_reset_dma(esp);
+
+	/* Reset the ESP */
+	esp_reset_esp(esp, eregs);
 
 	/* Reset the SCSI bus, but tell ESP not to generate an irq */
 	eregs->esp_cfg1 |= ESP_CONFIG1_SRRDISAB;
-	eregs->esp_cmd = ESP_CMD_RS;
-	do_pause(200);
+	esp_cmd(esp, eregs, ESP_CMD_RS);
+	udelay(400);
 	eregs->esp_cfg1 = esp->config1;
 
 	/* Eat any bitrot in the chip and we are done... */
@@ -312,34 +652,47 @@
 	struct Linux_SBus_DMA *dma, *dlink;
 	unsigned int fmhz;
 	unchar ccf, bsizes, bsizes_more;
-	int nesps = 0;
-	int esp_node;
+	int nesps = 0, esps_in_use = 0;
+	int esp_node, i;
 
 	espchain = 0;
 	if(!SBus_chain)
 		panic("No SBUS in esp_detect()");
 	for_each_sbus(sbus) {
 		for_each_sbusdev(sbdev_iter, sbus) {
+			struct linux_sbus_device *espdma = 0;
+			int hme = 0;
+
 			/* Is it an esp sbus device? */
 			esp_dev = sbdev_iter;
 			if(strcmp(esp_dev->prom_name, "esp") &&
 			   strcmp(esp_dev->prom_name, "SUNW,esp")) {
-				if(!esp_dev->child ||
-				   strcmp(esp_dev->prom_name, "espdma"))
-					continue; /* nope... */
-				esp_dev = esp_dev->child;
-				if(strcmp(esp_dev->prom_name, "esp") &&
-				   strcmp(esp_dev->prom_name, "SUNW,esp"))
-					continue; /* how can this happen? */
+				if(!strcmp(esp_dev->prom_name, "SUNW,fas")) {
+					hme = 1;
+					espdma = esp_dev;
+				} else {
+					if(!esp_dev->child ||
+					   (strcmp(esp_dev->prom_name, "espdma") &&
+					    strcmp(esp_dev->prom_name, "dma")))
+						continue; /* nope... */
+					espdma = esp_dev;
+					esp_dev = esp_dev->child;
+					if(strcmp(esp_dev->prom_name, "esp") &&
+					   strcmp(esp_dev->prom_name, "SUNW,esp"))
+						continue; /* how can this happen? */
+				}
 			}
 			esp_host = scsi_register(tpnt, sizeof(struct Sparc_ESP));
 			if(!esp_host)
 				panic("Cannot register ESP SCSI host");
+			if(hme)
+				esp_host->max_id = 16;
 			esp = (struct Sparc_ESP *) esp_host->hostdata;
 			if(!esp)
 				panic("No esp in hostdata");
 			esp->ehost = esp_host;
 			esp->edev = esp_dev;
+			esp->esp_id = nesps++;
 			/* Put into the chain of esp chips detected */
 			if(espchain) {
 				elink = espchain;
@@ -361,19 +714,31 @@
 			prom_getstring(esp_node, "name", esp->prom_name,
 				       sizeof(esp->prom_name));
 			esp->prom_node = esp_node;
-			for_each_dvma(dlink) {
-				if(ESP_IS_MY_DVMA(esp, dlink) && !dlink->allocated)
-					break;
+			if(espdma) {
+				for_each_dvma(dlink) {
+					if(dlink->SBus_dev == espdma)
+						break;
+				}
+			} else {
+				for_each_dvma(dlink) {
+					if(ESP_IS_MY_DVMA(esp, dlink) &&
+					   !dlink->allocated)
+						break;
+				}
 			}
 #undef ESP_IS_MY_DVMA
-			/* If we don't know how to handle the dvma, do not use this device */
+			/* If we don't know how to handle the dvma,
+			 * do not use this device.
+			 */
 			if(!dlink){
-				printk ("Cannot find dvma for ESP SCSI\n");
+				printk ("Cannot find dvma for ESP%d's SCSI\n",
+					esp->esp_id);
 				scsi_unregister (esp_host);
 				continue;
 			}
 			if (dlink->allocated){
-				printk ("esp: can't use my espdma\n");
+				printk ("esp%d: can't use my espdma\n",
+					esp->esp_id);
 				scsi_unregister (esp_host);
 				continue;
 			}
@@ -383,11 +748,23 @@
 			esp->dregs = dregs = dma->regs;
 
 			/* Map in the ESP registers from I/O space */
-			prom_apply_sbus_ranges(esp->edev->reg_addrs, 1);
-			esp->eregs = eregs = (struct Sparc_ESP_regs *)
+			if(!hme) {
+				prom_apply_sbus_ranges(esp->edev->my_bus, 
+						       esp->edev->reg_addrs, 1);
+
+				esp->eregs = eregs = (struct Sparc_ESP_regs *)
 				sparc_alloc_io(esp->edev->reg_addrs[0].phys_addr, 0,
 					       PAGE_SIZE, "ESP Registers",
 					       esp->edev->reg_addrs[0].which_io, 0x0);
+			} else {
+				/* On HME, two reg sets exist, first is DVMA,
+				 * second is ESP registers.
+				 */
+				esp->eregs = eregs = (struct Sparc_ESP_regs *)
+				sparc_alloc_io(esp->edev->reg_addrs[1].phys_addr, 0,
+					       PAGE_SIZE, "ESP Registers",
+					       esp->edev->reg_addrs[1].which_io, 0x0);
+			}
 			if(!eregs)
 				panic("ESP registers unmappable");
 			esp->esp_command =
@@ -400,7 +777,6 @@
 			esp->ehost->io_port = (unsigned int) esp->eregs;
 			esp->ehost->n_io_port = (unsigned char)
 				esp->edev->reg_addrs[0].reg_size;
-			/* XXX The following may be different on sun4ms XXX */
 			esp->ehost->irq = esp->irq = esp->edev->irqs[0].pri;
 
 			/* Allocate the irq only if necessary */
@@ -409,41 +785,102 @@
 					goto esp_irq_acquired; /* BASIC rulez */
 				}
 			}
-			/* XXX We have shared interrupts per level now, maybe
-			 * XXX use them, maybe not...
-			 */
-			if(request_irq(esp->ehost->irq, esp_intr, SA_INTERRUPT,
+			if(request_irq(esp->ehost->irq, esp_intr, SA_SHIRQ,
 				       "Sparc ESP SCSI", NULL))
 				panic("Cannot acquire ESP irq line");
 esp_irq_acquired:
-			printk("esp%d: IRQ %d ", nesps, esp->ehost->irq);
+			printk("esp%d: IRQ %d ", esp->esp_id, esp->ehost->irq);
+
 			/* Figure out our scsi ID on the bus */
 			esp->scsi_id = prom_getintdefault(esp->prom_node,
-							  "initiator-id", -1);
+							  "initiator-id",
+							  -1);
 			if(esp->scsi_id == -1)
 				esp->scsi_id = prom_getintdefault(esp->prom_node,
-								  "scsi-initiator-id", -1);
+								  "scsi-initiator-id",
+								  -1);
 			if(esp->scsi_id == -1)
 				esp->scsi_id =
 					prom_getintdefault(esp->edev->my_bus->prom_node,
-							   "scsi-initiator-id", 7);
+							   "scsi-initiator-id",
+							   7);
 			esp->ehost->this_id = esp->scsi_id;
 			esp->scsi_id_mask = (1 << esp->scsi_id);
-			/* Check for differential bus */
-			esp->diff = prom_getintdefault(esp->prom_node, "differential", -1);
-			esp->diff = (esp->diff == -1) ? 0 : 1;
-			/* Check out the clock properties of the chip */
-			fmhz = prom_getintdefault(esp->prom_node, "clock-frequency", -1);
+
+			/* Check for differential SCSI-bus */
+			esp->diff = prom_getbool(esp->prom_node, "differential");
+			if(esp->diff)
+				printk("Differential ");
+
+			/* Check out the clock properties of the chip. */
+
+			/* This is getting messy but it has to be done
+			 * correctly or else you get weird behavior all
+			 * over the place.  We are trying to basically
+			 * figure out three pieces of information.
+			 *
+			 * a) Clock Conversion Factor
+			 *
+			 *    This is a representation of the input
+			 *    crystal clock frequency going into the
+			 *    ESP on this machine.  Any operation whose
+			 *    timing is longer than 400ns depends on this
+			 *    value being correct.  For example, you'll
+			 *    get blips for arbitration/selection during
+			 *    high load or with multiple targets if this
+			 *    is not set correctly.
+			 *
+			 * b) Selection Time-Out
+			 *
+			 *    The ESP isn't very bright and will arbitrate
+			 *    for the bus and try to select a target
+			 *    forever if you let it.  This value tells
+			 *    the ESP when it has taken too long to
+			 *    negotiate and that it should interrupt
+			 *    the CPU so we can see what happened.
+			 *    The value is computed as follows (from
+			 *    NCR/Symbios chip docs).
+			 *
+			 *          (Time Out Period) *  (Input Clock)
+			 *    STO = ----------------------------------
+			 *          (8192) * (Clock Conversion Factor)
+			 *
+			 *    You usually want the time out period to be
+			 *    around 250ms, I think we'll set it a little
+			 *    bit higher to account for fully loaded SCSI
+			 *    bus's and slow devices that don't respond so
+			 *    quickly to selection attempts. (yeah, I know
+			 *    this is out of spec. but there is a lot of
+			 *    buggy pieces of firmware out there so bite me)
+			 *
+			 * c) Imperical constants for synchronous offset
+			 *    and transfer period register values
+			 *
+			 *    This entails the smallest and largest sync
+			 *    period we could ever handle on this ESP.
+			 */
+
+			fmhz = prom_getintdefault(esp->prom_node,
+						  "clock-frequency",
+						  -1);
 			if(fmhz==-1)
 				fmhz = prom_getintdefault(esp->edev->my_bus->prom_node,
-							  "clock-frequency", -1);
-			if(fmhz <= (5000))
+							  "clock-frequency",
+							  -1);
+			if(fmhz <= (5000000))
 				ccf = 0;
 			else
-				ccf = (((5000 - 1) + (fmhz))/(5000));
+				ccf = (((5000000 - 1) + (fmhz))/(5000000));
 			if(!ccf || ccf > 8) {
+				/* If we can't find anything reasonable,
+				 * just assume 20MHZ.  This is the clock
+				 * frequency of the older sun4c's where I've
+				 * been unable to find the clock-frequency
+				 * PROM property.  All other machines provide
+				 * useful values it seems.
+				 */
 				ccf = ESP_CCF_F4;
-				fmhz = (5000 * 4);
+				fmhz = (20000000);
 			}
 			if(ccf==(ESP_CCF_F7+1))
 				esp->cfact = ESP_CCF_F0;
@@ -452,31 +889,38 @@
 			else
 				esp->cfact = ccf;
 			esp->cfreq = fmhz;
-			esp->ccycle = ((1000000000) / ((fmhz)/1000));
-			esp->ctick = ((7682 * esp->cfact * esp->ccycle)/1000);
-			esp->sync_defp = ((7682 + esp->ctick - 1) / esp->ctick);
-
-			/* XXX HACK HACK HACK XXX */
-			if (esp->sync_defp < 153)
-				esp->sync_defp = 153;
-
-			printk("SCSI ID %d  Clock %d MHz Period %2x ", esp->scsi_id,
-			       (fmhz / 1000), esp->sync_defp);
+			esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz);
+			esp->ctick = ESP_TICK(ccf, esp->ccycle);
+			esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf);
+			esp->sync_defp = SYNC_DEFP_SLOW;
+			printk("SCSI ID %d  Clock %d MHz CCF=%d Time-Out %d ",
+			       esp->scsi_id, (fmhz / 1000000),
+			       ccf, (int) esp->neg_defp);
 
-			/* Find the burst sizes this dma supports. */
+			/* Find the burst sizes this dma/sbus/esp supports. */
 			bsizes = prom_getintdefault(esp->prom_node, "burst-sizes", 0xff);
+			bsizes &= 0xff;
+			if(espdma) {
+				bsizes_more = prom_getintdefault(
+						  espdma->prom_node,
+						  "burst-sizes", 0xff);
+				if(bsizes_more != 0xff)
+					bsizes &= bsizes_more;
+			}
 			bsizes_more = prom_getintdefault(esp->edev->my_bus->prom_node,
 							 "burst-sizes", 0xff);
-			if(bsizes_more != 0xff) bsizes &= bsizes_more;
+			if(bsizes_more != 0xff)
+				bsizes &= bsizes_more;
+
 			if(bsizes == 0xff || (bsizes & DMA_BURST16)==0 ||
 			   (bsizes & DMA_BURST32)==0)
 				bsizes = (DMA_BURST32 - 1);
+
 			esp->bursts = bsizes;
 
 			/* Probe the revision of this esp */
 			esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7));
 			esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
-			esp->config3[0] = ESP_CONFIG3_TENB;
 			eregs->esp_cfg2 = esp->config2;
 			if((eregs->esp_cfg2 & ~(ESP_CONFIG2_MAGIC)) !=
 			   (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
@@ -495,11 +939,11 @@
 					for(target=0; target<8; target++)
 						esp->config3[target] = 0;
 					eregs->esp_cfg3 = 0;
-					if(esp->cfact > ESP_CCF_F5) {
+					if(ccf > ESP_CCF_F5) {
 						printk("NCR53C9XF(espfast) detected\n");
 						esp->erev = fast;
-						esp->config2 |= ESP_CONFIG2_FENAB;
-						eregs->esp_cfg2 = esp->config2;
+						eregs->esp_cfg2 = esp->config2 = 0;
+						esp->sync_defp = SYNC_DEFP_FAST;
 					} else {
 						printk("NCR53C9x(esp236) detected\n");
 						esp->erev = esp236;
@@ -513,20 +957,34 @@
 			esp->disconnected_SC = 0;
 			esp->issue_SC = 0;
 
+			/* Clear the state machines. */
+			esp->targets_present = 0;
+			esp->resetting_bus = 0;
+			esp->snip = 0;
+			esp->targets_present = 0;
+			for(i = 0; i < 32; i++)
+				esp->espcmdlog[i] = 0;
+			esp->espcmdent = 0;
+			for(i = 0; i < 16; i++) {
+				esp->cur_msgout[i] = 0;
+				esp->cur_msgin[i] = 0;
+			}
+			esp->prevmsgout = esp->prevmsgin = 0;
+			esp->msgout_len = esp->msgin_len = 0;
+
 			/* Reset the thing before we try anything... */
 			esp_bootup_reset(esp, eregs);
 
-			nesps++;
-#ifdef THREADED_ESP_DRIVER
-			kernel_thread(esp_kernel_thread, esp, 0);
-#endif
+			esps_in_use++;
 		} /* for each sbusdev */
 	} /* for each sbus */
-	return nesps;
+	printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps,
+	       esps_in_use);
+	esps_running = esps_in_use;
+	return esps_in_use;
 }
 
-/*
- * The info function will return whatever useful
+/* The info function will return whatever useful
  * information the developer sees fit.  If not provided, then
  * the name field will be used instead.
  */
@@ -542,10 +1000,10 @@
 		return "Sparc ESP100A (NCR53C90A)";
 	case esp236:
 		return "Sparc ESP236";
-	case fast:
-		return "Sparc ESP-FAST (236 or 100A)";
 	case fas236:
 		return "Sparc ESP236-FAST";
+	case fashme:
+		return "Sparc ESP366-HME";
 	case fas100a:
 		return "Sparc ESP100A-FAST";
 	default:
@@ -553,142 +1011,710 @@
 	};
 }
 
-/* Execute a SCSI command when the bus is free.   All callers
- * turn off all interrupts, so we don't need to explicitly do
- * it here.
- */
-static inline void esp_exec_cmd(struct Sparc_ESP *esp)
+/* From Wolfgang Stanglmeier's NCR scsi driver. */
+struct info_str
 {
-	struct sparc_dma_registers *dregs;
-	struct Sparc_ESP_regs *eregs;
-	Scsi_Cmnd *SCptr;
-	int i;
-
-	eregs = esp->eregs;
-	dregs = esp->dregs;
-
-	/* Grab first member of the issue queue. */
-	SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC);
-	if(!SCptr)
-		goto bad;
-	SCptr->SCp.phase = in_selection;
-
-	/* NCR docs say:
-	 * 1) Load select/reselect Bus ID register with target ID
-	 * 2) Load select/reselect Timeout Reg with desired value
-	 * 3) Load Synchronous offset register with zero (for
-	 *    asynchronous transfers).
-	 * 4) Load Synchronous Transfer Period register (if
-	 *    synchronous)
-	 * 5) Load FIFO with 6, 10, or 12 byte SCSI command
-	 * 6) Issue SELECTION_WITHOUT_ATTENTION command
-	 *
-	 * They also mention that a DMA NOP command must be issued
-	 * to the SCSI chip under many circumstances, plus it's
-	 * also a good idea to flush out the fifo just in case.
-	 */
-
-	/* Load zeros into COUNTER via 2 DMA NOP chip commands
-	 * due to flaky implementations of the 53C9x which don't
-	 * get the idea the first time around.
-	 */
-	dregs->cond_reg = (DMA_INT_ENAB | DMA_FIFO_INV);
+	char *buffer;
+	int length;
+	int offset;
+	int pos;
+};
 
-	eregs->esp_tclow = 0;
-	eregs->esp_tcmed = 0;
-	eregs->esp_cmd   = (ESP_CMD_NULL | ESP_CMD_DMA);
+static void copy_mem_info(struct info_str *info, char *data, int len)
+{
+	if (info->pos + len > info->length)
+		len = info->length - info->pos;
 
-	/* Flush the fifo of excess garbage. */
-	eregs->esp_cmd   = ESP_CMD_FLUSH;
+	if (info->pos + len < info->offset) {
+		info->pos += len;
+		return;
+	}
+	if (info->pos < info->offset) {
+		data += (info->offset - info->pos);
+		len  -= (info->offset - info->pos);
+	}
 
-	/* Load bus-id and timeout values. */
-	eregs->esp_busid = (SCptr->target & 7);
-	eregs->esp_timeo = esp->sync_defp;
+	if (len > 0) {
+		memcpy(info->buffer + info->pos, data, len);
+		info->pos += len;
+	}
+}
 
-	eregs->esp_soff  = 0; /* This means async transfer... */
-	eregs->esp_stp   = 0;
+static int copy_info(struct info_str *info, char *fmt, ...)
+{
+	va_list args;
+	char buf[81];
+	int len;
+
+	va_start(args, fmt);
+	len = vsprintf(buf, fmt, args);
+	va_end(args);
 
-	/* Load FIFO with the actual SCSI command. */
-	for(i=0; i < SCptr->cmd_len; i++)
-		eregs->esp_fdata = SCptr->cmnd[i];
+	copy_mem_info(info, buf, len);
+	return len;
+}
 
-	/* Make sure the dvma forwards the ESP interrupt. */
-	dregs->cond_reg = DMA_INT_ENAB;
+static int esp_host_info(struct Sparc_ESP *esp, char *ptr, off_t offset, int len)
+{
+	struct info_str info;
+	int i;
 
-	/* Tell ESP to SELECT without asserting ATN. */
-	eregs->esp_cmd = ESP_CMD_SEL;
-	return;
+	info.buffer	= ptr;
+	info.length	= len;
+	info.offset	= offset;
+	info.pos	= 0;
+
+	copy_info(&info, "Sparc ESP Host Adapter:\n");
+	copy_info(&info, "\tPROM node\t\t%08lx\n", (unsigned long) esp->prom_node);
+	copy_info(&info, "\tPROM name\t\t%s\n", esp->prom_name);
+	copy_info(&info, "\tESP Model\t\t");
+	switch(esp->erev) {
+	case esp100:
+		copy_info(&info, "ESP100\n");
+		break;
+	case esp100a:
+		copy_info(&info, "ESP100A\n");
+		break;
+	case esp236:
+		copy_info(&info, "ESP236\n");
+		break;
+	case fas236:
+		copy_info(&info, "FAS236\n");
+		break;
+	case fas100a:
+		copy_info(&info, "FAS100A\n");
+		break;
+	case fast:
+		copy_info(&info, "FAST\n");
+		break;
+	case fashme:
+		copy_info(&info, "Happy Meal FAS\n");
+		break;
+	case espunknown:
+	default:
+		copy_info(&info, "Unknown!\n");
+		break;
+	};
+	copy_info(&info, "\tDMA Revision\t\t");
+	switch(esp->dma->revision) {
+	case dvmarev0:
+		copy_info(&info, "Rev 0\n");
+		break;
+	case dvmaesc1:
+		copy_info(&info, "ESC Rev 1\n");
+		break;
+	case dvmarev1:
+		copy_info(&info, "Rev 1\n");
+		break;
+	case dvmarev2:
+		copy_info(&info, "Rev 2\n");
+		break;
+	case dvmarev3:
+		copy_info(&info, "Rev 3\n");
+		break;
+	case dvmarevplus:
+		copy_info(&info, "Rev 1+\n");
+		break;
+	case dvmahme:
+		copy_info(&info, "Rev HME/FAS\n");
+		break;
+	default:
+		copy_info(&info, "Unknown!\n");
+		break;
+	};
+	copy_info(&info, "\tLive Targets\t\t[ ");
+	for(i = 0; i < 15; i++) {
+		if(esp->targets_present & (1 << i))
+			copy_info(&info, "%d ", i);
+	}
+	copy_info(&info, "]\n\n");
+	
+	/* Now describe the state of each existing target. */
+	copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\tWide\n");
+	for(i = 0; i < 15; i++) {
+		if(esp->targets_present & (1 << i)) {
+			Scsi_Device *SDptr = scsi_devices;
+
+			while((SDptr->host != esp->ehost) &&
+			      (SDptr->id != i) &&
+			      (SDptr->next))
+				SDptr = SDptr->next;
+
+			copy_info(&info, "%d\t\t", i);
+			copy_info(&info, "%08lx\t", esp->config3[i]);
+			copy_info(&info, "[%02lx,%02lx]\t\t\t", SDptr->sync_max_offset,
+				  SDptr->sync_min_period);
+			copy_info(&info, "%s\t\t", SDptr->disconnect ? "yes" : "no");
+			copy_info(&info, "%s\n",
+				  (esp->config3[i] & ESP_CONFIG3_EWIDE) ? "yes" : "no");
+		}
+	}
 
-bad:
-	panic("esp: daaarrrkk starrr crashesss....");
+	return info.pos > info.offset? info.pos - info.offset : 0;
 }
 
-/* Queue a SCSI command delivered from the mid-level Linux SCSI code. */
-int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+/* ESP proc filesystem code. */
+int esp_proc_info(char *buffer, char **start, off_t offset, int length,
+		  int hostno, int inout)
 {
 	struct Sparc_ESP *esp;
-	unsigned long flags;
-
-	save_flags(flags); cli();
-
-	/* Set up func ptr and initial driver cmd-phase. */
-	SCpnt->scsi_done = done;
-	SCpnt->SCp.phase = not_issued;
 
-	esp = (struct Sparc_ESP *) SCpnt->host->hostdata;
+	if(inout)
+		return -EINVAL; /* not yet */
 
-	/* We use the scratch area. */
-	if(!SCpnt->use_sg) {
-		SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
-		SCpnt->SCp.buffer           =
-			(struct scatterlist *) SCpnt->request_buffer;
-		SCpnt->SCp.buffers_residual = 0;
-		SCpnt->SCp.Status           = CHECK_CONDITION;
-		SCpnt->SCp.Message          = 0;
-		SCpnt->SCp.have_data_in     = 0;
-		SCpnt->SCp.sent_command     = 0;
-		SCpnt->SCp.ptr = mmu_get_scsi_one((char *)SCpnt->SCp.buffer,
-						     SCpnt->SCp.this_residual,
-						     esp->edev->my_bus);
-	} else {
-#ifdef DEBUG_ESP_SG
-		printk("esp: sglist at %p with %d buffers\n",
-		       SCpnt->buffer, SCpnt->use_sg);
-#endif
-		SCpnt->SCp.buffer           = (struct scatterlist *) SCpnt->buffer;
-		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
-		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
-		mmu_get_scsi_sgl((struct mmu_sglist *) SCpnt->SCp.buffer,
-				 SCpnt->SCp.buffers_residual,
-				 esp->edev->my_bus);
-		SCpnt->SCp.ptr              = (char *) SCpnt->SCp.buffer->alt_address;
+	for_each_esp(esp) {
+		if(esp->ehost->host_no == hostno)
+			break;
 	}
+	if(!esp)
+		return -EINVAL;
 
-	/* Place into our queue. */
-	append_SC(&esp->issue_SC, SCpnt);
-
-	/* Run it now if we can */
-	if(!esp->current_SC)
-		esp_exec_cmd(esp);
+	if(start)
+		*start = buffer;
 
-	restore_flags(flags);
-	return 0;
+	return esp_host_info(esp, buffer, offset, length);
 }
 
-/* Only queuing supported in this ESP driver. */
-int esp_command(Scsi_Cmnd *SCpnt)
+/* Some rules:
+ *
+ *   1) Never ever panic while something is live on the bus.
+ *      If there is to be any chance of syncing the disks this
+ *      rule is to be obeyed.
+ *
+ *   2) Any target that causes a foul condition will no longer
+ *      have synchronous transfers done to it, no questions
+ *      asked.
+ *
+ *   3) Keep register accesses to a minimum.  Think about some
+ *      day when we have Xbus machines this is running on and
+ *      the ESP chip is on the other end of the machine on a
+ *      different board from the cpu where this is running.
+ */
+
+/* Fire off a command.  We assume the bus is free and that the only
+ * case where we could see an interrupt is where we have disconnected
+ * commands active and they are trying to reselect us.
+ */
+static inline void esp_check_cmd(struct Sparc_ESP *esp, Scsi_Cmnd *sp)
 {
-	ESPLOG(("esp: esp_command() called...\n"));
+	switch(sp->cmd_len) {
+	case 6:
+	case 10:
+	case 12:
+		esp->esp_slowcmd = 0;
+		break;
+
+	default:
+		esp->esp_slowcmd = 1;
+		esp->esp_scmdleft = sp->cmd_len;
+		esp->esp_scmdp = &sp->cmnd[0];
+		break;
+	};
+}
+
+static inline void build_sync_nego_msg(struct Sparc_ESP *esp, int period, int offset)
+{
+	esp->cur_msgout[0] = EXTENDED_MESSAGE;
+	esp->cur_msgout[1] = 3;
+	esp->cur_msgout[2] = EXTENDED_SDTR;
+	esp->cur_msgout[3] = period;
+	esp->cur_msgout[4] = offset;
+	esp->msgout_len = 5;
+}
+
+/* SIZE is in bits, currently HME only supports 16 bit wide transfers. */
+static inline void build_wide_nego_msg(struct Sparc_ESP *esp, int size)
+{
+	esp->cur_msgout[0] = EXTENDED_MESSAGE;
+	esp->cur_msgout[1] = 2;
+	esp->cur_msgout[2] = EXTENDED_WDTR;
+	switch(size) {
+	case 32:
+		esp->cur_msgout[3] = 2;
+		break;
+	case 16:
+		esp->cur_msgout[3] = 1;
+		break;
+	case 8:
+	default:
+		esp->cur_msgout[3] = 0;
+		break;
+	};
+
+	esp->msgout_len = 4;
+}
+
+static inline void esp_exec_cmd(struct Sparc_ESP *esp)
+{
+	struct sparc_dma_registers *dregs = esp->dregs;
+	struct Sparc_ESP_regs *eregs = esp->eregs;
+	Scsi_Cmnd *SCptr;
+	Scsi_Device *SDptr;
+	volatile unchar *cmdp = esp->esp_command;
+	unsigned char the_esp_command;
+	int lun, target;
+	int i;
+
+	/* Hold off if we've been reselected. */
+	if(esp->disconnected_SC && DMA_IRQ_P(dregs)) return;
+
+	/* Grab first member of the issue queue. */
+	SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC);
+
+	/* Safe to panic here because current_SC is null. */
+	if(!SCptr) panic("esp: esp_exec_cmd and issue queue is NULL");
+
+	SDptr = SCptr->device;
+	lun = SCptr->lun;
+	target = SCptr->target;
+
+	esp->snip = 0;
+	esp->msgout_len = 0;
+
+	/* Send it out whole, or piece by piece?   The ESP
+	 * only knows how to automatically send out 6, 10,
+	 * and 12 byte commands.  I used to think that the
+	 * Linux SCSI code would never throw anything other
+	 * than that to us, but then again there is the
+	 * SCSI generic driver which can send us anything.
+	 */
+	esp_check_cmd(esp, SCptr);
+
+	/* If arbitration/selection is successful, the ESP will leave
+	 * ATN asserted, causing the target to go into message out
+	 * phase.  The ESP will feed the target the identify and then
+	 * the target can only legally go to one of command,
+	 * datain/out, status, or message in phase, or stay in message
+	 * out phase (should we be trying to send a sync negotiation
+	 * message after the identify).  It is not allowed to drop
+	 * BSY, but some buggy targets do and we check for this
+	 * condition in the selection complete code.  Most of the time
+	 * we'll make the command bytes available to the ESP and it
+	 * will not interrupt us until it finishes command phase, we
+	 * cannot do this for command sizes the ESP does not
+	 * understand and in this case we'll get interrupted right
+	 * when the target goes into command phase.
+	 *
+	 * It is absolutely _illegal_ in the presence of SCSI-2 devices
+	 * to use the ESP select w/o ATN command.  When SCSI-2 devices are
+	 * present on the bus we _must_ always go straight to message out
+	 * phase with an identify message for the target.  Being that
+	 * selection attempts in SCSI-1 w/o ATN was an option, doing SCSI-2
+	 * selections should not confuse SCSI-1 we hope.
+	 */
+
+	if(SDptr->sync) {
+		/* this targets sync is known */
+do_sync_known:
+		if(SDptr->disconnect)
+			*cmdp++ = IDENTIFY(1, lun);
+		else
+			*cmdp++ = IDENTIFY(0, lun);
+
+		if(esp->esp_slowcmd) {
+			the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA);
+			esp_advance_phase(SCptr, in_slct_stop);
+		} else {
+			the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
+			esp_advance_phase(SCptr, in_slct_norm);
+		}
+	} else if(!(esp->targets_present & (1<<target)) || !(SDptr->disconnect)) {
+		/* After the bootup SCSI code sends both the
+		 * TEST_UNIT_READY and INQUIRY commands we want
+		 * to at least attempt allowing the device to
+		 * disconnect.
+		 */
+		ESPMISC(("esp: Selecting device for first time. target=%d "
+			 "lun=%d\n", target, SCptr->lun));
+		if(!SDptr->borken && !SDptr->disconnect)
+			SDptr->disconnect = 1;
+
+		*cmdp++ = IDENTIFY(0, lun);
+		esp->prevmsgout = NOP;
+		esp_advance_phase(SCptr, in_slct_norm);
+		the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
+
+		/* Take no chances... */
+		SDptr->sync_max_offset = 0;
+		SDptr->sync_min_period = 0;
+	} else {
+		int toshiba_cdrom_hwbug_wkaround = 0;
+
+		/* Never allow disconnects or synchronous transfers on
+		 * SparcStation1 and SparcStation1+.  Allowing those
+		 * to be enabled seems to lockup the machine completely.
+		 */
+		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)
+				SDptr->disconnect = 1;
+			else
+				SDptr->disconnect = 0;
+			SDptr->sync_max_offset = 0;
+			SDptr->sync_min_period = 0;
+			SDptr->sync = 1;
+			esp->snip = 0;
+			goto do_sync_known;
+		}
+
+		/* We've talked to this guy before,
+		 * but never negotiated.. lets try,
+		 * need to attempt WIDE first, before
+		 * sync nego, as per SCSI 2 standard.
+		 */
+		if(esp->erev == fashme && !SDptr->wide) {
+			if(!SDptr->borken &&
+			   (SDptr->type != TYPE_ROM ||
+			    strncmp(SDptr->vendor, "TOSHIBA", 7))) {
+				build_wide_nego_msg(esp, 16);
+				esp->config3[SCptr->target] |= ESP_CONFIG3_EWIDE;
+				SDptr->wide = 1;
+				esp->wnip = 1;
+				goto after_nego_msg_built;
+			} else {
+				SDptr->wide = 1;
+				/* Fall through and try sync. */
+			}
+		}
+
+		if(!SDptr->borken) {
+			if((SDptr->type == TYPE_ROM) &&
+			   (!strncmp(SDptr->vendor, "TOSHIBA", 7))) {
+				/* Nice try sucker... */
+				printk(KERN_INFO "esp%d: Disabling sync for buggy "
+				       "Toshiba CDROM.\n", esp->esp_id);
+				toshiba_cdrom_hwbug_wkaround = 1;
+				build_sync_nego_msg(esp, 0, 0);
+			} else {
+				build_sync_nego_msg(esp, esp->sync_defp, 15);
+			}
+		} else {
+			build_sync_nego_msg(esp, 0, 0);
+		}
+		SDptr->sync = 1;
+		esp->snip = 1;
+
+after_nego_msg_built:
+		/* A fix for broken SCSI1 targets, when they disconnect
+		 * they lock up the bus and confuse ESP.  So disallow
+		 * disconnects for SCSI1 targets for now until we
+		 * find a better fix.
+		 *
+		 * Addendum: This is funny, I figured out what was going
+		 *           on.  The blotzed SCSI1 target would disconnect,
+		 *           one of the other SCSI2 targets or both would be
+		 *           disconnected as well.  The SCSI1 target would
+		 *           stay disconnected long enough that we start
+		 *           up a command on one of the SCSI2 targets.  As
+		 *           the ESP is arbitrating for the bus the SCSI1
+		 *           target begins to arbitrate as well to reselect
+		 *           the ESP.  The SCSI1 target refuses to drop it's
+		 *           ID bit on the data bus even though the ESP is
+		 *           at ID 7 and is the obvious winner for any
+		 *           arbitration.  The ESP is a poor sport and refuses
+		 *           to lose arbitration, it will continue indefinately
+		 *           trying to arbitrate for the bus and can only be
+		 *           stopped via a chip reset or SCSI bus reset.
+		 *           Therefore _no_ disconnects for SCSI1 targets
+		 *           thank you very much. ;-)
+		 */
+		if(((SDptr->scsi_level < 3) && (SDptr->type != TYPE_TAPE)) ||
+#if 1 /* Until I find out why HME barfs with disconnects enabled... */
+		   toshiba_cdrom_hwbug_wkaround || SDptr->borken || esp->erev == fashme) {
+#else
+		   toshiba_cdrom_hwbug_wkaround || SDptr->borken) {
+#endif
+			printk(KERN_INFO "esp%d: Disabling DISCONNECT for target %d "
+			       "lun %d\n", esp->esp_id, SCptr->target, SCptr->lun);
+			SDptr->disconnect = 0;
+			*cmdp++ = IDENTIFY(0, lun);
+		} else {
+			*cmdp++ = IDENTIFY(1, lun);
+		}
+
+		/* ESP fifo is only so big...
+		 * Make this look like a slow command.
+		 */
+		esp->esp_slowcmd = 1;
+		esp->esp_scmdleft = SCptr->cmd_len;
+		esp->esp_scmdp = &SCptr->cmnd[0];
+
+		the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA);
+		esp_advance_phase(SCptr, in_slct_msg);
+	}
+
+	if(!esp->esp_slowcmd)
+		for(i = 0; i < SCptr->cmd_len; i++)
+			*cmdp++ = SCptr->cmnd[i];
+
+	/* HME sucks... */
+	if(esp->erev == fashme)
+		eregs->esp_busid = (target & 0xf) |
+			(ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT);
+	else
+		eregs->esp_busid = (target & 7);
+	eregs->esp_soff = SDptr->sync_max_offset;
+	eregs->esp_stp  = SDptr->sync_min_period;
+	if(esp->erev > esp100a)
+		eregs->esp_cfg3 = esp->config3[target];
+
+	i = (cmdp - esp->esp_command);
+
+	if(esp->erev == fashme) {
+		unsigned long tmp;
+
+		esp_cmd(esp, eregs, ESP_CMD_FLUSH); /* Grrr! */
+
+		/* Set up the DMA and HME counters */
+		eregs->esp_tclow = i;
+		eregs->esp_tcmed = 0;
+		eregs->fas_rlo = 0;
+		eregs->fas_rhi = 0;
+		esp_cmd(esp, eregs, the_esp_command);
+
+		/* Talk about touchy hardware... */
+		tmp = dregs->cond_reg;
+		tmp |= (DMA_SCSI_DISAB | DMA_ENABLE);
+		tmp &= ~(DMA_ST_WRITE);
+		dregs->cnt = 16;
+		dregs->st_addr = esp->esp_command;
+		dregs->cond_reg = tmp;
+	} else {
+		/* Set up the DMA and ESP counters */
+		eregs->esp_tclow = i;
+		eregs->esp_tcmed = 0;
+		dregs->cond_reg = ((dregs->cond_reg & ~(DMA_ST_WRITE)) | DMA_ENABLE);
+		if(esp->dma->revision == dvmaesc1) {
+			if(i) /* Workaround ESC gate array SBUS rerun bug. */
+				dregs->cnt = (PAGE_SIZE);
+		}
+		dregs->st_addr = esp->esp_command;
+
+		/* Tell ESP to "go". */
+		esp_cmd(esp, eregs, the_esp_command);
+	}
+}
+
+/* Queue a SCSI command delivered from the mid-level Linux SCSI code. */
+int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+	struct Sparc_ESP *esp;
+	struct sparc_dma_registers *dregs;
+	unsigned long flags;
+	int don;
+
+	save_flags(flags); cli();
+
+	/* Set up func ptr and initial driver cmd-phase. */
+	SCpnt->scsi_done = done;
+	SCpnt->SCp.phase = not_issued;
+
+	esp = (struct Sparc_ESP *) SCpnt->host->hostdata;
+	dregs = esp->dregs;
+
+	don = (dregs->cond_reg & DMA_INT_ENAB);
+	if(don)
+		DMA_INTSOFF(dregs);
+
+	/* We use the scratch area. */
+	ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->target, SCpnt->lun));
+	ESPDISC(("N<%02x,%02x>", SCpnt->target, SCpnt->lun));
+	if(!SCpnt->use_sg) {
+		ESPQUEUE(("!use_sg\n"));
+		SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
+		SCpnt->SCp.buffer           =
+			(struct scatterlist *) SCpnt->request_buffer;
+		SCpnt->SCp.buffers_residual = 0;
+		/* Sneaky. */
+		SCpnt->SCp.have_data_in = (int) SCpnt->SCp.ptr =
+			mmu_get_scsi_one((char *)SCpnt->SCp.buffer,
+					 SCpnt->SCp.this_residual,
+					 esp->edev->my_bus);
+	} else {
+		ESPQUEUE(("use_sg "));
+#ifdef DEBUG_ESP_SG
+		printk("esp%d: sglist at %p with %d buffers\n",
+		       esp->esp_id, SCpnt->buffer, SCpnt->use_sg);
+#endif
+		SCpnt->SCp.buffer           = (struct scatterlist *) SCpnt->buffer;
+		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
+		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
+		mmu_get_scsi_sgl((struct mmu_sglist *) SCpnt->SCp.buffer,
+				 SCpnt->SCp.buffers_residual,
+				 esp->edev->my_bus);
+		SCpnt->SCp.ptr              = (char *) SCpnt->SCp.buffer->dvma_address;
+	}
+	SCpnt->SCp.Status           = CHECK_CONDITION;
+	SCpnt->SCp.Message          = 0xff;
+	SCpnt->SCp.sent_command     = 0;
+
+	/* Place into our queue. */
+	if(SCpnt->cmnd[0] == REQUEST_SENSE) {
+		ESPQUEUE(("RQSENSE\n"));
+		prepend_SC(&esp->issue_SC, SCpnt);
+	} else {
+		ESPQUEUE(("\n"));
+		append_SC(&esp->issue_SC, SCpnt);
+	}
+
+	/* Run it now if we can. */
+	if(!esp->current_SC && !esp->resetting_bus)
+		esp_exec_cmd(esp);
+
+	if(don)
+		DMA_INTSON(dregs);
+	restore_flags(flags);
+	return 0;
+}
+
+/* Only queuing supported in this ESP driver. */
+int esp_command(Scsi_Cmnd *SCpnt)
+{
+	struct Sparc_ESP *esp = (struct Sparc_ESP *) SCpnt->host->hostdata;
+
+	ESPLOG(("esp%d: esp_command() called...\n", esp->esp_id));
 	return -1;
 }
 
-/* Abort a command.  Those that are on the bus force a SCSI bus
- * reset.
- */
-int esp_abort(Scsi_Cmnd *SCpnt)
+/* Dump driver state. */
+static inline void esp_dump_cmd(Scsi_Cmnd *SCptr)
+{
+	ESPLOG(("[tgt<%02x> lun<%02x> "
+		"pphase<%s> cphase<%s>]",
+		SCptr->target, SCptr->lun,
+		phase_string(SCptr->SCp.sent_command),
+		phase_string(SCptr->SCp.phase)));
+}
+
+static inline void esp_dump_state(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+				  struct sparc_dma_registers *dregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+#ifdef DEBUG_ESP_CMDS
+	int i;
+#endif
+
+	ESPLOG(("esp%d: dumping state\n", esp->esp_id));
+	ESPLOG(("esp%d: dma -- cond_reg<%08lx> addr<%p>\n",
+		esp->esp_id, dregs->cond_reg, dregs->st_addr));
+	ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
+		esp->esp_id, esp->sreg, esp->seqreg, esp->ireg));
+	ESPLOG(("esp%d: HW reread [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
+		esp->esp_id, eregs->esp_status, eregs->esp_sstep, eregs->esp_intrpt));
+#ifdef DEBUG_ESP_CMDS
+	printk("esp%d: last ESP cmds [", esp->esp_id);
+	i = (esp->espcmdent - 1) & 31;
+	printk("<");
+	esp_print_cmd(esp->espcmdlog[i]);
+	printk(">");
+	i = (i - 1) & 31;
+	printk("<");
+	esp_print_cmd(esp->espcmdlog[i]);
+	printk(">");
+	i = (i - 1) & 31;
+	printk("<");
+	esp_print_cmd(esp->espcmdlog[i]);
+	printk(">");
+	i = (i - 1) & 31;
+	printk("<");
+	esp_print_cmd(esp->espcmdlog[i]);
+	printk(">");
+	printk("]\n");
+#endif /* (DEBUG_ESP_CMDS) */
+
+	if(SCptr) {
+		ESPLOG(("esp%d: current command ", esp->esp_id));
+		esp_dump_cmd(SCptr);
+	}
+	ESPLOG(("\n"));
+	SCptr = esp->disconnected_SC;
+	ESPLOG(("esp%d: disconnected ", esp->esp_id));
+	while(SCptr) {
+		esp_dump_cmd(SCptr);
+		SCptr = (Scsi_Cmnd *) SCptr->host_scribble;
+	}
+	ESPLOG(("\n"));
+}
+
+/* Abort a command. */
+int esp_abort(Scsi_Cmnd *SCptr)
 {
-	ESPLOG(("esp_abort: Not implemented yet\n"));
-	return SCSI_ABORT_ERROR;
+	struct Sparc_ESP *esp = (struct Sparc_ESP *) SCptr->host->hostdata;
+	struct Sparc_ESP_regs *eregs = esp->eregs;
+	struct sparc_dma_registers *dregs = esp->dregs;
+	unsigned long flags;
+	int don;
+
+	ESPLOG(("esp%d: Aborting command\n", esp->esp_id));
+	save_flags(flags); cli();
+
+	esp_dump_state(esp, eregs, dregs);
+
+	/* Wheee, if this is the current command on the bus, the
+	 * best we can do is assert ATN and wait for msgout phase.
+	 * This should even fix a hung SCSI bus when we lose state
+	 * in the driver and timeout because the eventual phase change
+	 * will cause the ESP to (eventually) give an interrupt.
+	 */
+	if(esp->current_SC == SCptr) {
+		esp->cur_msgout[0] = ABORT;
+		esp->msgout_len = 1;
+		esp->msgout_ctr = 0;
+		esp_cmd(esp, eregs, ESP_CMD_SATN);
+		restore_flags(flags);
+		return SCSI_ABORT_PENDING;
+	}
+
+	/* If it is still in the issue queue then we can safely
+	 * call the completion routine and report abort success.
+	 */
+	don = (dregs->cond_reg & DMA_INT_ENAB);
+	if(don)
+		DMA_INTSOFF(dregs);
+	if(esp->issue_SC) {
+		Scsi_Cmnd **prev, *this;
+		for(prev = (&esp->issue_SC), this = esp->issue_SC;
+		    this;
+		    prev = (Scsi_Cmnd **) &(this->host_scribble),
+		    this = (Scsi_Cmnd *) this->host_scribble) {
+			if(this == SCptr) {
+				*prev = (Scsi_Cmnd *) this->host_scribble;
+				this->host_scribble = NULL;
+				this->result = DID_ABORT << 16;
+				this->done(this);
+				cli();
+				if(don)
+					DMA_INTSON(dregs);
+				restore_flags(flags);
+				return SCSI_ABORT_SUCCESS;
+			}
+		}
+	}
+
+	/* Yuck, the command to abort is disconnected, it is not
+	 * worth trying to abort it now if something else is live
+	 * on the bus at this time.  So, we let the SCSI code wait
+	 * a little bit and try again later.
+	 */
+	if(esp->current_SC) {
+		if(don)
+			DMA_INTSON(dregs);
+		restore_flags(flags);
+		return SCSI_ABORT_BUSY;
+	}
+
+	/* It's disconnected, we have to reconnect to re-establish
+	 * the nexus and tell the device to abort.  However, we really
+	 * cannot 'reconnect' per se, therefore we tell the upper layer
+	 * the safest thing we can.  This is, wait a bit, if nothing
+	 * happens, we are really hung so reset the bug.
+	 */
+
+	if(don)
+		DMA_INTSON(dregs);
+	restore_flags(flags);
+	return SCSI_ABORT_SNOOZE;
 }
 
 /* Reset ESP chip, reset hanging bus, then kill active and
@@ -696,8 +1722,13 @@
  */
 int esp_reset(Scsi_Cmnd *SCptr, unsigned int how)
 {
-	ESPLOG(("esp_reset: Not implemented yet\n"));
-	return SCSI_RESET_ERROR;
+	struct Sparc_ESP *esp = (struct Sparc_ESP *) SCptr->host->hostdata;
+	struct Sparc_ESP_regs *eregs = esp->eregs;
+
+	ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id));
+	esp->resetting_bus = 1;
+	esp_cmd(esp, eregs, ESP_CMD_RS);
+	return SCSI_RESET_PENDING;
 }
 
 /* Internal ESP done function. */
@@ -709,17 +1740,20 @@
 	if(esp->current_SC) {
 		/* Critical section... */
 		save_flags(flags); cli();
+
 		done_SC = esp->current_SC;
 		esp->current_SC = NULL;
+
 		/* Free dvma entry. */
 		if(!done_SC->use_sg) {
-			mmu_release_scsi_one(done_SC->SCp.ptr,
-						done_SC->SCp.this_residual,
-						esp->edev->my_bus);
+			/* Sneaky. */
+			mmu_release_scsi_one((char *)done_SC->SCp.have_data_in,
+					     done_SC->request_bufflen,
+					     esp->edev->my_bus);
 		} else {
 			struct scatterlist *scl = (struct scatterlist *)done_SC->buffer;
 #ifdef DEBUG_ESP_SG
-			printk("esp: unmapping sg ");
+			printk("esp%d: unmapping sg ", esp->esp_id);
 #endif
 			mmu_release_scsi_sgl((struct mmu_sglist *) scl,
 					     done_SC->use_sg - 1,
@@ -728,387 +1762,2292 @@
 			printk("done.\n");
 #endif
 		}
+
 		done_SC->result = error;
 		if(done_SC->scsi_done)
 			done_SC->scsi_done(done_SC);
 		else
 			panic("esp: esp->current_SC->scsi_done() == NULL");
 
+		/* There is a window of time within the scsi_done() path
+		 * of execution where interrupts are turned back on full
+		 * blast and left that way.  During that time we could
+		 * reconnect to a disconnected command, then we'd bomb
+		 * out below.  We could also end up executing two commands
+		 * at _once_.  ...just so you know why the cli() is here...
+		 */
+
+		cli(); /* GRRR!!! */
+
 		/* Bus is free, issue any commands in the queue. */
-		if(esp->issue_SC)
+		if(esp->issue_SC && !esp->current_SC)
 			esp_exec_cmd(esp);
 
 		restore_flags(flags);
 		/* End of critical section... */
-	} else
+	} else {
+		/* Panic is safe as current_SC is null so we may still
+		 * be able to accept more commands to sync disk buffers.
+		 */
+		ESPLOG(("panicing\n"));
 		panic("esp: done() called with NULL esp->current_SC");
+	}
 }
 
-#ifdef THREADED_ESP_DRIVER /* planning stage... */
+/* Wheee, ESP interrupt engine. */  
 
-/* With multiple lots of commands being processed I frequently
- * see a situation where we see galloping esp herds.  esp_done()
- * wakes the entire world up and each interrupt causes a reschedule.
- * This kernel thread fixes some of these unwanted effects during
- * IO intensive activity.... I hope...
- */
+enum {
+	do_phase_determine, do_reset_bus, do_reset_complete,
+	do_work_bus, do_intr_end,
+};
+
+/* Forward declarations. */
+static int esp_do_phase_determine(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+				  struct sparc_dma_registers *dregs);
+static int esp_do_data_finale(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+			      struct sparc_dma_registers *dregs);
+static int esp_select_complete(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+			       struct sparc_dma_registers *dregs);
+static int esp_do_status(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+			 struct sparc_dma_registers *dregs);
+static int esp_do_msgin(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+			struct sparc_dma_registers *dregs);
+static int esp_do_msgindone(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+			    struct sparc_dma_registers *dregs);
+static int esp_do_msgout(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+			 struct sparc_dma_registers *dregs);
+static int esp_do_cmdbegin(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+			   struct sparc_dma_registers *dregs);
 
-static void esp_kernel_thread(void *opaque)
+static inline int sreg_datainp(unchar sreg)
 {
-	struct Sparc_ESP *esp = opaque;
+	return (sreg & ESP_STAT_PMASK) == ESP_DIP;
+}
 
-	for(;;) {
-		unsigned long flags;
+static inline int sreg_dataoutp(unchar sreg)
+{
+	return (sreg & ESP_STAT_PMASK) == ESP_DOP;
+}
 
-		while(esp->eatme_SC) {
-			struct Scsi_Cmnd *SCpnt;
+/* Did they drop these fabs on the floor or what?!?!! */
+static inline void hme_fifo_hwbug_workaround(struct Sparc_ESP *esp,
+					     struct Sparc_ESP_regs *eregs)
+{
+	unchar status = esp->sreg;
+
+	/* Cannot safely frob the fifo for these following cases. */
+	if(sreg_datainp(status) || sreg_dataoutp(status) ||
+	   (esp->current_SC && esp->current_SC->SCp.phase == in_data_done)) {
+		ESPHME(("<wkaround_skipped>"));
+		return;
+	} else {
+		unsigned long count = 0;
+		unsigned long fcnt = eregs->esp_fflags & ESP_FF_FBYTES;
 
-			SCpnt = remove_first_SC(esp->eatme_SC);
-			esp_done(esp, error, SCpnt);
+		/* The HME stores bytes in multiples of 2 in the fifo. */
+		ESPHME(("hme_fifo[fcnt=%d", (int)fcnt));
+		while(fcnt) {
+			esp->hme_fifo_workaround_buffer[count++] = eregs->esp_fdata;
+			esp->hme_fifo_workaround_buffer[count++] = eregs->esp_fdata;
+			ESPHME(("<%02x,%02x>", esp->hme_fifo_workaround_buffer[count-2], esp->hme_fifo_workaround_buffer[count-1]));
+			fcnt--;
+		}
+		if(eregs->esp_status2 & ESP_STAT2_F1BYTE) {
+			ESPHME(("<poke_byte>"));
+			eregs->esp_fdata = 0;
+			esp->hme_fifo_workaround_buffer[count++] = eregs->esp_fdata;
+			ESPHME(("<%02x,0x00>", esp->hme_fifo_workaround_buffer[count-1]));
+			ESPHME(("CMD_FLUSH"));
+			esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+		} else {
+			ESPHME(("no_xtra_byte"));
 		}
-		sleep();
+		esp->hme_fifo_workaround_count = count;
+		ESPHME(("wkarnd_cnt=%d]", (int)count));
 	}
 }
-#endif
 
-/* Read the interrupt status registers on this ESP board */
-static inline void esp_updatesoft(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs)
+static inline void hme_fifo_push(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+				 unchar *bytes, unchar count)
 {
-	/* Update our software copies of the three ESP status
-	 * registers for this ESP.  Be careful, reading the
-	 * ESP interrupt register clears the status and sequence
-	 * step registers (unlatches them, you get the idea).
-	 * So read the interrupt register last.
-	 */
+	esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+	while(count) {
+		eregs->esp_fdata = *bytes++;
+		eregs->esp_fdata = 0;
+		count--;
+	}
+}
 
-	esp->seqreg = eregs->esp_sstep;
-	esp->sreg = eregs->esp_status;
+/* We try to avoid some interrupts by jumping ahead and see if the ESP
+ * has gotten far enough yet.  Hence the following.
+ */
+static inline int skipahead1(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+			     struct sparc_dma_registers *dregs,
+			     Scsi_Cmnd *scp, int prev_phase, int new_phase)
+{
+	if(scp->SCp.sent_command != prev_phase)
+		return 0;
+	if(DMA_IRQ_P(dregs)) {
+		/* Yes, we are able to save an interrupt. */
+		esp->sreg = eregs->esp_status;
+		if(esp->erev == fashme) {
+			/* This chip is really losing. */
+			ESPHME(("HME["));
+			/* Must latch fifo before reading the interrupt
+			 * register else garbage ends up in the FIFO
+			 * which confuses the driver utterly.
+			 * Happy Meal indeed....
+			 */
+			ESPHME(("fifo_workaround]"));
+			hme_fifo_hwbug_workaround(esp, eregs);
+		}
+		esp->ireg = eregs->esp_intrpt;
+		esp->sreg &= ~(ESP_STAT_INTR);
+		if(!(esp->ireg & ESP_INTR_SR))
+			return 0;
+		else
+			return do_reset_complete;
+	}
+	/* Ho hum, target is taking forever... */
+	scp->SCp.sent_command = new_phase; /* so we don't recurse... */
+	return do_intr_end;
+}
 
-	/* Supposedly, the ESP100A and above assert the highest
-	 * bit in the status register if an interrupt is pending.
-	 * I've never seen this work properly, so let's clear it
-	 * manually while we are here.  If I see any esp chips
-	 * for which this bit is reliable I will conditionalize
-	 * this.  However, I don't see what this extra bit can
-	 * buy me with all the tests I'll have to place all over
-	 * the code to actually use it when I 'can'.  Plus the
-	 * 'pending interrupt' condition can more than reliably
-	 * be obtained from the DVMA control register.
-	 *
-	 * "Broken hardware"  -Linus
-	 */
-	esp->sreg &= (~ESP_STAT_INTR);
-	esp->ireg = eregs->esp_intrpt;   /* Must be last or we lose */
+static inline int skipahead2(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+			     struct sparc_dma_registers *dregs,
+			     Scsi_Cmnd *scp, int prev_phase1, int prev_phase2,
+			     int new_phase)
+{
+	if(scp->SCp.sent_command != prev_phase1 &&
+	   scp->SCp.sent_command != prev_phase2)
+		return 0;
+	if(DMA_IRQ_P(dregs)) {
+		/* Yes, we are able to save an interrupt. */
+		esp->sreg = eregs->esp_status;
+		if(esp->erev == fashme) {
+			/* This chip is really losing. */
+			ESPHME(("HME["));
+
+			/* Must latch fifo before reading the interrupt
+			 * register else garbage ends up in the FIFO
+			 * which confuses the driver utterly.
+			 * Happy Meal indeed....
+			 */
+			ESPHME(("fifo_workaround]"));
+			hme_fifo_hwbug_workaround(esp, eregs);
+		}
+		esp->ireg = eregs->esp_intrpt;
+		esp->sreg &= ~(ESP_STAT_INTR);
+		if(!(esp->ireg & ESP_INTR_SR))
+			return 0;
+		else
+			return do_reset_complete;
+	}
+	/* Ho hum, target is taking forever... */
+	scp->SCp.sent_command = new_phase; /* so we don't recurse... */
+	return do_intr_end;
 }
 
-/* #define ESP_IRQ_TRACE */
+/* Now some dma helpers. */
+static inline void dma_setup(struct sparc_dma_registers *dregs, enum dvma_rev drev,
+			     char *addr, int count, int write)
+{
+	unsigned long nreg = dregs->cond_reg;
+	if(write)
+		nreg |= DMA_ST_WRITE;
+	else
+		nreg &= ~(DMA_ST_WRITE);
+	nreg |= DMA_ENABLE;
+	dregs->cond_reg = nreg;
+	if(drev == dvmaesc1) {
+		/* This ESC gate array sucks! */
+		unsigned long src = ((unsigned long) addr);
+		unsigned long dest = src + count;
+
+		if(dest & (PAGE_SIZE - 1))
+			count = PAGE_ALIGN(count);
+		dregs->cnt = count;
+	}
+	dregs->st_addr = addr;
+}
 
-#ifdef ESP_IRQ_TRACE
-#define ETRACE(foo)  printk foo
-#else
-#define ETRACE(foo)
-#endif
+static inline void dma_drain(struct sparc_dma_registers *dregs, enum dvma_rev drev)
+{
+	if(drev == dvmahme)
+		return;
+	if(dregs->cond_reg & DMA_FIFO_ISDRAIN) {
+		switch(drev) {
+		default:
+			dregs->cond_reg |= DMA_FIFO_STDRAIN;
 
-static char last_fflags, last_status, last_msg;
+		case dvmarev3:
+		case dvmaesc1:
+			while(dregs->cond_reg & DMA_FIFO_ISDRAIN)
+				udelay(1);
+		};
+	}
+}
 
-/* Main interrupt handler for an esp adapter. */
-static inline void esp_handle(struct Sparc_ESP *esp)
+static inline void dma_invalidate(struct sparc_dma_registers *dregs, enum dvma_rev drev)
 {
-	struct sparc_dma_registers *dregs;
-	struct Sparc_ESP_regs *eregs;
-	Scsi_Cmnd *SCptr;
+	unsigned long tmp;
 
-	eregs = esp->eregs;
-	dregs = esp->dregs;
-	SCptr = esp->current_SC;
+	if(drev == dvmahme) {
+		/* SMCC can bite me. */
+		tmp = dregs->cond_reg;
+		dregs->cond_reg = DMA_RST_SCSI;
+		tmp |= (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB|DMA_INT_ENAB);
+		tmp &= ~(DMA_ENABLE|DMA_ST_WRITE);
+		dregs->cond_reg = 0;
+		dregs->cond_reg = tmp;
+	} else {
+		while(dregs->cond_reg & DMA_PEND_READ)
+			udelay(1);
 
-	DMA_IRQ_ENTRY(esp->dma, dregs);
-	esp_updatesoft(esp, eregs);
+		tmp = dregs->cond_reg;
+		tmp &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB);
+		tmp |= DMA_FIFO_INV;
+		dregs->cond_reg = tmp;
+		dregs->cond_reg = (tmp & ~(DMA_FIFO_INV));
+	}
+}
 
-	ETRACE(("ESPIRQ: <%2x,%2x,%2x> --> ", esp->ireg, esp->sreg, esp->seqreg));
+static inline void dma_flashclear(struct sparc_dma_registers *dregs, enum dvma_rev drev)
+{
+	dma_drain(dregs, drev);
+	dma_invalidate(dregs, drev);
+}
 
-	/* Check for errors. */
-	if(!SCptr)
-		panic("esp_handle: current_SC == penguin within interrupt!");
+static inline int dma_can_transfer(Scsi_Cmnd *sp, enum dvma_rev drev)
+{
+	unsigned long base, end, sz;
 
-	/* At this point in time, this esp driver should not see
-	 * scsibus resets, parity errors, or gross errors unless
-	 * something truly terrible happens which we are not ready
-	 * to properly recover from yet.
-	 */
-	if((esp->ireg & (ESP_INTR_SR | ESP_INTR_IC)) ||
-	   (esp->sreg & (ESP_STAT_PERR | ESP_STAT_SPAM))) {
-		printk("esp: really bad error detected\n");
-		printk("esp: intr<%2x> stat<%2x> seq<%2x>",
-		       esp->ireg, esp->sreg, esp->seqreg);
-		printk("esp: SCptr->SCp.phase = %d\n", SCptr->SCp.phase);
-		panic("esp: cannot continue\n");
+	if(drev == dvmarev3) {
+		sz = sp->SCp.this_residual;
+		if(sz > 0x1000000)
+			sz = 0x1000000;
+	} else {
+		base = (unsigned long) sp->SCp.ptr;
+		base &= (0x1000000 - 1);
+		end = (base + sp->SCp.this_residual);
+		if(end > 0x1000000)
+			end = 0x1000000;
+		sz = (end - base);
 	}
-	if(dregs->cond_reg & DMA_HNDL_ERROR) {
-		printk("esp: DMA shows an error cond_reg<%08lx> addr<%p>\n",
-		       dregs->cond_reg, dregs->st_addr);
-		printk("esp: intr<%2x> stat<%2x> seq<%2x>",
-		       esp->ireg, esp->sreg, esp->seqreg);
-		printk("esp: SCptr->SCp.phase = %d\n", SCptr->SCp.phase);
-		panic("esp: cannot continue\n");
-	}
-	if(esp->sreg & ESP_STAT_PERR) {
-		printk("esp: SCSI bus parity error\n");
-		printk("esp: intr<%2x> stat<%2x> seq<%2x>",
-		       esp->ireg, esp->sreg, esp->seqreg);
-		printk("esp: SCptr->SCp.phase = %d\n", SCptr->SCp.phase);
-		panic("esp: cannot continue\n");
+	return sz;
+}
+
+/* Misc. esp helper routines. */
+static inline void esp_setcount(struct Sparc_ESP_regs *eregs, int cnt, int hme)
+{
+	eregs->esp_tclow = (cnt & 0xff);
+	eregs->esp_tcmed = ((cnt >> 8) & 0xff);
+	if(hme) {
+		eregs->fas_rlo = 0;
+		eregs->fas_rhi = 0;
 	}
+}
 
-	/* Service interrupt. */
-	switch(SCptr->SCp.phase) {
-	case not_issued:
-		panic("Unexpected ESP interrupt, current_SC not issued.");
-		break;
-	case in_selection:
-		if(esp->ireg & ESP_INTR_RSEL) {
-			/* XXX Some day XXX */
-			panic("ESP penguin reselected in async mode.");
-		} else if(esp->ireg & ESP_INTR_DC) {
-			/* Either we are scanning the bus and no-one
-			 * lives at this target or it didn't respond.
-			 */
-			ETRACE(("DISCONNECT\n"));
-#ifdef THREADED_ESP_DRIVER
-			append_SC(esp->eatme_SC, esp->current_SC);
-			esp->current_SC = 0;
-			wake_up(esp_kernel_thread);
-#else
-			esp_done(esp, (DID_NO_CONNECT << 16));
-#endif
-			goto esp_handle_done;
-		} else if((esp->ireg & (ESP_INTR_FDONE | ESP_INTR_BSERV)) ==
-			  (ESP_INTR_FDONE | ESP_INTR_BSERV)) {
-			/* Selection successful, check the sequence step. */
-			/* XXX I know, I know... add error recovery.  XXX */
-			switch(esp->seqreg & ESP_STEP_VBITS) {
-			case ESP_STEP_NCMD:
-				panic("esp: penguin didn't enter cmd phase.");
-				break;
-			case ESP_STEP_PPC:
-				panic("esp: penguin prematurely changed from cmd phase.");
-				break;
-			case ESP_STEP_FINI:
-				/* At the completion of every command
-				 * or message-out phase, we _must_
-				 * unlatch the fifo-flags register
-				 * with an ESP nop command.
-				 */
-				eregs->esp_cmd = ESP_CMD_NULL;
+static inline int esp_getcount(struct Sparc_ESP_regs *eregs)
+{
+	return (((eregs->esp_tclow)&0xff) |
+		(((eregs->esp_tcmed)&0xff) << 8));
+}
 
-				/* Selection/Command sequence completed.  We
-				 * (at least for this driver) will be in
-				 * either one of the data phases or status
-				 * phase, check the status register to find
-				 * out.
-				 */
-				switch(esp->sreg & ESP_STAT_PMASK) {
-				default:
-					printk("esp: Not datain/dataout/status.\n");
-					panic("esp: penguin phase transition after selection.");
-					break;
-				case ESP_DOP:
-					/* Data out phase. */
-					dregs->cond_reg |= DMA_FIFO_INV;
-					while(dregs->cond_reg & DMA_FIFO_ISDRAIN)
-						barrier();
-					SCptr->SCp.phase = in_dataout;
-#ifdef DEBUG_ESP_SG
-					if(SCptr->use_sg)
-						printk("esp: sg-start <%p,%d>",
-						       SCptr->SCp.ptr,
-						       SCptr->SCp.this_residual);
-#endif
-					eregs->esp_tclow = SCptr->SCp.this_residual;
-					eregs->esp_tcmed = (SCptr->SCp.this_residual>>8);
-					eregs->esp_cmd = (ESP_CMD_DMA | ESP_CMD_NULL);
-
-					/* This is either the one buffer dvma ptr,
-					 * or the first one in the scatter gather
-					 * list.  Check out esp_queue to see how
-					 * this is set up.
-					 */
-					dregs->st_addr = SCptr->SCp.ptr;
-					dregs->cond_reg &= ~(DMA_ST_WRITE);
-					dregs->cond_reg |= (DMA_ENABLE | DMA_INT_ENAB);
-					eregs->esp_cmd = (ESP_CMD_DMA | ESP_CMD_TI);
-					ETRACE(("DATA_OUT\n"));
-					goto esp_handle_done;
-				case ESP_DIP:
-					/* Data in phase. */
-					dregs->cond_reg |= DMA_FIFO_INV;
-					while(dregs->cond_reg & DMA_FIFO_ISDRAIN)
-						barrier();
-					SCptr->SCp.phase = in_datain;
-#ifdef DEBUG_ESP_SG
-					if(SCptr->use_sg)
-						printk("esp: sg-start <%p,%d>",
-						       SCptr->SCp.ptr,
-						       SCptr->SCp.this_residual);
-#endif
-					eregs->esp_tclow = SCptr->SCp.this_residual;
-					eregs->esp_tcmed = (SCptr->SCp.this_residual>>8);
-					eregs->esp_cmd = (ESP_CMD_DMA | ESP_CMD_NULL);
-
-					/* This is either the one buffer dvma ptr,
-					 * or the first one in the scatter gather
-					 * list.  Check out esp_queue to see how
-					 * this is set up.
-					 */
-					dregs->st_addr = SCptr->SCp.ptr;
-					dregs->cond_reg |= (DMA_ENABLE | DMA_ST_WRITE | DMA_INT_ENAB);
-					eregs->esp_cmd = (ESP_CMD_DMA | ESP_CMD_TI);
-					ETRACE(("DATA_IN\n"));
-					goto esp_handle_done;
-				case ESP_STATP:
-					/* Status phase. */
-					SCptr->SCp.phase = in_status;
-					eregs->esp_cmd = ESP_CMD_ICCSEQ;
-					ETRACE(("STATUS\n"));
-					goto esp_handle_done; /* Wait for message. */
-				};
-			};
-		} else if(esp->ireg & ESP_INTR_FDONE) {
-			/* I'd like to investigate why this happens... */
-			ESPLOG(("esp: This is weird, halfway through "));
-			ESPLOG(("selection, trying to continue anyways.\n"));
-			goto esp_handle_done;
-		} else {
-			panic("esp: Did not get bus service during selection.");
-			goto esp_handle_done;
-		}
-		panic("esp: Mr. Potatoe Head is on the loose!");
+static inline int fcount(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs)
+{
+	if(esp->erev == fashme)
+		return esp->hme_fifo_workaround_count;
+	else
+		return eregs->esp_fflags & ESP_FF_FBYTES;
+}
 
-	case in_datain:
-		/* Drain the fifo for writes to memory. */
-		switch(esp->dma->revision) {
-		case dvmarev0:
-		case dvmarev1:
-		case dvmarevplus:
-		case dvmarev2:
-		case dvmarev3:
-			/* Force a drain. */
-			dregs->cond_reg |= DMA_FIFO_STDRAIN;
+static inline int fnzero(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs)
+{
+	if(esp->erev == fashme)
+		return 0;
+	else
+		return eregs->esp_fflags & ESP_FF_ONOTZERO;
+}
 
-			/* fall through */
-		case dvmaesc1:
-			/* Wait for the fifo to drain completely. */
-			while(dregs->cond_reg & DMA_FIFO_ISDRAIN)
-				barrier();
+/* XXX speculative nops unnecessary when continuing amidst a data phase
+ * XXX even on esp100!!!  another case of flooding the bus with I/O reg
+ * XXX writes...
+ */
+static inline void esp_maybe_nop(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs)
+{
+	if(esp->erev == esp100)
+		esp_cmd(esp, eregs, ESP_CMD_NULL);
+}
+
+static inline int sreg_to_dataphase(unchar sreg)
+{
+	if((sreg & ESP_STAT_PMASK) == ESP_DOP)
+		return in_dataout;
+	else
+		return in_datain;
+}
+
+/* The ESP100 when in synchronous data phase, can mistake a long final
+ * REQ pulse from the target as an extra byte, it places whatever is on
+ * the data lines into the fifo.  For now, we will assume when this
+ * happens that the target is a bit quirky and we don't want to
+ * be talking synchronously to it anyways.  Regardless, we need to
+ * tell the ESP to eat the extraneous byte so that we can proceed
+ * to the next phase.
+ */
+static inline int esp100_sync_hwbug(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+				    Scsi_Cmnd *sp, int fifocnt)
+{
+	/* Do not touch this piece of code. */
+	if((!(esp->erev == esp100)) ||
+	   (!(sreg_datainp((esp->sreg = eregs->esp_status)) && !fifocnt) &&
+	    !(sreg_dataoutp(esp->sreg) && !fnzero(esp, eregs)))) {
+		if(sp->SCp.phase == in_dataout)
+			esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+		return 0;
+	} else {
+		/* Async mode for this guy. */
+		build_sync_nego_msg(esp, 0, 0);
+
+		/* Ack the bogus byte, but set ATN first. */
+		esp_cmd(esp, eregs, ESP_CMD_SATN);
+		esp_cmd(esp, eregs, ESP_CMD_MOK);
+		return 1;
+	}
+}
+
+/* This closes the window during a selection with a reselect pending, because
+ * we use DMA for the selection process the FIFO should hold the correct
+ * contents if we get reselected during this process.  So we just need to
+ * ack the possible illegal cmd interrupt pending on the esp100.
+ */
+static inline int esp100_reconnect_hwbug(struct Sparc_ESP *esp,
+					 struct Sparc_ESP_regs *eregs)
+{
+	volatile unchar junk;
+
+	if(esp->erev != esp100)
+		return 0;
+	junk = eregs->esp_intrpt;
+	if(junk & ESP_INTR_SR)
+		return 1;
+	return 0;
+}
+
+/* This verifies the BUSID bits during a reselection so that we know which
+ * target is talking to us.
+ */
+static inline int reconnect_target(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs)
+{
+	int it, me = esp->scsi_id_mask, targ = 0;
+
+	if(2 != fcount(esp, eregs))
+		return -1;
+	if(esp->erev == fashme) {
+		/* HME does not latch it's own BUS ID bits during
+		 * a reselection.  Also the target number is given
+		 * as an unsigned char, not as a sole bit number
+		 * like the other ESP's do.
+		 * Happy Meal indeed....
+		 */
+		targ = esp->hme_fifo_workaround_buffer[0];
+	} else {
+		it = eregs->esp_fdata;
+		if(!(it & me))
+			return -1;
+		it &= ~me;
+		if(it & (it - 1))
+			return -1;
+		while(!(it & 1))
+			targ++, it >>= 1;
+	}
+	return targ;
+}
+
+/* This verifies the identify from the target so that we know which lun is
+ * being reconnected.
+ */
+static inline int reconnect_lun(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs)
+{
+	int lun;
+
+	if((esp->sreg & ESP_STAT_PMASK) != ESP_MIP)
+		return -1;
+	if(esp->erev == fashme)
+		lun = esp->hme_fifo_workaround_buffer[1];
+	else
+		lun = eregs->esp_fdata;
+	if(esp->sreg & ESP_STAT_PERR)
+		return 0;
+	if((lun & 0x40) || !(lun & 0x80))
+		return -1;
+	return lun & 7;
+}
+
+/* This puts the driver in a state where it can revitalize a command that
+ * is being continued due to reselection.
+ */
+static inline void esp_connect(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+			       Scsi_Cmnd *sp)
+{
+	Scsi_Device *dp = sp->device;
+	eregs->esp_soff = dp->sync_max_offset;
+	eregs->esp_stp  = dp->sync_min_period;
+	if(esp->erev > esp100a)
+		eregs->esp_cfg3 = esp->config3[sp->target];
+	if(esp->erev == fashme)
+		eregs->esp_busid = (sp->target & 0xf) |
+			(ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT);
+	esp->current_SC = sp;
+}
+
+/* This will place the current working command back into the issue queue
+ * if we are to receive a reselection amidst a selection attempt.
+ */
+static inline void esp_reconnect(struct Sparc_ESP *esp, Scsi_Cmnd *sp)
+{
+	if(!esp->disconnected_SC)
+		printk("esp%d: Weird, being reselected but disconnected "
+		       "command queue is empty.\n", esp->esp_id);
+	esp->snip = 0;
+	esp->current_SC = 0;
+	sp->SCp.phase = not_issued;
+	append_SC(&esp->issue_SC, sp);
+}
+
+/* Begin message in phase. */
+static inline int esp_do_msgin(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+			       struct sparc_dma_registers *dregs)
+{
+	/* Must be very careful with the fifo on the HME */
+	if((esp->erev != fashme) || !(eregs->esp_status2 & ESP_STAT2_FEMPTY))
+		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+	esp_maybe_nop(esp, eregs);
+	esp_cmd(esp, eregs, ESP_CMD_TI);
+	esp->msgin_len = 1;
+	esp->msgin_ctr = 0;
+	esp_advance_phase(esp->current_SC, in_msgindone);
+	return do_work_bus;
+}
+
+/* This uses various DMA csr fields and the fifo flags count value to
+ * determine how many bytes were successfully sent/received by the ESP.
+ */
+static inline int esp_bytes_sent(struct Sparc_ESP *esp,
+				 struct sparc_dma_registers *dregs,
+				 int fifo_count)
+{
+	int rval = (((unsigned long)dregs->st_addr) -
+		    ((unsigned long)esp->esp_command));
+
+	if(esp->dma->revision == dvmarev1)
+		rval -= (4 - ((dregs->cond_reg & DMA_READ_AHEAD)>>11));
+	return rval - fifo_count;
+}
+
+static inline void advance_sg(Scsi_Cmnd *sp)
+{
+	++sp->SCp.buffer;
+	--sp->SCp.buffers_residual;
+	sp->SCp.this_residual = sp->SCp.buffer->length;
+	sp->SCp.ptr = sp->SCp.buffer->dvma_address;
+}
+
+/* Complete a command, this is the only way to safely finish
+ * a command with disconnected commands or a reset interrupt
+ * pending because scsi_done() can enable interrupts full blast.
+ */
+static inline void safe_esp_done(struct Sparc_ESP *esp,
+				 struct sparc_dma_registers *dregs,
+				 int error)
+{
+	int before = 0;
+
+	if(dregs->cond_reg & DMA_INT_ENAB) {
+		before = 1;
+		DMA_INTSOFF(dregs);
+	}
+	esp_done(esp, error);
+	if(before)
+		DMA_INTSON(dregs);
+}
+
+/* Please note that the way I've coded these routines is that I _always_
+ * check for a disconnect during any and all information transfer
+ * phases.  The SCSI standard states that the target _can_ cause a BUS
+ * FREE condition by dropping all MSG/CD/IO/BSY signals.  Also note
+ * that during information transfer phases the target controls every
+ * change in phase, the only thing the initiator can do is "ask" for
+ * a message out phase by driving ATN true.  The target can, and sometimes
+ * will, completely ignore this request so we cannot assume anything when
+ * we try to force a message out phase to abort/reset a target.  Most of
+ * the time the target will eventually be nice and go to message out, so
+ * we may have to hold on to our state about what we want to tell the target
+ * for some period of time.
+ */
+
+/* I think I have things working here correctly.  Even partial transfers
+ * within a buffer or sub-buffer should not upset us at all no matter
+ * how bad the target and/or ESP fucks things up.
+ */
+static inline int esp_do_data(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+			      struct sparc_dma_registers *dregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+	int thisphase, hmuch;
+
+	ESPDATA(("esp_do_data: "));
+	esp_maybe_nop(esp, eregs);
+	thisphase = sreg_to_dataphase(esp->sreg);
+	esp_advance_phase(SCptr, thisphase);
+	ESPDATA(("newphase<%s> ", (thisphase == in_datain) ? "DATAIN" : "DATAOUT"));
+	hmuch = dma_can_transfer(SCptr, esp->dma->revision);
+	ESPDATA(("hmuch<%d> ", hmuch));
+	esp->current_transfer_size = hmuch;
+	if(esp->erev == fashme) {
+		unsigned long tmp = dregs->cond_reg;
+
+		/* Touchy chip, this stupid HME scsi adapter... */
+		esp_setcount(eregs, hmuch, 1);
+		esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+		dregs->cnt = hmuch;
+		tmp |= (DMA_SCSI_DISAB | DMA_ENABLE);
+		if(thisphase == in_datain)
+			tmp |= DMA_ST_WRITE;
+		else
+			tmp &= ~(DMA_ST_WRITE);
+		dregs->st_addr = SCptr->SCp.ptr;
+		dregs->cond_reg = tmp;
+	} else {
+		esp_setcount(eregs, hmuch, 0);
+		dma_setup(dregs, esp->dma->revision, SCptr->SCp.ptr,
+			  hmuch, (thisphase == in_datain));
+		ESPDATA(("DMA|TI --> do_intr_end\n"));
+		esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+	}
+	return do_intr_end;
+}
+
+/* See how successful the data transfer was. */
+static inline int esp_do_data_finale(struct Sparc_ESP *esp,
+				     struct Sparc_ESP_regs *eregs,
+				     struct sparc_dma_registers *dregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+	int bogus_data = 0, bytes_sent = 0, fifocnt, ecount = 0;
+
+	ESPDATA(("esp_do_data_finale: "));
+
+	if(SCptr->SCp.phase == in_datain) {
+		if(esp->sreg & ESP_STAT_PERR) {
+			/* Yuck, parity error.  The ESP asserts ATN
+			 * so that we can go to message out phase
+			 * immediately and inform the target that
+			 * something bad happened.
+			 */
+			ESPLOG(("esp%d: data bad parity detected.\n",
+				esp->esp_id));
+			esp->cur_msgout[0] = INITIATOR_ERROR;
+			esp->msgout_len = 1;
+		}
+		dma_drain(dregs, esp->dma->revision);
+	}
+	dma_invalidate(dregs, esp->dma->revision);
+
+	/* This could happen for the above parity error case. */
+	if(!(esp->ireg == ESP_INTR_BSERV)) {
+		/* Please go to msgout phase, please please please... */
+		ESPLOG(("esp%d: !BSERV after data, probably to msgout\n",
+			esp->esp_id));
+		return esp_do_phase_determine(esp, eregs, dregs);
+	}	
+
+	/* Check for partial transfers and other horrible events.
+	 * Note, here we read the real fifo flags register even
+	 * on HME broken adapters because we skip the HME fifo
+	 * workaround code in esp_handle() if we are doing data
+	 * phase things.  We don't want to fuck directly with
+	 * the fifo like that, especially if doing syncronous
+	 * transfers!  Also, will need to double the count on
+	 * HME if we are doing wide transfers, as the HME fifo
+	 * will move and count 16-bit quantities during wide data.
+	 * SMCC _and_ Qlogic can both bite me.
+	 */
+	fifocnt = eregs->esp_fflags & ESP_FF_FBYTES;
+	if(esp->erev != fashme)
+		ecount = esp_getcount(eregs);
+	bytes_sent = esp->current_transfer_size;
+
+	/* Uhhh, might not want both of these conditionals to run
+	 * at once on HME due to the fifo problems it has.  Consider
+	 * changing it to:
+	 *
+	 * 	if(!(esp->sreg & ESP_STAT_TCNT)) {
+	 * 		bytes_sent -= ecount;
+	 * 	} else if(SCptr->SCp.phase == in_dataout) {
+	 * 		bytes_sent -= fifocnt;
+	 *	}
+	 *
+	 * But only for the HME case, leave the current code alone
+	 * for all other ESP revisions as we know the existing code
+	 * works just fine for them.
+	 */
+	ESPDATA(("trans_sz=%d, ", bytes_sent));
+	if(esp->erev == fashme) {
+		if(!(esp->sreg & ESP_STAT_TCNT)) {
+			bytes_sent -= esp_getcount(eregs);
+		} else if(SCptr->SCp.phase == in_dataout) {
+			bytes_sent -= fifocnt;
+		}
+	} else {
+		if(!(esp->sreg & ESP_STAT_TCNT))
+			bytes_sent -= ecount;
+		if(SCptr->SCp.phase == in_dataout)
+			bytes_sent -= fifocnt;
+	}
+
+	ESPDATA(("bytes_sent=%d, ", bytes_sent));
+
+	/* If we were in synchronous mode, check for peculiarities. */
+	if(esp->erev == fashme) {
+		if(SCptr->device->sync_max_offset) {
+			if(SCptr->SCp.phase == in_dataout)
+				esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+		} else {
+			esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+		}
+	} else {
+		if(SCptr->device->sync_max_offset)
+			bogus_data = esp100_sync_hwbug(esp, eregs, SCptr, fifocnt);
+		else
+			esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+	}
+
+	/* Until we are sure of what has happened, we are certainly
+	 * in the dark.
+	 */
+	esp_advance_phase(SCptr, in_the_dark);
+
+	if(bytes_sent < 0) {
+		/* I've seen this happen due to lost state in this
+		 * driver.  No idea why it happened, but allowing
+		 * this value to be negative caused things to
+		 * lock up.  This allows greater chance of recovery.
+		 */
+		ESPLOG(("esp%d: yieee, bytes_sent < 0!\n", esp->esp_id));
+		ESPLOG(("esp%d: csz=%d fifocount=%d ecount=%d\n",
+			esp->esp_id,
+			esp->current_transfer_size, fifocnt, ecount));
+		ESPLOG(("esp%d: use_sg=%d ptr=%p this_residual=%d\n",
+			esp->esp_id,
+			SCptr->use_sg, SCptr->SCp.ptr, SCptr->SCp.this_residual));
+		bytes_sent = 0;
+	}
+
+	/* Update the state of our transfer. */
+	SCptr->SCp.ptr += bytes_sent;
+	SCptr->SCp.this_residual -= bytes_sent;
+	if(SCptr->SCp.this_residual < 0) {
+		/* shit */
+		printk("esp%d: Data transfer overrun.\n", esp->esp_id);
+		SCptr->SCp.this_residual = 0;
+	}
+
+	/* Maybe continue. */
+	if(!bogus_data) {
+		ESPDATA(("!bogus_data, "));
+		/* NO MATTER WHAT, we advance the scatterlist,
+		 * if the target should decide to disconnect
+		 * in between scatter chunks (which is common)
+		 * we could die horribly!  I used to have the sg
+		 * advance occur only if we are going back into
+		 * (or are staying in) a data phase, you can
+		 * imagine the hell I went through trying to
+		 * figure this out.
+		 */
+		if(SCptr->use_sg && !SCptr->SCp.this_residual)
+			advance_sg(SCptr);
+		if(sreg_datainp(esp->sreg) || sreg_dataoutp(esp->sreg)) {
+			ESPDATA(("to more data\n"));
+			return esp_do_data(esp, eregs, dregs);
+		}
+		ESPDATA(("to new phase\n"));
+		return esp_do_phase_determine(esp, eregs, dregs);
+	}
+	/* Bogus data, just wait for next interrupt. */
+	ESPLOG(("esp%d: bogus_data during end of data phase\n",
+		esp->esp_id));
+	return do_intr_end;
+}
+
+/* Either a command is completing or a target is dropping off the bus
+ * to continue the command in the background so we can do other work.
+ */
+static inline int esp_do_freebus(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+				 struct sparc_dma_registers *dregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+	int rval;
+
+	rval = skipahead2(esp, eregs, dregs, SCptr, in_status, in_msgindone, in_freeing);
+	if(rval)
+		return rval;
+	if(esp->ireg != ESP_INTR_DC) {
+		ESPLOG(("esp%d: Target will not disconnect\n", esp->esp_id));
+		return do_reset_bus; /* target will not drop BSY... */
+	}
+	esp->msgout_len = 0;
+	esp->prevmsgout = NOP;
+	if(esp->prevmsgin == COMMAND_COMPLETE) {
+		/* Normal end of nexus. */
+		if(esp->disconnected_SC || (esp->erev == fashme))
+			esp_cmd(esp, eregs, ESP_CMD_ESEL);
+
+		if(SCptr->SCp.Status != GOOD && SCptr->SCp.Status != CONDITION_GOOD &&
+		   ((1<<SCptr->target) & esp->targets_present) &&
+		   SCptr->device->sync && SCptr->device->sync_max_offset) {
+			/* SCSI standard says that the synchronous capabilities
+			 * should be renegotiated at this point.  Most likely
+			 * we are about to request sense from this target
+			 * in which case we want to avoid using sync
+			 * transfers until we are sure of the current target
+			 * state.
+			 */
+			ESPMISC(("esp: Status <%d> for target %d lun %d\n",
+				 SCptr->SCp.Status, SCptr->target, SCptr->lun));
+
+			/* But don't do this when spinning up a disk at
+			 * boot time while we poll for completion as it
+			 * fills up the console with messages.  Also, tapes
+			 * can report not ready many times right after
+			 * loading up a tape.
+			 */
+			if(SCptr->cmnd[0] != START_STOP &&
+			   SCptr->data_cmnd[0] != START_STOP &&
+			   SCptr->cmnd[0] != TEST_UNIT_READY &&
+			   SCptr->data_cmnd[0] != TEST_UNIT_READY &&
+			   !(SCptr->device->type == TYPE_TAPE &&
+			     (SCptr->cmnd[0] == TEST_UNIT_READY ||
+			      SCptr->data_cmnd[0] == TEST_UNIT_READY ||
+			      SCptr->cmnd[0] == MODE_SENSE ||
+			      SCptr->data_cmnd[0] == MODE_SENSE)))
+				SCptr->device->sync = 0;
+		}
+		ESPDISC(("F<%02x,%02x>", SCptr->target, SCptr->lun));
+		safe_esp_done(esp, dregs, ((SCptr->SCp.Status & 0xff) |
+					   ((SCptr->SCp.Message & 0xff)<<8) |
+					   (DID_OK << 16)));
+	} else if(esp->prevmsgin == DISCONNECT) {
+		/* Normal disconnect. */
+		esp_cmd(esp, eregs, ESP_CMD_ESEL);
+		ESPDISC(("D<%02x,%02x>", SCptr->target, SCptr->lun));
+		append_SC(&esp->disconnected_SC, SCptr);
+		esp->current_SC = NULL;
+		if(esp->issue_SC)
+			esp_exec_cmd(esp);
+	} else {
+		/* Driver bug, we do not expect a disconnect here
+		 * and should not have advanced the state engine
+		 * to in_freeing.
+		 */
+		ESPLOG(("esp%d: last msg not disc and not cmd cmplt.\n",
+			esp->esp_id));
+		return do_reset_bus;
+	}
+	return do_intr_end;
+}
+
+/* Do the needy when a target tries to reconnect to us. */
+static inline int esp_do_reconnect(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+				   struct sparc_dma_registers *dregs)
+{
+	int lun, target;
+	Scsi_Cmnd *SCptr;
+
+	/* Check for all bogus conditions first. */
+	target = reconnect_target(esp, eregs);
+	if(target < 0) {
+		ESPDISC(("bad bus bits\n"));
+		return do_reset_bus;
+	}
+	lun = reconnect_lun(esp, eregs);
+	if(lun < 0) {
+		ESPDISC(("target=%2x, bad identify msg\n", target));
+		return do_reset_bus;
+	}
+
+	/* Things look ok... */
+	ESPDISC(("R<%02x,%02x>", target, lun));
+
+	/* Must flush both FIFO and the DVMA on HME. */
+	if(esp->erev == fashme) {
+		/* XXX this still doesn't fix the problem... */
+		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+		dma_invalidate(esp->dregs, dvmahme);
+	} else {
+		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+		if(esp100_reconnect_hwbug(esp, eregs))
+			return do_reset_bus;
+		esp_cmd(esp, eregs, ESP_CMD_NULL);
+	}
+
+	SCptr = remove_SC(&esp->disconnected_SC, (unchar) target, (unchar) lun);
+	if(!SCptr) {
+		Scsi_Cmnd *sp;
+
+		ESPLOG(("esp%d: Eieeee, reconnecting unknown command!\n",
+			esp->esp_id));
+		ESPLOG(("QUEUE DUMP\n"));
+		sp = esp->issue_SC;
+		ESPLOG(("esp%d: issue_SC[", esp->esp_id));
+		while(sp) {
+			ESPLOG(("<%02x,%02x>", sp->target, sp->lun));
+			sp = (Scsi_Cmnd *) sp->host_scribble;
+		}
+		ESPLOG(("]\n"));
+		sp = esp->current_SC;
+		ESPLOG(("esp%d: current_SC[", esp->esp_id));
+		while(sp) {
+			ESPLOG(("<%02x,%02x>", sp->target, sp->lun));
+			sp = (Scsi_Cmnd *) sp->host_scribble;
+		}
+		ESPLOG(("]\n"));
+		sp = esp->disconnected_SC;
+		ESPLOG(("esp%d: disconnected_SC[", esp->esp_id));
+		while(sp) {
+			ESPLOG(("<%02x,%02x>", sp->target, sp->lun));
+			sp = (Scsi_Cmnd *) sp->host_scribble;
+		}
+		ESPLOG(("]\n"));
+		return do_reset_bus;
+	}
+	esp_connect(esp, eregs, SCptr);
+	esp_cmd(esp, eregs, ESP_CMD_MOK);
+
+	/* No need for explicit restore pointers operation. */
+	esp->snip = 0;
+	esp_advance_phase(SCptr, in_the_dark);
+	return do_intr_end;
+}
+
+/* End of NEXUS (hopefully), pick up status + message byte then leave if
+ * all goes well.
+ */
+static int esp_do_status(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+			 struct sparc_dma_registers *dregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+	int intr, rval;
+
+	rval = skipahead1(esp, eregs, dregs, SCptr, in_the_dark, in_status);
+	if(rval)
+		return rval;
+	intr = esp->ireg;
+	ESPSTAT(("esp_do_status: "));
+	if(intr != ESP_INTR_DC) {
+		int message_out = 0; /* for parity problems */
+
+		/* Ack the message. */
+		ESPSTAT(("ack msg, "));
+		esp_cmd(esp, eregs, ESP_CMD_MOK);
+
+		if(esp->erev != fashme) {
+			dma_flashclear(dregs, esp->dma->revision);
+
+			/* Wait till the first bits settle. */
+			while(esp->esp_command[0] == 0xff)
+				udelay(1);
+		} else {
+			esp->esp_command[0] = esp->hme_fifo_workaround_buffer[0];
+			esp->esp_command[1] = esp->hme_fifo_workaround_buffer[1];
+		}
+
+		ESPSTAT(("got something, "));
+		/* ESP chimes in with one of
+		 *
+		 * 1) function done interrupt:
+		 *	both status and message in bytes
+		 *	are available
+		 *
+		 * 2) bus service interrupt:
+		 *	only status byte was acquired
+		 *
+		 * 3) Anything else:
+		 *	can't happen, but we test for it
+		 *	anyways
+		 *
+		 * ALSO: If bad parity was detected on either
+		 *       the status _or_ the message byte then
+		 *       the ESP has asserted ATN on the bus
+		 *       and we must therefore wait for the
+		 *       next phase change.
+		 */
+		if(intr & ESP_INTR_FDONE) {
+			/* We got it all, hallejulia. */
+			ESPSTAT(("got both, "));
+			SCptr->SCp.Status = esp->esp_command[0];
+			SCptr->SCp.Message = esp->esp_command[1];
+			esp->prevmsgin = SCptr->SCp.Message;
+			esp->cur_msgin[0] = SCptr->SCp.Message;
+			if(esp->sreg & ESP_STAT_PERR) {
+				/* There was bad parity for the
+				 * message byte, the status byte
+				 * was ok.
+				 */
+				message_out = MSG_PARITY_ERROR;
+			}
+		} else if(intr == ESP_INTR_BSERV) {
+			/* Only got status byte. */
+			ESPLOG(("esp%d: got status only, ", esp->esp_id));
+			if(!(esp->sreg & ESP_STAT_PERR)) {
+				SCptr->SCp.Status = esp->esp_command[0];
+				SCptr->SCp.Message = 0xff;
+			} else {
+				/* The status byte had bad parity.
+				 * we leave the scsi_pointer Status
+				 * field alone as we set it to a default
+				 * of CHECK_CONDITION in esp_queue.
+				 */
+				message_out = INITIATOR_ERROR;
+			}
+		} else {
+			/* This shouldn't happen ever. */
+			ESPSTAT(("got bolixed\n"));
+			esp_advance_phase(SCptr, in_the_dark);
+			return esp_do_phase_determine(esp, eregs, dregs);
+		}
+
+		if(!message_out) {
+			ESPSTAT(("status=%2x msg=%2x, ", SCptr->SCp.Status,
+				SCptr->SCp.Message));
+			if(SCptr->SCp.Message == COMMAND_COMPLETE) {
+				ESPSTAT(("and was COMMAND_COMPLETE\n"));
+				esp_advance_phase(SCptr, in_freeing);
+				return esp_do_freebus(esp, eregs, dregs);
+			} else {
+				ESPLOG(("esp%d: and _not_ COMMAND_COMPLETE\n",
+					esp->esp_id));
+				esp->msgin_len = esp->msgin_ctr = 1;
+				esp_advance_phase(SCptr, in_msgindone);
+				return esp_do_msgindone(esp, eregs, dregs);
+			}
+		} else {
+			/* With luck we'll be able to let the target
+			 * know that bad parity happened, it will know
+			 * which byte caused the problems and send it
+			 * again.  For the case where the status byte
+			 * receives bad parity, I do not believe most
+			 * targets recover very well.  We'll see.
+			 */
+			ESPLOG(("esp%d: bad parity somewhere mout=%2x\n",
+				esp->esp_id, message_out));
+			esp->cur_msgout[0] = message_out;
+			esp->msgout_len = esp->msgout_ctr = 1;
+			esp_advance_phase(SCptr, in_the_dark);
+			return esp_do_phase_determine(esp, eregs, dregs);
+		}
+	} else {
+		/* If we disconnect now, all hell breaks loose. */
+		ESPLOG(("esp%d: whoops, disconnect\n", esp->esp_id));
+		esp_advance_phase(SCptr, in_the_dark);
+		return esp_do_phase_determine(esp, eregs, dregs);
+	}
+}
+
+/* The target has control of the bus and we have to see where it has
+ * taken us.
+ */
+static int esp_do_phase_determine(struct Sparc_ESP *esp,
+				  struct Sparc_ESP_regs *eregs,
+				  struct sparc_dma_registers *dregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+
+	ESPPHASE(("esp_do_phase_determine: "));
+	if(!(esp->ireg & ESP_INTR_DC)) {
+		switch(esp->sreg & ESP_STAT_PMASK) {
+		case ESP_DOP:
+		case ESP_DIP:
+			ESPPHASE(("to data phase\n"));
+			return esp_do_data(esp, eregs, dregs);
+
+		case ESP_STATP:
+			/* Whee, status phase, finish up the command. */
+			ESPPHASE(("to status phase\n"));
+			esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+			if(esp->erev != fashme) {
+				esp->esp_command[0] = 0xff;
+				esp->esp_command[1] = 0xff;
+				eregs->esp_tclow = 2;
+				eregs->esp_tcmed = 0;
+				dregs->cond_reg |= (DMA_ST_WRITE | DMA_ENABLE);
+				if(esp->dma->revision == dvmaesc1)
+					dregs->cnt = 0x1000;
+				dregs->st_addr = esp->esp_command;
+				esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_ICCSEQ);
+			} else {
+				/* Using DVMA for status/message bytes is
+				 * unreliable on HME, nice job QLogic.
+				 * Happy Meal indeed....
+				 */
+				esp_cmd(esp, eregs, ESP_CMD_ICCSEQ);
+			}
+			esp_advance_phase(SCptr, in_status);
+			return esp_do_status(esp, eregs, dregs);
+
+		case ESP_MOP:
+			ESPPHASE(("to msgout phase\n"));
+			esp_advance_phase(SCptr, in_msgout);
+			return esp_do_msgout(esp, eregs, dregs);
+
+		case ESP_MIP:
+			ESPPHASE(("to msgin phase\n"));
+			esp_advance_phase(SCptr, in_msgin);
+			return esp_do_msgin(esp, eregs, dregs);
+
+		case ESP_CMDP:
+			/* Ugh, we're running a non-standard command the
+			 * ESP doesn't understand, one byte at a time.
+			 */
+			ESPPHASE(("to cmd phase\n"));
+			esp_advance_phase(SCptr, in_cmdbegin);
+			return esp_do_cmdbegin(esp, eregs, dregs);
+		};
+	} else {
+		Scsi_Device *dp = SCptr->device;
+
+		/* This means real problems if we see this
+		 * here.  Unless we were actually trying
+		 * to force the device to abort/reset.
+		 */
+		ESPLOG(("esp%d Disconnect amidst phases, ", esp->esp_id));
+		ESPLOG(("pphase<%s> cphase<%s>, ",
+			phase_string(SCptr->SCp.phase),
+			phase_string(SCptr->SCp.sent_command)));
+		if(esp->disconnected_SC || (esp->erev == fashme))
+			esp_cmd(esp, eregs, ESP_CMD_ESEL);
+
+		switch(esp->cur_msgout[0]) {
+		default:
+			/* We didn't expect this to happen at all. */
+			ESPLOG(("device is bolixed\n"));
+			esp_advance_phase(SCptr, in_tgterror);
+			safe_esp_done(esp, dregs, (DID_ERROR << 16));
+			break;
+
+		case BUS_DEVICE_RESET:
+			ESPLOG(("device reset successful\n"));
+			dp->sync_max_offset = 0;
+			dp->sync_min_period = 0;
+			dp->sync = 0;
+			esp_advance_phase(SCptr, in_resetdev);
+			safe_esp_done(esp, dregs, (DID_RESET << 16));
 			break;
+
+		case ABORT:
+			ESPLOG(("device abort successful\n"));
+			esp_advance_phase(SCptr, in_abortone);
+			safe_esp_done(esp, dregs, (DID_ABORT << 16));
+			break;
+
 		};
+		return do_intr_end;
+	}
 
-	case in_dataout:
-		dregs->cond_reg &= ~DMA_ENABLE;
+	ESPLOG(("esp%d: to unknown phase\n", esp->esp_id));
+	printk("esp%d: Bizarre bus phase %2x.\n", esp->esp_id,
+	       esp->sreg & ESP_STAT_PMASK);
+	return do_reset_bus;
+}
+
+/* First interrupt after exec'ing a cmd comes here. */
+static int esp_select_complete(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+			       struct sparc_dma_registers *dregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+	Scsi_Device *SDptr = SCptr->device;
+	int cmd_bytes_sent, fcnt;
+
+	if(esp->erev != fashme)
+		esp->seqreg = (eregs->esp_sstep & ESP_STEP_VBITS);
+	if(esp->erev == fashme)
+		fcnt = esp->hme_fifo_workaround_count;
+	else
+		fcnt = (eregs->esp_fflags & ESP_FF_FBYTES);
+	cmd_bytes_sent = esp_bytes_sent(esp, dregs, fcnt);
+	dma_invalidate(dregs, esp->dma->revision);
+
+	/* Let's check to see if a reselect happened
+	 * while we we're trying to select.  This must
+	 * be checked first.
+	 */
+	if(esp->ireg == (ESP_INTR_RSEL | ESP_INTR_FDONE)) {
+		esp_reconnect(esp, SCptr);
+		return esp_do_reconnect(esp, eregs, dregs);
+	}
 
-		/* We may be pipelining an sg-list. */
-		if(SCptr->use_sg) {
-			if(SCptr->SCp.buffers_residual) {
-				/* If we do not see a BUS SERVICE interrupt
-				 * at this point, or we see that we have left
-				 * the current data phase, then we lose.
+	/* Looks like things worked, we should see a bus service &
+	 * a function complete interrupt at this point.  Note we
+	 * are doing a direct comparison because we don't want to
+	 * be fooled into thinking selection was successful if
+	 * ESP_INTR_DC is set, see below.
+	 */
+	if(esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) {
+		/* target speaks... */
+		esp->targets_present |= (1<<SCptr->target);
+
+		/* What if the target ignores the sdtr? */
+		if(esp->snip)
+			SDptr->sync = 1;
+
+		/* See how far, if at all, we got in getting
+		 * the information out to the target.
+		 */
+		switch(esp->seqreg) {
+		default:
+
+		case ESP_STEP_ASEL:
+			/* Arbitration won, target selected, but
+			 * we are in some phase which is not command
+			 * phase nor is it message out phase.
+			 *
+			 * XXX We've confused the target, obviously.
+			 * XXX So clear it's state, but we also end
+			 * XXX up clearing everyone elses.  That isn't
+			 * XXX so nice.  I'd like to just reset this
+			 * XXX target, but if I cannot even get it's
+			 * XXX attention and finish selection to talk
+			 * XXX to it, there is not much more I can do.
+			 * XXX If we have a loaded bus we're going to
+			 * XXX spend the next second or so renegotiating
+			 * XXX for synchronous transfers.
+			 */
+			ESPLOG(("esp%d: STEP_ASEL for tgt %d\n",
+				esp->esp_id, SCptr->target));
+
+		case ESP_STEP_SID:
+			/* Arbitration won, target selected, went
+			 * to message out phase, sent one message
+			 * byte, then we stopped.  ATN is asserted
+			 * on the SCSI bus and the target is still
+			 * there hanging on.  This is a legal
+			 * sequence step if we gave the ESP a select
+			 * and stop command.
+			 *
+			 * XXX See above, I could set the borken flag
+			 * XXX in the device struct and retry the
+			 * XXX command.  But would that help for
+			 * XXX tagged capable targets?
+			 */
+
+		case ESP_STEP_NCMD:
+			/* Arbitration won, target selected, maybe
+			 * sent the one message byte in message out
+			 * phase, but we did not go to command phase
+			 * in the end.  Actually, we could have sent
+			 * only some of the message bytes if we tried
+			 * to send out the entire identify and tag
+			 * message using ESP_CMD_SA3.
+			 */
+			cmd_bytes_sent = 0;
+			break;
+
+		case ESP_STEP_PPC:
+			/* No, not the powerPC pinhead.  Arbitration
+			 * won, all message bytes sent if we went to
+			 * message out phase, went to command phase
+			 * but only part of the command was sent.
+			 *
+			 * XXX I've seen this, but usually in conjunction
+			 * XXX with a gross error which appears to have
+			 * XXX occurred between the time I told the
+			 * XXX ESP to arbitrate and when I got the
+			 * XXX interrupt.  Could I have misloaded the
+			 * XXX command bytes into the fifo?  Actually,
+			 * XXX I most likely missed a phase, and therefore
+			 * XXX went into never never land and didn't even
+			 * XXX know it.  That was the old driver though.
+			 * XXX What is even more peculiar is that the ESP
+			 * XXX showed the proper function complete and
+			 * XXX bus service bits in the interrupt register.
+			 */
+
+		case ESP_STEP_FINI4:
+		case ESP_STEP_FINI5:
+		case ESP_STEP_FINI6:
+		case ESP_STEP_FINI7:
+			/* Account for the identify message */
+			if(SCptr->SCp.phase == in_slct_norm)
+				cmd_bytes_sent -= 1;
+		};
+		if(esp->erev != fashme)
+			esp_cmd(esp, eregs, ESP_CMD_NULL);
+
+		/* Be careful, we could really get fucked during synchronous
+		 * data transfers if we try to flush the fifo now.
+		 */
+		if((esp->erev != fashme) && /* not a Happy Meal and... */
+		   !fcnt && /* Fifo is empty and... */
+		   /* either we are not doing synchronous transfers or... */
+		   (!SDptr->sync_max_offset ||
+		    /* We are not going into data in phase. */
+		    ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP)))
+			esp_cmd(esp, eregs, ESP_CMD_FLUSH); /* flush is safe */
+
+		/* See how far we got if this is not a slow command. */
+		if(!esp->esp_slowcmd) {
+			if(cmd_bytes_sent < 0)
+				cmd_bytes_sent = 0;
+			if(cmd_bytes_sent != SCptr->cmd_len) {
+				/* Crapola, mark it as a slowcmd
+				 * so that we have some chance of
+				 * keeping the command alive with
+				 * good luck.
+				 *
+				 * XXX Actually, if we didn't send it all
+				 * XXX this means either we didn't set things
+				 * XXX up properly (driver bug) or the target
+				 * XXX or the ESP detected parity on one of
+				 * XXX the command bytes.  This makes much
+				 * XXX more sense, and therefore this code
+				 * XXX should be changed to send out a
+				 * XXX parity error message or if the status
+				 * XXX register shows no parity error then
+				 * XXX just expect the target to bring the
+				 * XXX bus into message in phase so that it
+				 * XXX can send us the parity error message.
+				 * XXX SCSI sucks...
 				 */
-				if(!(esp->ireg & ESP_INTR_BSERV) ||
-				   ((esp->sreg & ESP_STAT_PMASK) > 1))
-					panic("esp: Aiee penguin on the SCSI-bus.");
-
-				++SCptr->SCp.buffer;
-				--SCptr->SCp.buffers_residual;
-				SCptr->SCp.this_residual = SCptr->SCp.buffer->length;
-				SCptr->SCp.ptr = SCptr->SCp.buffer->alt_address;
+				esp->esp_slowcmd = 1;
+				esp->esp_scmdp = &(SCptr->cmnd[cmd_bytes_sent]);
+				esp->esp_scmdleft = (SCptr->cmd_len - cmd_bytes_sent);
+			}
+		}
 
-#ifdef DEBUG_ESP_SG
-				printk("<%p,%d> ", SCptr->SCp.ptr,
-				       SCptr->SCp.this_residual);
-#endif
+		/* Now figure out where we went. */
+		esp_advance_phase(SCptr, in_the_dark);
+		return esp_do_phase_determine(esp, eregs, dregs);
+	}
+
+	/* Did the target even make it? */
+	if(esp->ireg == ESP_INTR_DC) {
+		/* wheee... nobody there or they didn't like
+		 * what we told it to do, clean up.
+		 */
+
+		/* If anyone is off the bus, but working on
+		 * a command in the background for us, tell
+		 * the ESP to listen for them.
+		 */
+		if(esp->disconnected_SC)
+			esp_cmd(esp, eregs, ESP_CMD_ESEL);
+
+		if(((1<<SCptr->target) & esp->targets_present) &&
+		   esp->seqreg && esp->cur_msgout[0] == EXTENDED_MESSAGE &&
+		   (SCptr->SCp.phase == in_slct_msg ||
+		    SCptr->SCp.phase == in_slct_stop)) {
+			/* shit */
+			esp->snip = 0;
+			printk("esp%d: Failed synchronous negotiation for target %d "
+			       "lun %d\n",
+			       esp->esp_id, SCptr->target, SCptr->lun);
+			SDptr->sync_max_offset = 0;
+			SDptr->sync_min_period = 0;
+			SDptr->sync = 1; /* so we dont negotiate again */
+
+			/* Run the command again, this time though we
+			 * won't try to negotiate for synchronous transfers.
+			 *
+			 * XXX I'd like to do something like send an
+			 * XXX INITIATOR_ERROR or ABORT message to the
+			 * XXX target to tell it, "Sorry I confused you,
+			 * XXX please come back and I will be nicer next
+			 * XXX time".  But that requires having the target
+			 * XXX on the bus, and it has dropped BSY on us.
+			 */
+			esp->current_SC = NULL;
+			esp_advance_phase(SCptr, not_issued);
+			prepend_SC(&esp->issue_SC, SCptr);
+			esp_exec_cmd(esp);
+			return do_intr_end;
+		}
 
-				/* Latch in new esp counters... */
-				eregs->esp_tclow = SCptr->SCp.this_residual;
-				eregs->esp_tcmed = (SCptr->SCp.this_residual>>8);
-				eregs->esp_cmd = (ESP_CMD_DMA | ESP_CMD_NULL);
-
-				/* Reload DVMA gate array with new vaddr and enab. */
-				dregs->st_addr = SCptr->SCp.ptr;
-				dregs->cond_reg |= DMA_ENABLE;
+		/* Ok, this is normal, this is what we see during boot
+		 * or whenever when we are scanning the bus for targets.
+		 * But first make sure that is really what is happening.
+		 */
+		if(((1<<SCptr->target) & esp->targets_present)) {
+			printk("esp%d: Warning, live target %d not responding to "
+			       "selection.\n", esp->esp_id, SCptr->target);
+
+			/* This _CAN_ happen.  The SCSI standard states that
+			 * the target is to _not_ respond to selection if
+			 * _it_ detects bad parity on the bus for any reason.
+			 * Therefore, we assume that if we've talked successfully
+			 * to this target before, bad parity is the problem.
+			 */
+			safe_esp_done(esp, dregs, (DID_PARITY << 16));
+		} else {
+			/* Else, there really isn't anyone there. */
+			ESPMISC(("esp: selection failure, maybe nobody there?\n"));
+			ESPMISC(("esp: target %d lun %d\n",
+				 SCptr->target, SCptr->lun));
+			safe_esp_done(esp, dregs, (DID_BAD_TARGET << 16));
+		}
+		return do_intr_end;
+	}
 
-				/* Tell the esp to start transferring. */
-				eregs->esp_cmd = (ESP_CMD_DMA | ESP_CMD_TI);
-				goto esp_handle_done;
+
+	ESPLOG(("esp%d: Selection failure.\n", esp->esp_id));
+	printk("esp%d: Currently -- ", esp->esp_id);
+	esp_print_ireg(esp->ireg);
+	printk(" ");
+	esp_print_statreg(esp->sreg);
+	printk(" ");
+	esp_print_seqreg(esp->seqreg);
+	printk("\n");
+	printk("esp%d: New -- ", esp->esp_id);
+	esp->sreg = eregs->esp_status;
+	esp->seqreg = eregs->esp_sstep;
+	esp->ireg = eregs->esp_intrpt;
+	esp_print_ireg(esp->ireg);
+	printk(" ");
+	esp_print_statreg(esp->sreg);
+	printk(" ");
+	esp_print_seqreg(esp->seqreg);
+	printk("\n");
+	ESPLOG(("esp%d: resetting bus\n", esp->esp_id));
+	return do_reset_bus; /* ugh... */
+}
+
+/* Continue reading bytes for msgin phase. */
+static int esp_do_msgincont(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+			    struct sparc_dma_registers *dregs)
+{
+	if(esp->ireg & ESP_INTR_BSERV) {
+		/* in the right phase too? */
+		if((esp->sreg & ESP_STAT_PMASK) == ESP_MIP) {
+			/* phew... */
+			esp_cmd(esp, eregs, ESP_CMD_TI);
+			esp_advance_phase(esp->current_SC, in_msgindone);
+			return do_intr_end;
+		}
+
+		/* We changed phase but ESP shows bus service,
+		 * in this case it is most likely that we, the
+		 * hacker who has been up for 20hrs straight
+		 * staring at the screen, drowned in coffee
+		 * smelling like retched cigarette ashes
+		 * have miscoded something..... so, try to
+		 * recover as best we can.
+		 */
+		printk("esp%d: message in mis-carriage.\n", esp->esp_id);
+	}
+	esp_advance_phase(esp->current_SC, in_the_dark);
+	return do_phase_determine;
+}
+
+static inline int check_singlebyte_msg(struct Sparc_ESP *esp,
+				       struct Sparc_ESP_regs *eregs,
+				       struct sparc_dma_registers *dregs)
+{
+	esp->prevmsgin = esp->cur_msgin[0];
+	if(esp->cur_msgin[0] & 0x80) {
+		/* wheee... */
+		ESPLOG(("esp%d: target sends identify amidst phases\n",
+			esp->esp_id));
+		esp_advance_phase(esp->current_SC, in_the_dark);
+		return 0;
+	} else if(((esp->cur_msgin[0] & 0xf0) == 0x20) ||
+		  (esp->cur_msgin[0] == EXTENDED_MESSAGE)) {
+		esp->msgin_len = 2;
+		esp_advance_phase(esp->current_SC, in_msgincont);
+		return 0;
+	}
+	esp_advance_phase(esp->current_SC, in_the_dark);
+	switch(esp->cur_msgin[0]) {
+	default:
+		/* We don't want to hear about it. */
+		ESPLOG(("esp%d: msg %02x which we dont know about\n", esp->esp_id,
+			esp->cur_msgin[0]));
+		return MESSAGE_REJECT;
+
+	case NOP:
+		ESPLOG(("esp%d: target %d sends a nop\n", esp->esp_id,
+			esp->current_SC->target));
+		return 0;
+
+	case RESTORE_POINTERS:
+	case SAVE_POINTERS:
+		/* We handle this all automatically. */
+		return 0;
+
+	case COMMAND_COMPLETE:
+	case DISCONNECT:
+		/* Freeing the bus, let it go. */
+		esp->current_SC->SCp.phase = in_freeing;
+		return 0;
+
+	case MESSAGE_REJECT:
+		ESPMISC(("msg reject, "));
+		if(esp->prevmsgout == EXTENDED_MESSAGE) {
+			Scsi_Device *SDptr = esp->current_SC->device;
+
+			/* Doesn't look like this target can
+			 * do synchronous or WIDE transfers.
+			 */
+			ESPSDTR(("got reject, was trying nego, clearing sync/WIDE\n"));
+			SDptr->sync = 1;
+			SDptr->wide = 1;
+			SDptr->sync_min_period = 0;
+			SDptr->sync_max_offset = 0;
+			return 0;
+		} else {
+			ESPMISC(("not sync nego, sending ABORT\n"));
+			return ABORT;
+		}
+	};
+}
+
+/* Target negotiates for synchronous transfers before we do, this
+ * is legal although very strange.  What is even funnier is that
+ * the SCSI2 standard specifically recommends against targets doing
+ * this because so many initiators cannot cope with this occuring.
+ */
+static inline int target_with_ants_in_pants(struct Sparc_ESP *esp,
+					    Scsi_Cmnd *SCptr,
+					    Scsi_Device *SDptr)
+{
+	if(SDptr->sync || SDptr->borken) {
+		/* sorry, no can do */
+		ESPSDTR(("forcing to async, "));
+		build_sync_nego_msg(esp, 0, 0);
+		SDptr->sync = 1;
+		esp->snip = 1;
+		ESPLOG(("esp%d: hoping for msgout\n", esp->esp_id));
+		esp_advance_phase(SCptr, in_the_dark);
+		return EXTENDED_MESSAGE;
+	}
+
+	/* Ok, we'll check them out... */
+	return 0;
+}
+
+static inline void sync_report(struct Sparc_ESP *esp)
+{
+	int msg3, msg4;
+	char *type;
+
+	msg3 = esp->cur_msgin[3];
+	msg4 = esp->cur_msgin[4];
+	if(msg4) {
+		int hz = 1000000000 / (msg3 * 4);
+		int integer = hz / 1000000;
+		int fraction = (hz - (integer * 1000000)) / 10000;
+		if((esp->erev == fashme) &&
+		   (esp->config3[esp->current_SC->target] & ESP_CONFIG3_EWIDE)) {
+			type = "FAST-WIDE";
+			integer <<= 1;
+			fraction <<= 1;
+		} else if((msg3 * 4) < 200) {
+			type = "FAST";
+		} else {
+			type = "synchronous";
+		}
+		printk(KERN_INFO "esp%d: target %d [period %dns offset %d %d.%02dMHz %s SCSI%s]\n",
+		       esp->esp_id, esp->current_SC->target,
+		       (int) msg3 * 4,
+		       (int) msg4,
+		       integer, fraction, type,
+		       (((msg3 * 4) < 200) ? "-II" : ""));
+	} else {
+		printk(KERN_INFO "esp%d: target %d asynchronous\n",
+		       esp->esp_id, esp->current_SC->target);
+	}
+}
+
+static inline int check_multibyte_msg(struct Sparc_ESP *esp,
+				       struct Sparc_ESP_regs *eregs,
+				       struct sparc_dma_registers *dregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+	Scsi_Device *SDptr = SCptr->device;
+	unchar regval = 0;
+	int message_out = 0;
+
+	ESPSDTR(("chk multibyte msg: "));
+	if(esp->cur_msgin[2] == EXTENDED_SDTR) {
+		int period = esp->cur_msgin[3];
+		int offset = esp->cur_msgin[4];
+
+		ESPSDTR(("is sync nego response, "));
+		if(!esp->snip) {
+			int rval;
+
+			/* Target negotiates first! */
+			ESPSDTR(("target jumps the gun, "));
+			message_out = EXTENDED_MESSAGE; /* we must respond */
+			rval = target_with_ants_in_pants(esp, SCptr, SDptr);
+			if(rval)
+				return rval;
+		}
+
+		ESPSDTR(("examining sdtr, "));
+
+		/* Offset cannot be larger than ESP fifo size. */
+		if(offset > 15) {
+			ESPSDTR(("offset too big %2x, ", offset));
+			offset = 15;
+			ESPSDTR(("sending back new offset\n"));
+			build_sync_nego_msg(esp, period, offset);
+			return EXTENDED_MESSAGE;
+		}
+
+		if(offset && period > esp->max_period) {
+			/* Yeee, async for this slow device. */
+			ESPSDTR(("period too long %2x, ", period));
+			build_sync_nego_msg(esp, 0, 0);
+			ESPSDTR(("hoping for msgout\n"));
+			esp_advance_phase(esp->current_SC, in_the_dark);
+			return EXTENDED_MESSAGE;
+		} else if (offset && period < esp->min_period) {
+			ESPSDTR(("period too short %2x, ", period));
+			period = esp->min_period;
+			if(esp->erev > esp236)
+				regval = 4;
+			else
+				regval = 5;
+		} else if(offset) {
+			int tmp;
+
+			ESPSDTR(("period is ok, "));
+			tmp = esp->ccycle / 1000;
+			regval = (((period << 2) + tmp - 1) / tmp);
+			if(regval && ((esp->erev == fas100a ||
+				       esp->erev == fas236 ||
+				       esp->erev == fashme))) {
+				if(period >= 50)
+					regval--;
 			}
-#ifdef DEBUG_ESP_SG
-			printk("done.\n");
-#endif
 		}
-		/* Take a look at what happened. */
-		if(esp->ireg & ESP_INTR_DC) {
-			panic("esp: target disconnects during data transfer.");
-			goto esp_handle_done;
-		} else if(esp->ireg & ESP_INTR_BSERV) {
-			if((esp->sreg & ESP_STAT_PMASK) != ESP_STATP) {
-				panic("esp: Not status phase after data phase.");
-				goto esp_handle_done;
+
+		if(offset) {
+			unchar bit;
+
+			SDptr->sync_min_period = (regval & 0x1f);
+			SDptr->sync_max_offset = (offset | esp->radelay);
+			if((esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme)) {
+				if((esp->erev == fas100a) || (esp->erev == fashme))
+					bit = ESP_CONFIG3_FAST;
+				else
+					bit = ESP_CONFIG3_FSCSI;
+				if(period < 50)
+					esp->config3[SCptr->target] |= bit;
+				else
+					esp->config3[SCptr->target] &= ~bit;
+				eregs->esp_cfg3 = esp->config3[SCptr->target];
 			}
-			SCptr->SCp.phase = in_status;
-			eregs->esp_cmd = ESP_CMD_ICCSEQ;
-			ETRACE(("STATUS\n"));
-			goto esp_handle_done; /* Wait for message. */
-		} else {
-			printk("esp: did not get bus service after data transfer.");
-			printk("esp_status: intr<%2x> stat<%2x> seq<%2x>\n",
-			       esp->ireg, esp->sreg, esp->seqreg);
-			panic("esp: penguin data transfer.");
-			goto esp_handle_done;
+			eregs->esp_soff = SDptr->sync_min_period;
+			eregs->esp_stp  = SDptr->sync_max_offset;
+
+			ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n",
+				SDptr->sync_max_offset,
+				SDptr->sync_min_period,
+				esp->config3[SCptr->target]));
+
+			esp->snip = 0;
+		} else if(SDptr->sync_max_offset) {
+			unchar bit;
+
+			/* back to async mode */
+			ESPSDTR(("unaccaptable sync nego, forcing async\n"));
+			SDptr->sync_max_offset = 0;
+			SDptr->sync_min_period = 0;
+			eregs->esp_soff = 0;
+			eregs->esp_stp = 0;
+			if((esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme)) {
+				if((esp->erev == fas100a) || (esp->erev == fashme))
+					bit = ESP_CONFIG3_FAST;
+				else
+					bit = ESP_CONFIG3_FSCSI;
+				esp->config3[SCptr->target] &= ~bit;
+				eregs->esp_cfg3 = esp->config3[SCptr->target];
+			}
+		}
+
+		sync_report(esp);
+
+		ESPSDTR(("chk multibyte msg: sync is known, "));
+		SDptr->sync = 1;
+
+		if(message_out) {
+			ESPLOG(("esp%d: sending sdtr back, hoping for msgout\n",
+				esp->esp_id));
+			build_sync_nego_msg(esp, period, offset);
+			esp_advance_phase(SCptr, in_the_dark);
+			return EXTENDED_MESSAGE;
+		}
+
+		ESPSDTR(("returning zero\n"));
+		esp_advance_phase(SCptr, in_the_dark); /* ...or else! */
+		return 0;
+	} else if(esp->cur_msgin[2] == EXTENDED_WDTR) {
+		int size = 8 << esp->cur_msgin[3];
+
+		esp->wnip = 0;
+		if(esp->erev != fashme) {
+			printk("esp%d: AIEEE wide msg received and not HME.\n",
+			       esp->esp_id);
+			message_out = MESSAGE_REJECT;
+		} else if(size > 16) {
+			printk("esp%d: AIEEE wide transfer for %d size not supported.\n",
+			       esp->esp_id, size);
+			message_out = MESSAGE_REJECT;
+		} else {
+			/* Things look good, lets see what we got. */
+			if(size == 16) {
+				/* Set config 3 register for this target. */
+				printk("esp%d: 16 byte WIDE transfers enabled for target %d.\n",
+				       esp->esp_id, SCptr->target);
+				esp->config3[SCptr->target] |= ESP_CONFIG3_EWIDE;
+			} else {
+				/* Just make sure it was one byte sized. */
+				if(size != 8) {
+					printk("esp%d: Aieee, wide nego of %d size.\n",
+					       esp->esp_id, size);
+					message_out = MESSAGE_REJECT;
+					goto finish;
+				}
+				/* Pure paranoia. */
+				esp->config3[SCptr->target] &= ~(ESP_CONFIG3_EWIDE);
+			}
+			eregs->esp_cfg3 = esp->config3[SCptr->target];
+
+			/* Regardless, next try for sync transfers. */
+			build_sync_nego_msg(esp, esp->sync_defp, 15);
+			SDptr->sync = 1;
+			esp->snip = 1;
+			message_out = EXTENDED_MESSAGE;
+		}
+	} else if(esp->cur_msgin[2] == EXTENDED_MODIFY_DATA_POINTER) {
+		ESPLOG(("esp%d: rejecting modify data ptr msg\n", esp->esp_id));
+		message_out = MESSAGE_REJECT;
+	}
+finish:
+	esp_advance_phase(SCptr, in_the_dark);
+	return message_out;
+}
+
+static int esp_do_msgindone(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+			    struct sparc_dma_registers *dregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+	int message_out = 0, it = 0, rval;
+
+	rval = skipahead1(esp, eregs, dregs, SCptr, in_msgin, in_msgindone);
+	if(rval)
+		return rval;
+	if(SCptr->SCp.sent_command != in_status) {
+		if(!(esp->ireg & ESP_INTR_DC)) {
+			if(esp->msgin_len && (esp->sreg & ESP_STAT_PERR)) {
+				message_out = MSG_PARITY_ERROR;
+				esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+			} else if(esp->erev != fashme &&
+				  (it = (eregs->esp_fflags & ESP_FF_FBYTES))!=1) {
+				/* We certainly dropped the ball somewhere. */
+				message_out = INITIATOR_ERROR;
+				esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+			} else if(!esp->msgin_len) {
+				if(esp->erev == fashme)
+					it = esp->hme_fifo_workaround_buffer[0];
+				else
+					it = eregs->esp_fdata;
+				esp_advance_phase(SCptr, in_msgincont);
+			} else {
+				/* it is ok and we want it */
+				if(esp->erev == fashme)
+					it = esp->cur_msgin[esp->msgin_ctr] =
+						esp->hme_fifo_workaround_buffer[0];
+				else
+					it = esp->cur_msgin[esp->msgin_ctr] =
+						eregs->esp_fdata;
+				esp->msgin_ctr++;
+			}
+		} else {
+			esp_advance_phase(SCptr, in_the_dark);
+			return do_work_bus;
+		}
+	} else {
+		it = esp->cur_msgin[0];
+	}
+	if(!message_out && esp->msgin_len) {
+		if(esp->msgin_ctr < esp->msgin_len) {
+			esp_advance_phase(SCptr, in_msgincont);
+		} else if(esp->msgin_len == 1) {
+			message_out = check_singlebyte_msg(esp, eregs, dregs);
+		} else if(esp->msgin_len == 2) {
+			if(esp->cur_msgin[0] == EXTENDED_MESSAGE) {
+				if((it+2) >= 15) {
+					message_out = MESSAGE_REJECT;
+				} else {
+					esp->msgin_len = (it + 2);
+					esp_advance_phase(SCptr, in_msgincont);
+				}
+			} else {
+				message_out = MESSAGE_REJECT; /* foo on you */
+			}
+		} else {
+			message_out = check_multibyte_msg(esp, eregs, dregs);
+		}
+	}
+	if(message_out < 0) {
+		return -message_out;
+	} else if(message_out) {
+		if(((message_out != 1) &&
+		    ((message_out < 0x20) || (message_out & 0x80))))
+			esp->msgout_len = 1;
+		esp->cur_msgout[0] = message_out;
+		esp_cmd(esp, eregs, ESP_CMD_SATN);
+		esp_advance_phase(SCptr, in_the_dark);
+		esp->msgin_len = 0;
+	}
+	esp->sreg = eregs->esp_status;
+	esp->sreg &= ~(ESP_STAT_INTR);
+	if((esp->sreg & (ESP_STAT_PMSG|ESP_STAT_PCD)) == (ESP_STAT_PMSG|ESP_STAT_PCD))
+		esp_cmd(esp, eregs, ESP_CMD_MOK);
+	if((SCptr->SCp.sent_command == in_msgindone) &&
+	    (SCptr->SCp.phase == in_freeing))
+		return esp_do_freebus(esp, eregs, dregs);
+	return do_intr_end;
+}
+
+static int esp_do_cmdbegin(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+			   struct sparc_dma_registers *dregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+
+	esp_advance_phase(SCptr, in_cmdend);
+	if(esp->erev == fashme) {
+		unsigned long tmp = dregs->cond_reg;
+		int i;
+
+		for(i = 0; i < esp->esp_scmdleft; i++)
+			esp->esp_command[i] = *esp->esp_scmdp++;
+		esp->esp_scmdleft = 0;
+		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+		esp_setcount(eregs, i, 1);
+		esp_cmd(esp, eregs, (ESP_CMD_DMA | ESP_CMD_TI));
+		tmp |= (DMA_SCSI_DISAB | DMA_ENABLE);
+		tmp &= ~(DMA_ST_WRITE);
+		dregs->cnt = i;
+		dregs->st_addr = &esp->esp_command[0];
+		dregs->cond_reg = tmp;
+	} else {
+		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+		eregs->esp_fdata = *esp->esp_scmdp++;
+		esp->esp_scmdleft--;
+		esp_cmd(esp, eregs, ESP_CMD_TI);
+	}
+	return do_intr_end;
+}
+
+static inline int esp_do_cmddone(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+				 struct sparc_dma_registers *dregs)
+{
+	if(esp->erev == fashme)
+		dma_invalidate(dregs, dvmahme);
+	else
+		esp_cmd(esp, eregs, ESP_CMD_NULL);
+	if(esp->ireg & ESP_INTR_BSERV) {
+		esp_advance_phase(esp->current_SC, in_the_dark);
+		return esp_do_phase_determine(esp, eregs, dregs);
+	}
+	ESPLOG(("esp%d: in do_cmddone() but didn't get BSERV interrupt.\n",
+		esp->esp_id));
+	return do_reset_bus;
+}
+
+static int esp_do_msgout(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+				struct sparc_dma_registers *dregs)
+{
+	esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+	switch(esp->msgout_len) {
+	case 1:
+		if(esp->erev == fashme)
+			hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 1);
+		else
+			eregs->esp_fdata = esp->cur_msgout[0];
+		esp_cmd(esp, eregs, ESP_CMD_TI);
+		break;
+
+	case 2:
+		esp->esp_command[0] = esp->cur_msgout[0];
+		esp->esp_command[1] = esp->cur_msgout[1];
+		if(esp->erev == fashme) {
+			hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 2);
+			esp_cmd(esp, eregs, ESP_CMD_TI);
+		} else {
+			dma_setup(dregs, esp->dma->revision,
+				  (char *) esp->esp_command, 2, 0);
+			esp_setcount(eregs, 2, 0);
+			esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+		}
+		break;
+
+	case 4:
+		esp->esp_command[0] = esp->cur_msgout[0];
+		esp->esp_command[1] = esp->cur_msgout[1];
+		esp->esp_command[2] = esp->cur_msgout[2];
+		esp->esp_command[3] = esp->cur_msgout[3];
+		esp->snip = 1;
+		if(esp->erev == fashme) {
+			hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 4);
+			esp_cmd(esp, eregs, ESP_CMD_TI);
+		} else {
+			dma_setup(dregs, esp->dma->revision,
+				  (char *) esp->esp_command, 4, 0);
+			esp_setcount(eregs, 4, 0);
+			esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
 		}
+		break;
+
+	case 5:
+		esp->esp_command[0] = esp->cur_msgout[0];
+		esp->esp_command[1] = esp->cur_msgout[1];
+		esp->esp_command[2] = esp->cur_msgout[2];
+		esp->esp_command[3] = esp->cur_msgout[3];
+		esp->esp_command[4] = esp->cur_msgout[4];
+		esp->snip = 1;
+		if(esp->erev == fashme) {
+			hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 5);
+			esp_cmd(esp, eregs, ESP_CMD_TI);
+		} else {
+			dma_setup(dregs, esp->dma->revision,
+				  (char *) esp->esp_command, 5, 0);
+			esp_setcount(eregs, 5, 0);
+			esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+		}
+		break;
+
+	default:
+		/* whoops */
+		ESPMISC(("bogus msgout sending NOP\n"));
+		esp->cur_msgout[0] = NOP;
+		if(esp->erev == fashme) {
+			hme_fifo_push(esp, eregs, &esp->cur_msgout[0], 1);
+		} else {
+			eregs->esp_fdata = esp->cur_msgout[0];
+		}
+		esp->msgout_len = 1;
+		esp_cmd(esp, eregs, ESP_CMD_TI);
+		break;
+	}
+	esp_advance_phase(esp->current_SC, in_msgoutdone);
+	return do_intr_end;
+}
+
+static inline int esp_do_msgoutdone(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+				    struct sparc_dma_registers *dregs)
+{
+	if(esp->msgout_len > 1) {
+		/* XXX HME/FAS ATN deassert workaround required,
+		 * XXX no DMA flushing, only possible ESP_CMD_FLUSH
+		 * XXX to kill the fifo.
+		 */
+		if(esp->erev != fashme) {
+			while(dregs->cond_reg & DMA_PEND_READ)
+				udelay(1);
+			dregs->cond_reg &= ~(DMA_ENABLE);
+			dma_invalidate(dregs, esp->dma->revision);
+		} else {
+			esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+		}
+	}
+	if(!(esp->ireg & ESP_INTR_DC)) {
+		if(esp->erev != fashme)
+			esp_cmd(esp, eregs, ESP_CMD_NULL);
+		switch(esp->sreg & ESP_STAT_PMASK) {
+		case ESP_MOP:
+			/* whoops, parity error */
+			ESPLOG(("esp%d: still in msgout, parity error assumed\n",
+				esp->esp_id));
+			if(esp->msgout_len > 1)
+				esp_cmd(esp, eregs, ESP_CMD_SATN);
+			esp_advance_phase(esp->current_SC, in_msgout);
+			return do_work_bus;
+
+		case ESP_DIP:
+			break;
+
+		default:
+			/* Happy Meal fifo is touchy... */
+			if((esp->erev != fashme) &&
+			   !fcount(esp, eregs) &&
+			   !(esp->current_SC->device->sync_max_offset))
+				esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+			break;
+
+		};
+	} else {
+		ESPLOG(("esp%d: disconnect, resetting bus\n", esp->esp_id));
+		return do_reset_bus;
+	}
+
+	/* If we sent out a synchronous negotiation message, update
+	 * our state.
+	 */
+	if(esp->cur_msgout[2] == EXTENDED_MESSAGE &&
+	   esp->cur_msgout[4] == EXTENDED_SDTR) {
+		esp->snip = 1; /* anal retentiveness... */
+	}
+
+	esp->prevmsgout = esp->cur_msgout[0];
+	esp->msgout_len = 0;
+	esp_advance_phase(esp->current_SC, in_the_dark);
+	return esp_do_phase_determine(esp, eregs, dregs);
+}
+
+/* This is the second tier in our dual-level SCSI state machine. */
+static inline int esp_work_bus(struct Sparc_ESP *esp, struct Sparc_ESP_regs *eregs,
+			       struct sparc_dma_registers *dregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+
+	ESPBUS(("esp_work_bus: "));
+	if(!SCptr) {
+		ESPBUS(("reconnect\n"));
+		return esp_do_reconnect(esp, eregs, dregs);
+	}
+
+	switch(SCptr->SCp.phase) {
+	case in_the_dark:
+		ESPBUS(("in the dark\n"));
+		return esp_do_phase_determine(esp, eregs, dregs);
+
+	case in_slct_norm:
+	case in_slct_stop:
+	case in_slct_msg:
+	case in_slct_tag:
+	case in_slct_sneg:
+		ESPBUS(("finish selection\n"));
+		return esp_select_complete(esp, eregs, dregs);
+
+	case in_datain:
+	case in_dataout:
+		ESPBUS(("finish data\n"));
+		return esp_do_data_finale(esp, eregs, dregs);
+
+	case in_msgout:
+		ESPBUS(("message out "));
+		return esp_do_msgout(esp, eregs, dregs);
+
+	case in_msgoutdone:
+		ESPBUS(("finish message out "));
+		return esp_do_msgoutdone(esp, eregs, dregs);
+
+	case in_msgin:
+		ESPBUS(("message in "));
+		return esp_do_msgin(esp, eregs, dregs);
+
+	case in_msgincont:
+		ESPBUS(("continue message in "));
+		return esp_do_msgincont(esp, eregs, dregs);
+
+	case in_msgindone:
+		ESPBUS(("finish message in "));
+		return esp_do_msgindone(esp, eregs, dregs);
+
 	case in_status:
-		if(esp->ireg & ESP_INTR_DC) {
-			panic("esp: penguin disconnects in status phase.");
-			goto esp_handle_done;
-		} else if (esp->ireg & ESP_INTR_FDONE) {
-			/* Status and Message now sit in the fifo for us. */
-			last_fflags = eregs->esp_fflags;
-			SCptr->SCp.phase   = in_finale;
-			last_status = SCptr->SCp.Status  = eregs->esp_fdata;
-			last_msg = SCptr->SCp.Message = eregs->esp_fdata;
-			eregs->esp_cmd = ESP_CMD_MOK;
-			ETRACE(("FINALE\n"));
-			goto esp_handle_done;
+		ESPBUS(("status phase "));
+		return esp_do_status(esp, eregs, dregs);
+
+	case in_freeing:
+		ESPBUS(("freeing the bus "));
+		return esp_do_freebus(esp, eregs, dregs);
+
+	case in_cmdbegin:
+		ESPBUS(("begin slow cmd "));
+		return esp_do_cmdbegin(esp, eregs, dregs);
+
+	case in_cmdend:
+		ESPBUS(("end slow cmd "));
+		return esp_do_cmddone(esp, eregs, dregs);
+
+	default:
+		printk("esp%d: command in weird state %2x\n",
+		       esp->esp_id, esp->current_SC->SCp.phase);
+		return do_reset_bus;
+	};
+}
+
+/* Main interrupt handler for an esp adapter. */
+static inline void esp_handle(struct Sparc_ESP *esp)
+{
+	struct sparc_dma_registers *dregs;
+	struct Sparc_ESP_regs *eregs;
+	Scsi_Cmnd *SCptr;
+	int what_next = do_intr_end;
+
+	eregs = esp->eregs;
+	dregs = esp->dregs;
+	SCptr = esp->current_SC;
+
+	DMA_IRQ_ENTRY(esp->dma, dregs);
+
+	/* Check for errors. */
+	esp->sreg = eregs->esp_status;
+	esp->sreg &= (~ESP_STAT_INTR);
+	if(esp->erev == fashme) {
+		esp->sreg2 = eregs->esp_status2;
+		esp->seqreg = (eregs->esp_sstep & ESP_STEP_VBITS);
+	}
+	if(esp->sreg & (ESP_STAT_SPAM)) {
+		/* Gross error, could be due to one of:
+		 *
+		 * - top of fifo overwritten, could be because
+		 *   we tried to do a synchronous transfer with
+		 *   an offset greater than ESP fifo size
+		 *
+		 * - top of command register overwritten
+		 *
+		 * - DMA setup to go in one direction, SCSI
+		 *   bus points in the other, whoops
+		 *
+		 * - weird phase change during asynchronous
+		 *   data phase while we are initiator
+		 */
+		ESPLOG(("esp%d: Gross error sreg=%2x\n", esp->esp_id, esp->sreg));
+
+		/* If a command is live on the bus we cannot safely
+		 * reset the bus, so we'll just let the pieces fall
+		 * where they may.  Here we are hoping that the
+		 * target will be able to cleanly go away soon
+		 * so we can safely reset things.
+		 */
+		if(!SCptr) {
+			ESPLOG(("esp%d: No current cmd during gross error, "
+				"resetting bus\n", esp->esp_id));
+			what_next = do_reset_bus;
+			goto again;
+		}
+	}
+
+	if(dregs->cond_reg & DMA_HNDL_ERROR) {
+		/* A DMA gate array error.  Here we must
+		 * be seeing one of two things.  Either the
+		 * virtual to physical address translation
+		 * on the SBUS could not occur, else the
+		 * translation it did get pointed to a bogus
+		 * page.  Ho hum...
+		 */
+		ESPLOG(("esp%d: DMA error %08lx\n", esp->esp_id,
+			dregs->cond_reg));
+
+		/* DMA gate array itself must be reset to clear the
+		 * error condition.
+		 */
+		esp_reset_dma(esp);
+
+		what_next = do_reset_bus;
+		goto again;
+	}
+
+	if(esp->erev == fashme) {
+		/* This chip is really losing. */
+		ESPHME(("HME["));
+
+		ESPHME(("sreg2=%02x,", esp->sreg2));
+		/* Must latch fifo before reading the interrupt
+		 * register else garbage ends up in the FIFO
+		 * which confuses the driver utterly.
+		 */
+		if(!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
+		   (esp->sreg2 & ESP_STAT2_F1BYTE)) {
+			ESPHME(("fifo_workaround]"));
+			hme_fifo_hwbug_workaround(esp, eregs);
 		} else {
-			panic("esp: penguin status phase.");
+			ESPHME(("no_fifo_workaround]"));
 		}
-	case in_finale:
-		if(esp->ireg & ESP_INTR_BSERV) {
-			panic("esp: penguin doesn't disconnect after status msg-ack.");
-			goto esp_handle_done;
-		} else if(esp->ireg & ESP_INTR_DC) {
-			/* Nexus is complete. */
-#ifdef THREADED_ESP_DRIVER
-			append_SC(esp->eatme_SC, esp->current_SC);
-			esp->current_SC = 0;
-			wake_up(esp_kernel_thread);
-#else
-			esp_done(esp, ((SCptr->SCp.Status & 0xff) |
-				 ((SCptr->SCp.Message & 0xff) << 8) |
-				 (DID_OK << 16)));
-#endif
-			ETRACE(("NEXUS_COMPLETE\n"));
-			goto esp_handle_done;
+	}
+
+	esp->ireg = eregs->esp_intrpt;   /* Unlatch intr and stat regs */
+
+	/* No current cmd is only valid at this point when there are
+	 * commands off the bus or we are trying a reset.
+	 */
+	if(!SCptr && !esp->disconnected_SC && !(esp->ireg & ESP_INTR_SR)) {
+		/* Panic is safe, since current_SC is null. */
+		ESPLOG(("esp%d: no command in esp_handle()\n", esp->esp_id));
+		panic("esp_handle: current_SC == penguin within interrupt!");
+	}
+
+	if(esp->ireg & (ESP_INTR_IC)) {
+		/* Illegal command fed to ESP.  Outside of obvious
+		 * software bugs that could cause this, there is
+		 * a condition with esp100 where we can confuse the
+		 * ESP into an erroneous illegal command interrupt
+		 * because it does not scrape the FIFO properly
+		 * for reselection.  See esp100_reconnect_hwbug()
+		 * to see how we try very hard to avoid this.
+		 */
+		ESPLOG(("esp%d: illegal command\n", esp->esp_id));
+
+		esp_dump_state(esp, eregs, dregs);
+
+		if(SCptr) {
+			/* Devices with very buggy firmware can drop BSY
+			 * during a scatter list interrupt when using sync
+			 * mode transfers.  We continue the transfer as
+			 * expected, the target drops the bus, the ESP
+			 * gets confused, and we get a illegal command
+			 * interrupt because the bus is in the disconnected
+			 * state now and ESP_CMD_TI is only allowed when
+			 * a nexus is alive on the bus.
+			 */
+			ESPLOG(("esp%d: Forcing async and disabling disconnect for "
+				"target %d\n", esp->esp_id, SCptr->target));
+			SCptr->device->borken = 1; /* foo on you */
+		}
+
+		what_next = do_reset_bus;
+		goto again;
+	}
+
+	if(!(esp->ireg & ~(ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC))) {
+		int phase;
+
+		if(SCptr) {
+			phase = SCptr->SCp.phase;
+			if(phase & in_phases_mask) {
+				what_next = esp_work_bus(esp, eregs, dregs);
+			} else if(phase & in_slct_mask) {
+				what_next = esp_select_complete(esp, eregs, dregs);
+			} else {
+				ESPLOG(("esp%d: interrupt for no good reason...\n",
+					esp->esp_id));
+				goto esp_handle_done;
+			}
 		} else {
-			printk("esp: wacky state while in in_finale phase.\n");
-			printk("esp_status: intr<%2x> stat<%2x> seq<%2x>\n",
-			       esp->ireg, esp->sreg, esp->seqreg);
-			panic("esp: penguin esp state.");
+			ESPLOG(("esp%d: BSERV or FDONE or DC while SCptr==NULL\n",
+				esp->esp_id));
+			what_next = do_reset_bus;
+			goto again;
+		}
+	} else if(esp->ireg & ESP_INTR_SR) {
+		ESPLOG(("esp%d: SCSI bus reset interrupt\n", esp->esp_id));
+		what_next = do_reset_complete;
+	} else if(esp->ireg & (ESP_INTR_S | ESP_INTR_SATN)) {
+		ESPLOG(("esp%d: AIEEE we have been selected by another initiator!\n",
+			esp->esp_id));
+		what_next = do_reset_bus;
+		goto again;
+	} else if(esp->ireg & ESP_INTR_RSEL) {
+		if(!SCptr) {
+			/* This is ok. */
+			what_next = esp_do_reconnect(esp, eregs, dregs);
+		} else if(SCptr->SCp.phase & in_slct_mask) {
+			/* Only selection code knows how to clean
+			 * up properly.
+			 */
+			ESPDISC(("Reselected during selection attempt\n"));
+			what_next = esp_select_complete(esp, eregs, dregs);
+		} else {
+			ESPLOG(("esp%d: Reselected while bus is busy\n",
+				esp->esp_id));
+			what_next = do_reset_bus;
+			goto again;
+		}
+	}
+
+	/* We're trying to fight stack problems, and inline as much as
+	 * possible without making this driver a mess. hate hate hate
+	 * This is tier-one in our dual level SCSI state machine.
+	 */
+again:
+	switch(what_next) {
+	case do_intr_end:
+		goto esp_handle_done;
+
+	case do_work_bus:
+		what_next = esp_work_bus(esp, eregs, dregs);
+		break;
+
+	case do_phase_determine:
+		what_next = esp_do_phase_determine(esp, eregs, dregs);
+		break;
+
+	case do_reset_bus:
+		ESPLOG(("esp%d: resetting bus...\n", esp->esp_id));
+		esp->resetting_bus = 1;
+		esp_cmd(esp, eregs, ESP_CMD_RS);
+		goto esp_handle_done;
+
+	case do_reset_complete:
+		/* Tricky, we don't want to cause any more commands to
+		 * go out until we clear all the live cmds by hand.
+		 */
+		if(!DMA_ISBROKEN(esp->dma))
+			DMA_INTSOFF(dregs);
+		if(esp->current_SC) {
+			Scsi_Cmnd *SCptr = esp->current_SC;
+			if(!SCptr->use_sg)
+				mmu_release_scsi_one((char *)
+						     SCptr->SCp.have_data_in,
+						     SCptr->request_bufflen,
+						     esp->edev->my_bus);
+			else
+				mmu_release_scsi_sgl((struct mmu_sglist *)
+						     SCptr->buffer,
+						     SCptr->use_sg - 1,
+						     esp->edev->my_bus);
+			SCptr->result = (DID_RESET << 16);
+			SCptr->scsi_done(SCptr);
+			cli();
+		}
+		esp->current_SC = NULL;
+		if(esp->disconnected_SC) {
+			Scsi_Cmnd *SCptr;
+			while((SCptr = remove_first_SC(&esp->disconnected_SC))) {
+				if(!SCptr->use_sg)
+					mmu_release_scsi_one((char *)
+							     SCptr->SCp.have_data_in,
+							     SCptr->request_bufflen,
+							     esp->edev->my_bus);
+				else
+					mmu_release_scsi_sgl((struct mmu_sglist *)
+							     SCptr->buffer,
+							     SCptr->use_sg - 1,
+							     esp->edev->my_bus);
+				SCptr->result = (DID_RESET << 16);
+				SCptr->scsi_done(SCptr);
+				cli();
+			}
+		}
+		esp->resetting_bus = 0;
+		if(!DMA_ISBROKEN(esp->dma))
+			DMA_INTSON(dregs);
+
+		if(esp->current_SC) {
+			printk("esp%d: weird weird weird, current_SC not NULL after "
+			       "SCSI bus reset.\n", esp->esp_id);
 			goto esp_handle_done;
 		}
-	default:
-		panic("esp: detected penguin phase.");
+
+		/* Now it is safe to execute more things. */
+		if(esp->issue_SC)
+			esp_exec_cmd(esp);
 		goto esp_handle_done;
-	}
-	panic("esp: Heading to the promised land.");
+
+	default:
+		/* state is completely lost ;-( */
+		ESPLOG(("esp%d: interrupt engine loses state, resetting bus\n",
+			esp->esp_id));
+		what_next = do_reset_bus;
+		break;
+
+	};
+	goto again;
 
 esp_handle_done:
 	DMA_IRQ_EXIT(esp->dma, dregs);
@@ -1118,11 +4057,28 @@
 static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
 {
 	struct Sparc_ESP *esp;
+	static int running = 0;
+	int again;
+
+	/* It is ok to take irq's on one esp while the other
+	 * is amidst the processing of a reset.
+	 */
+	running++;
+	if(running > esps_running)
+		ESPLOG(("esp_intr: yieee, recursive interrupt!\n"));
 
 	/* Handle all ESP interrupts showing */
+repeat:
+	again = 0;
 	for_each_esp(esp) {
 		if(DMA_IRQ_P(esp->dregs)) {
+			again = 1;
+			ESPIRQ(("I%d(", esp->esp_id));
 			esp_handle(esp);
+			ESPIRQ((")"));
 		}
 	}
+	if(again)
+		goto repeat;
+	running--;
 }
diff -u --recursive --new-file v2.1.15/linux/drivers/scsi/esp.h linux/drivers/scsi/esp.h
--- v2.1.15/linux/drivers/scsi/esp.h	Tue Apr 23 12:31:34 1996
+++ linux/drivers/scsi/esp.h	Fri Dec 13 11:37:37 1996
@@ -49,6 +49,7 @@
     volatile unchar esp_cfg1;   /* rw  First configuration register   0x20   */
                                 unchar cfpad[3];
     volatile unchar esp_cfact;  /* wo  Clock conversion factor        0x24   */
+#define esp_status2 esp_cfact   /* ro  HME status2 register           0x24   */
                                 unchar ctpad[3];
     volatile unchar esp_ctest;  /* wo  Chip test register             0x28   */
                                 unchar cf2pd[3];
@@ -62,24 +63,27 @@
     /* The following is found on all chips except the NCR53C90 (ESP100) */
     volatile unchar esp_tchi;   /* rw  High bits of transfer count    0x38  */
 #define esp_uid     esp_tchi    /* ro  Unique ID code                 0x38  */
+#define fas_rlo     esp_tchi    /* rw  HME extended counter           0x38  */
                                 unchar fgpad[3];
     volatile unchar esp_fgrnd;  /* rw  Data base for fifo             0x3c  */
+#define fas_rhi     esp_fgrnd   /* rw  HME extended counter           0x3c  */
 };
 
 /* Various revisions of the ESP board. */
 enum esp_rev {
-  esp100     = 0x00,  /* NCR53C90  */
+  esp100     = 0x00,  /* NCR53C90 - very broken */
   esp100a    = 0x01,  /* NCR53C90A */
   esp236     = 0x02,
   fas236     = 0x03,
   fas100a    = 0x04,
   fast       = 0x05,
-  espunknown = 0x06
+  fashme     = 0x06,
+  espunknown = 0x07
 };
 
 /* We get one of these for each ESP probed. */
 struct Sparc_ESP {
-  struct Sparc_ESP *next;           /* Next ESP on probed or NULL */
+  struct Sparc_ESP *next;                 /* Next ESP on probed or NULL */
   struct Sparc_ESP_regs *eregs;           /* All esp registers */
   struct Linux_SBus_DMA *dma;             /* Who I do transfers with. */
   struct sparc_dma_registers *dregs;      /* And his registers. */
@@ -88,23 +92,27 @@
   struct linux_sbus_device *edev;         /* Pointer to SBus entry */
   char prom_name[64];                     /* Name of ESP device from prom */
   int prom_node;                          /* Prom node where ESP found */
-  int esp_id;                             /* Same as esphost->host_id */
+  int esp_id;                             /* Unique per-ESP ID number */
 
   /* ESP Configuration Registers */
   unsigned char config1;                  /* Copy of the 1st config register */
   unsigned char config2;                  /* Copy of the 2nd config register */
-  unsigned char config3[8];               /* Copy of the 3rd config register */
+  unsigned char config3[16];              /* Copy of the 3rd config register */
 
   /* The current command we are sending to the ESP chip.  This esp_command
    * ptr needs to be mapped in DVMA area so we can send commands and read
    * from the ESP fifo without burning precious CPU cycles.  Programmed I/O
-   * sucks when we have the DVMA to do it for us.
+   * sucks when we have the DVMA to do it for us.  The ESP is stupid and will
+   * only send out 6, 10, and 12 byte SCSI commands, others we need to send
+   * one byte at a time.  esp_slowcmd being set says that we are doing one
+   * of the command types ESP doesn't understand, esp_scmdp keeps track of
+   * which byte we are sending, esp_scmdleft says how many bytes to go.
    */
   volatile unchar *esp_command;           /* Location of command */
-  int esp_clen;                           /* Length of this command */
-
-  /* To hold onto the dvma buffer ptr. */
-  char *dvma_hold;
+  unsigned char esp_clen;                 /* Length of this command */
+  unsigned char esp_slowcmd;
+  unsigned char *esp_scmdp;
+  unsigned char esp_scmdleft;
 
   /* The following are used to determine the cause of an IRQ. Upon every
    * IRQ entry we synchronize these with the hardware registers.
@@ -112,20 +120,45 @@
   unchar ireg;                            /* Copy of ESP interrupt register */
   unchar sreg;                            /* Same for ESP status register */
   unchar seqreg;                          /* The ESP sequence register */
+  unchar sreg2;                           /* Copy of HME status2 register */
+
+  /* The HME is the biggest piece of shit I have ever seen. */
+  unchar hme_fifo_workaround_buffer[16 * 2]; /* 16-bit/entry fifo for wide scsi */
+  unchar hme_fifo_workaround_count;
 
   /* Clock periods, frequencies, synchronization, etc. */
   unsigned int cfreq;                    /* Clock frequency in HZ */
   unsigned int cfact;                    /* Clock conversion factor */
   unsigned int ccycle;                   /* One ESP clock cycle */
   unsigned int ctick;                    /* One ESP clock time */
-  unsigned int sync_defp;                /* Default negotiation period */
+  unsigned int radelay;                  /* FAST chip req/ack delay */
+  unsigned int neg_defp;                 /* Default negotiation period */
+  unsigned int sync_defp;                /* Default sync transfer period */
+  unsigned int max_period;               /* longest our period can be */
+  unsigned int min_period;               /* shortest period we can withstand */
+  /* For slow to medium speed input clock rates we shoot for 5mb/s,
+   * but for high input clock rates we try to do 10mb/s although I
+   * don't think a transfer can even run that fast with an ESP even
+   * with DMA2 scatter gather pipelining.
+   */
+#define SYNC_DEFP_SLOW            0x32   /* 5mb/s  */
+#define SYNC_DEFP_FAST            0x19   /* 10mb/s */
+
+  unsigned int snip;                      /* Sync. negotiation in progress */
+  unsigned int wnip;                      /* WIDE negotiation in progress */
+  unsigned int targets_present;           /* targets spoken to before */
+
+  int current_transfer_size;              /* Set at beginning of data dma */
+
+  unchar espcmdlog[32];                   /* Log of current esp cmds sent. */
+  unchar espcmdent;                       /* Current entry in esp cmd log. */
 
   /* Misc. info about this ESP */
   enum esp_rev erev;                      /* ESP revision */
   int irq;                                /* SBus IRQ for this ESP */
   int scsi_id;                            /* Who am I as initiator? */
   int scsi_id_mask;                       /* Bitmask of 'me'. */
-  int diff;                               /* Differential SCSI? */
+  int diff;                               /* Differential SCSI bus? */
   int bursts;                             /* Burst sizes our DVMA supports */
 
   /* Our command queues, only one cmd lives in the current_SC queue. */
@@ -133,12 +166,17 @@
   Scsi_Cmnd *current_SC;         /* Who is currently working the bus */
   Scsi_Cmnd *disconnected_SC;    /* Commands disconnected from the bus */
 
-#ifdef THREADED_ESP_DRIVER
-  Scsi_Cmnd *eatme_SC;           /* Cmds waiting for esp thread to process. */
-#endif
+  /* Message goo */
+  unchar cur_msgout[16];
+  unchar cur_msgin[16];
+  unchar prevmsgout, prevmsgin;
+  unchar msgout_len, msgin_len;
+  unchar msgout_ctr, msgin_ctr;
 
-  /* Abortion status */
-  int aborting, abortion_complete, abort_result;
+  /* States that we cannot keep in the per cmd structure because they
+   * cannot be assosciated with any specific command.
+   */
+  unchar resetting_bus;
 };
 
 /* Bitfield meanings for the above registers. */
@@ -152,30 +190,37 @@
 #define ESP_CONFIG1_SLCABLE   0x80             /* Enable slow cable mode */
 
 /* ESP config reg 2, read-write, found only on esp100a+esp200+esp236 chips */
-#define ESP_CONFIG2_DMAPARITY 0x01             /* Parity DMA err (200,236) */
-#define ESP_CONFIG2_REGPARITY 0x02             /* Parity reg err (200,236) */
+#define ESP_CONFIG2_DMAPARITY 0x01             /* enable DMA Parity (200,236) */
+#define ESP_CONFIG2_REGPARITY 0x02             /* enable reg Parity (200,236) */
 #define ESP_CONFIG2_BADPARITY 0x04             /* Bad parity target abort  */
-#define ESP_CONFIG2_SCSI2ENAB 0x08             /* Enable SCSI-2 features   */
+#define ESP_CONFIG2_SCSI2ENAB 0x08             /* Enable SCSI-2 features (tmode only) */
 #define ESP_CONFIG2_HI        0x10             /* High Impedance DREQ ???  */
+#define ESP_CONFIG2_HMEFENAB  0x10             /* HME features enable */
 #define ESP_CONFIG2_BCM       0x20             /* Enable byte-ctrl (236)   */
+#define ESP_CONFIG2_DISPINT   0x20             /* Disable pause irq (hme) */
 #define ESP_CONFIG2_FENAB     0x40             /* Enable features (fas100,esp216)      */
 #define ESP_CONFIG2_SPL       0x40             /* Enable status-phase latch (esp236)   */
+#define ESP_CONFIG2_MKDONE    0x40             /* HME magic feature */
+#define ESP_CONFIG2_HME32     0x80             /* HME 32 extended */
 #define ESP_CONFIG2_MAGIC     0xe0             /* Invalid bits... */
 
-/* ESP config register 3 read-write, found only esp236+fas236+fas100a chips */
-#define ESP_CONFIG3_FCLOCK    0x01             /* FAST SCSI clock rate (esp100a)     */
+/* ESP config register 3 read-write, found only esp236+fas236+fas100a+hme chips */
+#define ESP_CONFIG3_FCLOCK    0x01             /* FAST SCSI clock rate (esp100a/hme) */
 #define ESP_CONFIG3_TEM       0x01             /* Enable thresh-8 mode (esp/fas236)  */
-#define ESP_CONFIG3_FAST      0x02             /* Enable FAST SCSI     (esp100a)     */
+#define ESP_CONFIG3_FAST      0x02             /* Enable FAST SCSI     (esp100a/hme) */
 #define ESP_CONFIG3_ADMA      0x02             /* Enable alternate-dma (esp/fas236)  */
-#define ESP_CONFIG3_TENB      0x04             /* group2 SCSI2 support (esp100a)     */
+#define ESP_CONFIG3_TENB      0x04             /* group2 SCSI2 support (esp100a/hme) */
 #define ESP_CONFIG3_SRB       0x04             /* Save residual byte   (esp/fas236)  */
-#define ESP_CONFIG3_TMS       0x08             /* Three-byte msg's ok  (esp100a)     */
+#define ESP_CONFIG3_TMS       0x08             /* Three-byte msg's ok  (esp100a/hme) */
 #define ESP_CONFIG3_FCLK      0x08             /* Fast SCSI clock rate (esp/fas236)  */
-#define ESP_CONFIG3_IDMSG     0x10             /* ID message checking  (esp100a)     */
+#define ESP_CONFIG3_IDMSG     0x10             /* ID message checking  (esp100a/hme) */
 #define ESP_CONFIG3_FSCSI     0x10             /* Enable FAST SCSI     (esp/fas236)  */
 #define ESP_CONFIG3_GTM       0x20             /* group2 SCSI2 support (esp/fas236)  */
+#define ESP_CONFIG3_BIGID     0x20             /* SCSI-ID's are 4bits  (hme)         */
 #define ESP_CONFIG3_TBMS      0x40             /* Three-byte msg's ok  (esp/fas236)  */
+#define ESP_CONFIG3_EWIDE     0x40             /* Enable Wide-SCSI     (hme)         */
 #define ESP_CONFIG3_IMS       0x80             /* ID msg chk'ng        (esp/fas236)  */
+#define ESP_CONFIG3_OBPUSH    0x80             /* Push odd-byte to dma (hme)         */
 
 /* ESP command register read-write */
 /* Group 1 commands:  These may be sent at any point in time to the ESP
@@ -244,6 +289,16 @@
  */
 #define ESP_STAT_INTR         0x80             /* Interrupt */
 
+/* HME only: status 2 register */
+#define ESP_STAT2_SCHBIT      0x01 /* Upper bits 3-7 of sstep enabled */
+#define ESP_STAT2_FFLAGS      0x02 /* The fifo flags are now latched */
+#define ESP_STAT2_XCNT        0x04 /* The transfer counter is latched */
+#define ESP_STAT2_CREGA       0x08 /* The command reg is active now */
+#define ESP_STAT2_WIDE        0x10 /* Interface on this adapter is wide */
+#define ESP_STAT2_F1BYTE      0x20 /* There is one byte at top of fifo */
+#define ESP_STAT2_FMSB        0x40 /* Next byte in fifo is most significant */
+#define ESP_STAT2_FEMPTY      0x80 /* FIFO is empty */
+
 /* The status register can be masked with ESP_STAT_PMASK and compared
  * with the following values to determine the current phase the ESP
  * (at least thinks it) is in.  For our purposes we also add our own
@@ -283,7 +338,12 @@
 #define ESP_STEP_PPC          0x03             /* Early phase chg caused cmnd
                                                 * bytes to be lost
                                                 */
-#define ESP_STEP_FINI         0x04             /* Command was sent ok */
+#define ESP_STEP_FINI4        0x04             /* Command was sent ok */
+
+/* Ho hum, some ESP's set the step register to this as well... */
+#define ESP_STEP_FINI5        0x05
+#define ESP_STEP_FINI6        0x06
+#define ESP_STEP_FINI7        0x07
 
 /* ESP chip-test register read-write */
 #define ESP_TEST_TARG         0x01             /* Target test mode */
@@ -299,6 +359,7 @@
 /* ESP fifo flags register read-only */
 /* Note that the following implies a 16 byte FIFO on the ESP. */
 #define ESP_FF_FBYTES         0x1f             /* Num bytes in FIFO */
+#define ESP_FF_ONOTZERO       0x20             /* offset ctr not zero (esp100) */
 #define ESP_FF_SSTEP          0xe0             /* Sequence step */
 
 /* ESP clock conversion factor register write-only */
@@ -311,12 +372,25 @@
 #define ESP_CCF_F6            0x06             /* 25.01MHz - 30MHz */
 #define ESP_CCF_F7            0x07             /* 30.01MHz - 35MHz */
 
+/* HME only... */
+#define ESP_BUSID_RESELID     0x10
+#define ESP_BUSID_CTR32BIT    0x40
+
+#define ESP_BUS_TIMEOUT        275             /* In milli-seconds */
+#define ESP_TIMEO_CONST       8192
+#define ESP_NEG_DEFP(mhz, cfact) \
+        ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact)))
+#define ESP_MHZ_TO_CYCLE(mhertz)  ((1000000000) / ((mhertz) / 1000))
+#define ESP_TICK(ccf, cycle)  ((7682 * (ccf) * (cycle) / 1000))
+
 extern int esp_detect(struct SHT *);
 extern const char *esp_info(struct Scsi_Host *);
 extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 extern int esp_command(Scsi_Cmnd *);
 extern int esp_abort(Scsi_Cmnd *);
 extern int esp_reset(Scsi_Cmnd *, unsigned int);
+extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
+			 int hostno, int inout);
 
 extern struct proc_dir_entry proc_scsi_esp;
 
@@ -324,7 +398,7 @@
 /* struct SHT *next */                                         NULL,                   \
 /* long *usage_count */                                        NULL,                   \
 /* struct proc_dir_entry *proc_dir */                          &proc_scsi_esp,         \
-/* int (*proc_info)(char *, char **, off_t, int, int, int) */  NULL,                   \
+/* int (*proc_info)(char *, char **, off_t, int, int, int) */  &esp_proc_info,         \
 /* const char *name */                                         "Sun ESP 100/100a/200", \
 /* int detect(struct SHT *) */                                 esp_detect,             \
 /* int release(struct Scsi_Host *) */                          NULL,                   \
@@ -335,7 +409,7 @@
 /* int reset(Scsi_Cmnd *, int) */                              esp_reset,              \
 /* int slave_attach(int, int) */                               NULL,                   \
 /* int bios_param(Disk *, kdev_t, int[]) */                    NULL,                   \
-/* int can_queue */                                            10,                     \
+/* int can_queue */                                            7,                      \
 /* int this_id */                                              7,                      \
 /* short unsigned int sg_tablesize */                          SG_ALL,                 \
 /* short cmd_per_lun */                                        1,                      \
diff -u --recursive --new-file v2.1.15/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v2.1.15/linux/drivers/scsi/hosts.c	Thu Dec 12 19:37:07 1996
+++ linux/drivers/scsi/hosts.c	Fri Dec 13 11:37:37 1996
@@ -169,6 +169,10 @@
 #include "esp.h"
 #endif
 
+#ifdef CONFIG_SCSI_QLOGICPTI
+#include "qlogicpti.h"
+#endif
+
 #ifdef CONFIG_BLK_DEV_IDESCSI
 #include "ide-scsi.h"
 #endif
@@ -179,7 +183,7 @@
 
 
 /*
-static const char RCSid[] = "$Header: /usr/src/linux-1.3.95/drivers/scsi/RCS/hosts.c,v 1.7 1996/04/25 22:21:56 root Exp root $";
+static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/hosts.c,v 1.20 1996/12/12 19:18:32 davem Exp $";
 */
 
 /*
@@ -313,6 +317,9 @@
 #endif
 #ifdef CONFIG_SCSI_SUNESP
     SCSI_SPARC_ESP,
+#endif
+#ifdef CONFIG_SCSI_QLOGICPTI
+    QLOGICPTI,
 #endif
 #ifdef CONFIG_BLK_DEV_IDESCSI
     IDESCSI,
diff -u --recursive --new-file v2.1.15/linux/drivers/scsi/ibmmca.c linux/drivers/scsi/ibmmca.c
--- v2.1.15/linux/drivers/scsi/ibmmca.c	Thu Dec 12 19:37:07 1996
+++ linux/drivers/scsi/ibmmca.c	Wed Dec 18 11:48:52 1996
@@ -590,13 +590,13 @@
       scb.command = IM_DEVICE_INQUIRY_CMD;
       scb.enable = IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
       /* I think this virt_to_bus is needed.. ??? AC */
-      scb.sys_buf_adr = virt_to_bus((unsigned long) buf);
+      scb.sys_buf_adr = virt_to_bus(buf);
       scb.sys_buf_length = 255;
-      scb.tsb_adr = virt_to_bus((unsigned long) &tsb);
+      scb.tsb_adr = virt_to_bus(&tsb);
 
       /*issue scb to passed ldn, and busy wait for interrupt */
       got_interrupt = 0;
-      issue_cmd (virt_to_bus((unsigned long)) &scb, IM_SCB | ldn);
+      issue_cmd (virt_to_bus(&scb), IM_SCB | ldn);
       while (!got_interrupt)
 	barrier ();
 
@@ -627,13 +627,13 @@
 	  /*fill scb with read capacity command */
 	  scb.command = IM_READ_CAPACITY_CMD;
 	  scb.enable = IM_READ_CONTROL;
-	  scb.sys_buf_adr = virt_to_bus((unsigned long) buf);
+	  scb.sys_buf_adr = virt_to_bus(buf);
 	  scb.sys_buf_length = 8;
-	  scb.tsb_adr = virt_to_bus((unsigned long) &tsb);
+	  scb.tsb_adr = virt_to_bus(&tsb);
 
 	  /*issue scb to passed ldn, and busy wait for interrupt */
 	  got_interrupt = 0;
-	  issue_cmd (virt_to_bus((unsigned long) &scb), IM_SCB | ldn);
+	  issue_cmd (virt_to_bus(&scb), IM_SCB | ldn);
 	  while (!got_interrupt)
 	    barrier ();
 
@@ -740,7 +740,7 @@
   /*fill scb information independent of the scsi command */
   scb = &(ld[ldn].scb);
   scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR;
-  scb->tsb_adr = virt_to_bus((unsigned long) &(ld[ldn].tsb));
+  scb->tsb_adr = virt_to_bus(&(ld[ldn].tsb));
   if (cmd->use_sg)
     {
       int i = cmd->use_sg;
@@ -749,16 +749,16 @@
 	panic ("IBM MCA SCSI: scatter-gather list too long.\n");
       while (--i >= 0)
 	{
-	  ld[ldn].sge[i].address = virt_to_bus(sl[i].address);
+	  ld[ldn].sge[i].address = (void *) virt_to_bus(sl[i].address);
 	  ld[ldn].sge[i].byte_length = sl[i].length;
 	}
       scb->enable |= IM_POINTER_TO_LIST;
-      scb->sys_buf_adr = virt_to_bus((unsigned long) &(ld[ldn].sge[0]));
+      scb->sys_buf_adr = virt_to_bus(&(ld[ldn].sge[0]));
       scb->sys_buf_length = cmd->use_sg * sizeof (struct im_sge);
     }
   else
     {
-      scb->sys_buf_adr = virt_to_bus((unsigned long) cmd->request_buffer);
+      scb->sys_buf_adr = virt_to_bus(cmd->request_buffer);
       scb->sys_buf_length = cmd->request_bufflen;
     }
 
@@ -833,7 +833,7 @@
     }
 
   /*issue scb command, and return */
-  issue_cmd (virt_to_bus((unsigned long) scb), IM_SCB | ldn);
+  issue_cmd (virt_to_bus(scb), IM_SCB | ldn);
   return 0;
 }
 
diff -u --recursive --new-file v2.1.15/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c
--- v2.1.15/linux/drivers/scsi/qlogicpti.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/qlogicpti.c	Fri Dec 13 11:37:37 1996
@@ -0,0 +1,1118 @@
+/* qlogicpti.c: Performance Technologies QlogicISP sbus card driver.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
+ *
+ * A lot of this driver was directly stolen from Erik H. Moe's PCI
+ * Qlogic ISP driver.  Mucho kudos to him for this code.
+ *
+ * An even bigger kudos to John Grana at Performance Technologies
+ * for providing me with the hardware to write this driver, you rule
+ * John you really do.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/blk.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
+#include <asm/byteorder.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "qlogicpti.h"
+
+#include <asm/sbus.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/machines.h>
+#include <asm/ptrace.h>
+#include <asm/pgtable.h>
+#include <asm/oplib.h>
+#include <asm/vaddrs.h>
+#include <asm/io.h>
+
+#include <linux/module.h>
+
+#define MAX_TARGETS	16
+#define MAX_LUNS	8
+
+#define DEFAULT_LOOP_COUNT	1000000
+
+#include "qlogicpti_asm.c"
+
+static struct qlogicpti *qptichain;
+static int qptis_running = 0;
+
+#define PACKB(a, b)			(((a)<<4)|(b))
+
+const u_char mbox_param[] = {
+	PACKB(1, 1),	/* MBOX_NO_OP */
+	PACKB(5, 5),	/* MBOX_LOAD_RAM */
+	PACKB(2, 0),	/* MBOX_EXEC_FIRMWARE */
+	PACKB(5, 5),	/* MBOX_DUMP_RAM */
+	PACKB(3, 3),	/* MBOX_WRITE_RAM_WORD */
+	PACKB(2, 3),	/* MBOX_READ_RAM_WORD */
+	PACKB(6, 6),	/* MBOX_MAILBOX_REG_TEST */
+	PACKB(2, 3),	/* MBOX_VERIFY_CHECKSUM	*/
+	PACKB(1, 3),	/* MBOX_ABOUT_FIRMWARE */
+	PACKB(0, 0),	/* 0x0009 */
+	PACKB(0, 0),	/* 0x000a */
+	PACKB(0, 0),	/* 0x000b */
+	PACKB(0, 0),	/* 0x000c */
+	PACKB(0, 0),	/* 0x000d */
+	PACKB(1, 2),	/* MBOX_CHECK_FIRMWARE */
+	PACKB(0, 0),	/* 0x000f */
+	PACKB(5, 5),	/* MBOX_INIT_REQ_QUEUE */
+	PACKB(6, 6),	/* MBOX_INIT_RES_QUEUE */
+	PACKB(4, 4),	/* MBOX_EXECUTE_IOCB */
+	PACKB(2, 2),	/* MBOX_WAKE_UP	*/
+	PACKB(1, 6),	/* MBOX_STOP_FIRMWARE */
+	PACKB(4, 4),	/* MBOX_ABORT */
+	PACKB(2, 2),	/* MBOX_ABORT_DEVICE */
+	PACKB(3, 3),	/* MBOX_ABORT_TARGET */
+	PACKB(2, 2),	/* MBOX_BUS_RESET */
+	PACKB(2, 3),	/* MBOX_STOP_QUEUE */
+	PACKB(2, 3),	/* MBOX_START_QUEUE */
+	PACKB(2, 3),	/* MBOX_SINGLE_STEP_QUEUE */
+	PACKB(2, 3),	/* MBOX_ABORT_QUEUE */
+	PACKB(2, 4),	/* MBOX_GET_DEV_QUEUE_STATUS */
+	PACKB(0, 0),	/* 0x001e */
+	PACKB(1, 3),	/* MBOX_GET_FIRMWARE_STATUS */
+	PACKB(1, 2),	/* MBOX_GET_INIT_SCSI_ID */
+	PACKB(1, 2),	/* MBOX_GET_SELECT_TIMEOUT */
+	PACKB(1, 3),	/* MBOX_GET_RETRY_COUNT	*/
+	PACKB(1, 2),	/* MBOX_GET_TAG_AGE_LIMIT */
+	PACKB(1, 2),	/* MBOX_GET_CLOCK_RATE */
+	PACKB(1, 2),	/* MBOX_GET_ACT_NEG_STATE */
+	PACKB(1, 2),	/* MBOX_GET_ASYNC_DATA_SETUP_TIME */
+	PACKB(1, 3),	/* MBOX_GET_SBUS_PARAMS */
+	PACKB(2, 4),	/* MBOX_GET_TARGET_PARAMS */
+	PACKB(2, 4),	/* MBOX_GET_DEV_QUEUE_PARAMS */
+	PACKB(0, 0),	/* 0x002a */
+	PACKB(0, 0),	/* 0x002b */
+	PACKB(0, 0),	/* 0x002c */
+	PACKB(0, 0),	/* 0x002d */
+	PACKB(0, 0),	/* 0x002e */
+	PACKB(0, 0),	/* 0x002f */
+	PACKB(2, 2),	/* MBOX_SET_INIT_SCSI_ID */
+	PACKB(2, 2),	/* MBOX_SET_SELECT_TIMEOUT */
+	PACKB(3, 3),	/* MBOX_SET_RETRY_COUNT	*/
+	PACKB(2, 2),	/* MBOX_SET_TAG_AGE_LIMIT */
+	PACKB(2, 2),	/* MBOX_SET_CLOCK_RATE */
+	PACKB(2, 2),	/* MBOX_SET_ACTIVE_NEG_STATE */
+	PACKB(2, 2),	/* MBOX_SET_ASYNC_DATA_SETUP_TIME */
+	PACKB(3, 3),	/* MBOX_SET_SBUS_CONTROL_PARAMS */
+	PACKB(4, 4),	/* MBOX_SET_TARGET_PARAMS */
+	PACKB(4, 4),	/* MBOX_SET_DEV_QUEUE_PARAMS */
+	PACKB(0, 0),	/* 0x003a */
+	PACKB(0, 0),	/* 0x003b */
+	PACKB(0, 0),	/* 0x003c */
+	PACKB(0, 0),	/* 0x003d */
+	PACKB(0, 0),	/* 0x003e */
+	PACKB(0, 0),	/* 0x003f */
+	PACKB(0, 0),	/* 0x0040 */
+	PACKB(0, 0),	/* 0x0041 */
+	PACKB(0, 0)	/* 0x0042 */
+};
+
+#define MAX_MBOX_COMMAND	(sizeof(mbox_param)/sizeof(u_short))
+
+/* queue length's _must_ be power of two: */
+#define QUEUE_DEPTH(in, out, ql)	((in - out) & (ql))
+#define REQ_QUEUE_DEPTH(in, out)	QUEUE_DEPTH(in, out, 		     \
+						    QLOGICISP_REQ_QUEUE_LEN)
+#define RES_QUEUE_DEPTH(in, out)	QUEUE_DEPTH(in, out, RES_QUEUE_LEN)
+
+static struct proc_dir_entry proc_scsi_qlogicpti = {
+	PROC_SCSI_QLOGICPTI, 7, "qlogicpti",
+	S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+static inline void qlogicpti_enable_irqs(struct qlogicpti_regs *qregs)
+{
+	qregs->sbus_ctrl = SBUS_CTRL_ERIRQ | SBUS_CTRL_GENAB;
+}
+
+
+static inline void qlogicpti_disable_irqs(struct qlogicpti_regs *qregs)
+{
+	qregs->sbus_ctrl = 0;
+}
+
+static inline void set_sbus_cfg1(struct qlogicpti_regs *qregs, unsigned char bursts)
+{
+	if(bursts & DMA_BURST32) {
+		qregs->sbus_cfg1 = (SBUS_CFG1_BENAB | SBUS_CFG1_B32);
+	} else if(bursts & DMA_BURST16) {
+		qregs->sbus_cfg1 = (SBUS_CFG1_BENAB | SBUS_CFG1_B16);
+	} else if(bursts & DMA_BURST8) {
+		qregs->sbus_cfg1 = (SBUS_CFG1_BENAB | SBUS_CFG1_B8);
+	} else {
+		qregs->sbus_cfg1 = 0; /* No sbus bursts for you... */
+	}
+}
+
+static int qlogicpti_mbox_command(struct qlogicpti *qpti, u_short param[], int force)
+{
+	struct qlogicpti_regs *qregs = qpti->qregs;
+	int loop_count;
+
+	if(mbox_param[param[0]] == 0)
+		return 1;
+
+	loop_count = DEFAULT_LOOP_COUNT;
+	while(--loop_count && (qregs->hcctrl & HCCTRL_HIRQ))
+		barrier();
+	if(!loop_count)
+		printk(KERN_EMERG "qlogicpti: mbox_command loop timeout #1\n");
+
+	switch(mbox_param[param[0]] >> 4) {
+	case 6: qregs->mbox5 = param[5];
+	case 5: qregs->mbox4 = param[4];
+	case 4: qregs->mbox3 = param[3];
+	case 3: qregs->mbox2 = param[2];
+	case 2: qregs->mbox1 = param[1];
+	case 1: qregs->mbox0 = param[0];
+	}
+
+	qregs->hcctrl |= HCCTRL_SHIRQ;
+
+	loop_count = DEFAULT_LOOP_COUNT;
+	while(--loop_count && !(qregs->sbus_semaphore & SBUS_SEMAPHORE_LCK))
+		udelay(20);
+	if(!loop_count)
+		printk(KERN_EMERG "qlogicpti: mbox_command loop timeout #2\n");
+
+	loop_count = DEFAULT_LOOP_COUNT;
+	while(--loop_count && (qregs->mbox0 == 0x04))
+		udelay(20);
+	if(!loop_count)
+		printk(KERN_EMERG "qlogicpti: mbox_command loop timeout #3\n");
+
+	if(force) {
+		qregs->hcctrl = HCCTRL_CRIRQ;
+	} else {
+		if((qregs->mbox5 - qpti->res_out_ptr) == 0)
+			qregs->hcctrl = HCCTRL_CRIRQ;
+	}
+
+	switch(mbox_param[param[0]] & 0xf) {
+	case 6: param[5] = qregs->mbox5;
+	case 5: param[4] = qregs->mbox4;
+	case 4: param[3] = qregs->mbox3;
+	case 3: param[2] = qregs->mbox2;
+	case 2: param[1] = qregs->mbox1;
+	case 1: param[0] = qregs->mbox0;
+	}
+
+	qregs->sbus_semaphore &= ~(SBUS_SEMAPHORE_LCK);
+	return 0;
+}
+
+static int qlogicpti_reset_hardware(struct Scsi_Host *host)
+{
+	struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
+	struct qlogicpti_regs *qregs = qpti->qregs;
+	u_short param[6];
+	int loop_count, i;
+	unsigned long flags;
+
+	save_flags(flags); cli();
+
+	qregs->hcctrl = HCCTRL_PAUSE;
+
+	/* Only reset the scsi bus if it is not free. */
+	if(qregs->cpu_pctrl & CPU_PCTRL_BSY) {
+		qregs->cpu_oride = CPU_ORIDE_RMOD;
+		qregs->cpu_cmd = CPU_CMD_BRESET;
+		udelay(400);
+	}
+
+	qregs->sbus_ctrl = SBUS_CTRL_RESET;
+	qregs->cmd_dma_ctrl = (DMA_CTRL_CCLEAR | DMA_CTRL_CIRQ);
+	qregs->data_dma_ctrl = (DMA_CTRL_CCLEAR | DMA_CTRL_CIRQ);
+
+	loop_count = DEFAULT_LOOP_COUNT;
+	while(--loop_count && ((qregs->mbox0 & 0xff) == 0x04))
+		udelay(20);
+	if(!loop_count)
+		printk(KERN_EMERG "qlogicpti: reset_hardware loop timeout\n");
+
+	qregs->hcctrl = HCCTRL_PAUSE;
+	set_sbus_cfg1(qregs, qpti->bursts);
+	qlogicpti_enable_irqs(qregs);
+
+	if(qregs->risc_psr & RISC_PSR_ULTRA) {
+		qpti->ultra = 1;
+		qregs->risc_mtreg = (RISC_MTREG_P0ULTRA | RISC_MTREG_P1ULTRA);
+	} else {
+		qpti->ultra = 0;
+		qregs->risc_mtreg = (RISC_MTREG_P0DFLT | RISC_MTREG_P1DFLT);
+	}
+
+	/* Release the RISC processor. */
+	qregs->hcctrl = HCCTRL_REL;
+
+	/* Get RISC to start executing the firmware code. */
+	param[0] = MBOX_EXEC_FIRMWARE;
+	param[1] = risc_code_addr01;
+	if(qlogicpti_mbox_command(qpti, param, 1)) {
+		printk(KERN_EMERG "qlogicpti%d: Cannot execute ISP firmware.\n",
+		       qpti->qpti_id);
+		restore_flags(flags);
+		return 1;
+	}
+
+	/* Set initiator scsi ID. */
+	param[0] = MBOX_SET_INIT_SCSI_ID;
+	param[1] = qpti->host_param.initiator_scsi_id;
+	if(qlogicpti_mbox_command(qpti, param, 1) ||
+	   (param[0] != MBOX_COMMAND_COMPLETE)) {
+		printk(KERN_EMERG "qlogicpti%d: Cannot set initiator SCSI ID.\n",
+		       qpti->qpti_id);
+		restore_flags(flags);
+		return 1;
+	}
+
+	/* Initialize state of the queues, both hw and sw. */
+	qpti->req_in_ptr = qpti->res_out_ptr = 0;
+
+	param[0] = MBOX_INIT_RES_QUEUE;
+	param[1] = RES_QUEUE_LEN + 1;
+	param[2] = (u_short) (((u_int) qpti->res)>>16);
+	param[3] = (u_short) (((u_int) qpti->res) & 0xffff);
+	param[4] = param[5] = 0;
+	if(qlogicpti_mbox_command(qpti, param, 1)) {
+		printk(KERN_EMERG "qlogicpti%d: Cannot init response queue.\n",
+		       qpti->qpti_id);
+		restore_flags(flags);
+		return 1;
+	}
+
+	param[0] = MBOX_INIT_REQ_QUEUE;
+	param[1] = QLOGICISP_REQ_QUEUE_LEN + 1;
+	param[2] = (u_short) (((u_int) qpti->req)>>16);
+	param[3] = (u_short) (((u_int) qpti->req) & 0xffff);
+	param[4] = param[5] = 0;
+	if(qlogicpti_mbox_command(qpti, param, 1)) {
+		printk(KERN_EMERG "qlogicpti%d: Cannot init request queue.\n",
+		       qpti->qpti_id);
+		restore_flags(flags);
+		return 1;
+	}
+
+	param[0] = MBOX_SET_RETRY_COUNT;
+	param[1] = qpti->host_param.retry_count;
+	param[2] = qpti->host_param.retry_delay;
+	qlogicpti_mbox_command(qpti, param, 0);
+
+	param[0] = MBOX_SET_TAG_AGE_LIMIT;
+	param[1] = qpti->host_param.tag_aging;
+	qlogicpti_mbox_command(qpti, param, 0);
+
+	for(i = 0; i < MAX_TARGETS; i++) {
+		param[0] = MBOX_GET_DEV_QUEUE_PARAMS;
+		param[1] = (i << 8);
+		qlogicpti_mbox_command(qpti, param, 0);
+	}
+
+	param[0] = MBOX_GET_FIRMWARE_STATUS;
+	qlogicpti_mbox_command(qpti, param, 0);
+
+	param[0] = MBOX_SET_SELECT_TIMEOUT;
+	param[1] = qpti->host_param.selection_timeout;
+	qlogicpti_mbox_command(qpti, param, 0);
+
+	for(i = 0; i < MAX_TARGETS; i++) {
+		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);
+	}
+
+	restore_flags(flags);
+	return 0;
+}
+
+#define PTI_RESET_LIMIT 400
+
+static int qlogicpti_load_firmware(struct qlogicpti *qpti)
+{
+	struct qlogicpti_regs *qregs = qpti->qregs;
+	unsigned short csum = 0;
+	unsigned short param[6];
+	unsigned long flags;
+#ifndef MODULE
+	unsigned long dvma_addr;
+#endif
+	int i, timeout;
+
+	save_flags(flags); cli();
+
+	/* Verify the checksum twice, one before loading it, and once
+	 * afterwards via the mailbox commands.
+	 */
+	for(i = 0; i < risc_code_length01; i++)
+		csum += risc_code01[i];
+	if(csum) {
+		printk(KERN_EMERG "qlogicpti%d: AIeee, firmware checksum failed!",
+		       qpti->qpti_id);
+		return 1;
+	}		
+	qregs->sbus_ctrl = SBUS_CTRL_RESET;
+	qregs->cmd_dma_ctrl = (DMA_CTRL_CCLEAR | DMA_CTRL_CIRQ);
+	qregs->data_dma_ctrl = (DMA_CTRL_CCLEAR | DMA_CTRL_CIRQ);
+	timeout = PTI_RESET_LIMIT;
+	while(--timeout && (qregs->sbus_ctrl & SBUS_CTRL_RESET))
+		udelay(20);
+	if(!timeout) {
+		printk(KERN_EMERG "qlogicpti%d: Cannot reset the ISP.", qpti->qpti_id);
+		return 1;
+	}
+
+	qregs->hcctrl = HCCTRL_RESET;
+	udelay(1000);
+
+	qregs->sbus_ctrl = (SBUS_CTRL_GENAB | SBUS_CTRL_ERIRQ);
+	set_sbus_cfg1(qregs, qpti->bursts);
+	qregs->sbus_semaphore = 0;
+
+	if(qregs->risc_psr & RISC_PSR_ULTRA) {
+		qpti->ultra = 1;
+		qregs->risc_mtreg = (RISC_MTREG_P0ULTRA | RISC_MTREG_P1ULTRA);
+	} else {
+		qpti->ultra = 0;
+		qregs->risc_mtreg = (RISC_MTREG_P0DFLT | RISC_MTREG_P1DFLT);
+	}
+
+	qregs->hcctrl = HCCTRL_REL;
+
+	/* Pin lines are only stable while RISC is paused. */
+	qregs->hcctrl = HCCTRL_PAUSE;
+	if(qregs->cpu_pdiff & CPU_PDIFF_MODE)
+		qpti->differential = 1;
+	else
+		qpti->differential = 0;
+	qregs->hcctrl = HCCTRL_REL;
+
+	/* XXX Talk to PTI engineer about the following, ISP always
+	 * XXX returns 0x4001 return status for stop firmware command,
+	 * XXX documentation claims this means the cmd is unsupported
+	 * XXX on this ISP.  I think something fishy is going on.
+	 */
+	param[0] = MBOX_STOP_FIRMWARE;
+	param[1] = param[2] = param[3] = param[4] = param[5] = 0;
+	if(qlogicpti_mbox_command(qpti, param, 1)) {
+		printk(KERN_EMERG "qlogicpti%d: Cannot stop firmware for reload.\n",
+		       qpti->qpti_id);
+		restore_flags(flags);
+		return 1;
+	}		
+
+	/* Load the firmware. */
+#ifndef MODULE
+	dvma_addr = (unsigned long) mmu_lockarea((char *)&risc_code01[0],
+						 (sizeof(u_short) * risc_code_length01));
+	param[0] = MBOX_LOAD_RAM;
+	param[1] = risc_code_addr01;
+	param[2] = (dvma_addr >> 16);
+	param[3] = (dvma_addr & 0xffff);
+	param[4] = (sizeof(u_short) * risc_code_length01);
+	if(qlogicpti_mbox_command(qpti, param, 1) ||
+	   (param[0] != MBOX_COMMAND_COMPLETE)) {
+		printk(KERN_EMERG "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_length01));
+#else
+	for(i = 0; i < risc_code_length01; i++) {
+		param[0] = MBOX_WRITE_RAM_WORD;
+		param[1] = risc_code_addr01 + i;
+		param[2] = risc_code01[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;
+		}
+	}
+#endif
+
+	/* Reset the ISP again. */
+	qregs->hcctrl = HCCTRL_RESET;
+	udelay(1000);
+
+	qlogicpti_enable_irqs(qregs);
+	qregs->sbus_semaphore = 0;
+	qregs->hcctrl = HCCTRL_REL;
+
+	/* Ask ISP to verify the checksum of the new code. */
+	param[0] = MBOX_VERIFY_CHECKSUM;
+	param[1] = risc_code_addr01;
+	if(qlogicpti_mbox_command(qpti, param, 1) ||
+	   (param[0] != MBOX_COMMAND_COMPLETE)) {
+		printk(KERN_EMERG "qlogicpti%d: New firmware csum failure!\n",
+		       qpti->qpti_id);
+		restore_flags(flags);
+		return 1;
+	}
+
+	/* Start using newly downloaded firmware. */
+	param[0] = MBOX_EXEC_FIRMWARE;
+	param[1] = risc_code_addr01;
+	qlogicpti_mbox_command(qpti, param, 1);
+
+	param[0] = MBOX_ABOUT_FIRMWARE;
+	if(qlogicpti_mbox_command(qpti, param, 1) ||
+	   (param[0] != MBOX_COMMAND_COMPLETE)) {
+		printk(KERN_EMERG "qlogicpti%d: AboutFirmware cmd fails.\n",
+		       qpti->qpti_id);
+		restore_flags(flags);
+		return 1;
+	}
+
+	/* Snag the major and minor revisions from the result. */
+	qpti->fware_majrev = param[1];
+	qpti->fware_minrev = param[2];
+
+	/* Load scsi initiator ID and interrupt level into sbus static ram. */
+	param[0] = MBOX_WRITE_RAM_WORD;
+	param[1] = 0xff80;
+	param[2] = (unsigned short) qpti->scsi_id;
+	qlogicpti_mbox_command(qpti, param, 1);
+
+	param[0] = MBOX_WRITE_RAM_WORD;
+	param[1] = 0xff00;
+	param[2] = (unsigned short) 3;
+	qlogicpti_mbox_command(qpti, param, 1);
+
+	restore_flags(flags);
+	return 0;
+}
+
+static int qlogicpti_verify_tmon(struct qlogicpti *qpti)
+{
+	int curstat = *qpti->sreg;
+
+	curstat &= 0xf0;
+	if(!(curstat & SREG_FUSE) && (qpti->swsreg & SREG_FUSE))
+		printk("qlogicpti%d: Fuse returned to normal state.\n", qpti->qpti_id);
+	if(!(curstat & SREG_TPOWER) && (qpti->swsreg & SREG_TPOWER))
+		printk("qlogicpti%d: termpwr back to normal state.\n", qpti->qpti_id);
+	if(curstat != qpti->swsreg) {
+		int error = 0;
+		if(curstat & SREG_FUSE) {
+			error++;
+			printk("qlogicpti%d: Fuse is open!\n", qpti->qpti_id);
+		}
+		if(curstat & SREG_TPOWER) {
+			error++;
+			printk("qlogicpti%d: termpwr failure\n", qpti->qpti_id);
+		}
+		if(qpti->differential &&
+		   (curstat & SREG_DSENSE) != SREG_DSENSE) {
+			error++;
+			printk("qlogicpti%d: You have a single ended device on a "
+			       "differential bus!  Please fix!\n", qpti->qpti_id);
+		}
+		qpti->swsreg = curstat;
+		return error;
+	}
+	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++) {
+		qpti->dev_param[i].device_flags = 0xf9;
+		qpti->dev_param[i].execution_throttle = 16;
+		qpti->dev_param[i].synchronous_period = 16;
+		qpti->dev_param[i].synchronous_offset = 12;
+		qpti->dev_param[i].device_enable = 1;
+	}
+}
+
+static void qlogicpti_intr_handler(int irq, void *dev_id, struct pt_regs *regs);
+
+/* Detect all PTI Qlogic ISP's in the machine. */
+int qlogicpti_detect(Scsi_Host_Template *tpnt)
+{
+	struct qlogicpti *qpti, *qlink;
+	struct Scsi_Host *qpti_host;
+	struct linux_sbus *sbus;
+	struct linux_sbus_device *qpti_dev, *sbdev_iter;
+	struct qlogicpti_regs *qregs;
+	volatile unsigned char *sreg;
+	unsigned char bsizes, bsizes_more;
+	int nqptis = 0, nqptis_in_use = 0;
+	int qpti_node;
+
+	tpnt->proc_dir = &proc_scsi_qlogicpti;
+	qptichain = 0;
+	if(!SBus_chain)
+		panic("No SBUS in qlogicpti_detect()");
+	for_each_sbus(sbus) {
+		for_each_sbusdev(sbdev_iter, sbus) {
+			qpti_dev = sbdev_iter;
+
+			/* Is this a red snapper? */
+			if(strcmp(qpti_dev->prom_name, "ptisp") &&
+			   strcmp(qpti_dev->prom_name, "PTI,ptisp"))
+				continue;
+
+			/* Yep, register and allocate software state. */
+			qpti_host = scsi_register(tpnt, sizeof(struct qlogicpti));
+			if(!qpti_host)
+				panic("Cannot register PTI Qlogic ISP SCSI host");
+			qpti = (struct qlogicpti *) qpti_host->hostdata;
+			if(!qpti)
+				panic("No qpti in hostdata");
+
+			/* We are wide capable, 16 targets. */
+			qpti_host->max_id = MAX_TARGETS;
+
+			/* Setup back pointers and misc. state. */
+			qpti->qhost = qpti_host;
+			qpti->qdev = qpti_dev;
+			qpti->qpti_id = nqptis++;
+
+			/* Insert this one into the global interrupt service chain. */
+			if(qptichain) {
+				qlink = qptichain;
+				while(qlink->next) qlink = qlink->next;
+				qlink->next = qpti;
+			} else {
+				qptichain = qpti;
+			}
+			qpti->next = 0;
+
+			/* More misc. prom information. */
+			qpti_node = qpti_dev->prom_node;
+			prom_getstring(qpti_node, "name", qpti->prom_name,
+				       sizeof(qpti->prom_name));
+			qpti->prom_node = qpti_node;
+
+			/* Setup the reg property for this device. */
+			prom_apply_sbus_ranges(qpti->qdev->my_bus,
+					       qpti->qdev->reg_addrs, 1);
+
+			/* Map in Qlogic,ISP regs and the PTI status reg. */
+			qpti->qregs = qregs = (struct qlogicpti_regs *)
+				sparc_alloc_io(qpti->qdev->reg_addrs[0].phys_addr, 0,
+					       qpti->qdev->reg_addrs[0].reg_size,
+					       "PTI Qlogic/ISP Registers",
+					       qpti->qdev->reg_addrs[0].which_io, 0x0);
+			if(!qregs)
+				panic("PTI Qlogic/ISP registers unmappable");
+
+			/* Map this one read only. */
+			qpti->sreg = sreg = (volatile unsigned char *)
+				sparc_alloc_io((qpti->qdev->reg_addrs[0].phys_addr +
+					       (16 * PAGE_SIZE)), 0,
+					       sizeof(unsigned char),
+					       "PTI Qlogic/ISP Status Reg",
+					       qpti->qdev->reg_addrs[0].which_io, 1);
+			if(!sreg)
+				panic("PTI Qlogic/ISP status reg unmappable");
+			qpti->swsreg = 0;
+
+			qpti_host->base = (unsigned char *)qregs;
+			qpti_host->io_port = (unsigned int) qregs;
+			qpti_host->n_io_port = (unsigned char)
+				qpti->qdev->reg_addrs[0].reg_size;
+
+			qpti_host->irq = qpti->irq = qpti->qdev->irqs[0].pri;
+
+			/* Allocate the irq only if necessary. */
+			for_each_qlogicpti(qlink) {
+				if((qlink != qpti) && (qpti->irq == qlink->irq)) {
+					goto qpti_irq_acquired; /* BASIC rulez */
+				}
+			}
+			if(request_irq(qpti->qhost->irq, qlogicpti_intr_handler,
+				       SA_SHIRQ, "PTI Qlogic/ISP SCSI", NULL)) {
+				printk("Cannot acquire PTI Qlogic/ISP irq line\n");
+				/* XXX Unmap regs, unregister scsi host, free things. */
+				continue;
+			}
+qpti_irq_acquired:
+			printk("qpti%d: IRQ %d ", qpti->qpti_id, qpti->qhost->irq);
+
+			/* Figure out our scsi ID on the bus */
+			qpti->scsi_id = prom_getintdefault(qpti->prom_node,
+							   "initiator-id",
+							   -1);
+			if(qpti->scsi_id == -1)
+				qpti->scsi_id = prom_getintdefault(qpti->prom_node,
+								   "scsi-initiator-id",
+								   -1);
+			if(qpti->scsi_id == -1)
+				qpti->scsi_id =
+					prom_getintdefault(qpti->qdev->my_bus->prom_node,
+							   "scsi-initiator-id", 7);
+			qpti->qhost->this_id = qpti->scsi_id;
+			printk("SCSI ID %d ", qpti->scsi_id);
+
+			/* Check for what the best SBUS burst we can use happens
+			 * to be on this machine.
+			 */
+			bsizes = prom_getintdefault(qpti->prom_node,"burst-sizes",0xff);
+			bsizes &= 0xff;
+			bsizes_more = prom_getintdefault(qpti->qdev->my_bus->prom_node,
+							 "burst-sizes", 0xff);
+			if(bsizes_more != 0xff)
+				bsizes &= bsizes_more;
+			if(bsizes == 0xff || (bsizes & DMA_BURST16)==0 ||
+			   (bsizes & DMA_BURST32) == 0)
+				bsizes = (DMA_BURST32 - 1);
+			qpti->bursts = bsizes;
+
+			/* The request and response queues must each be aligned
+			 * on a page boundry.
+			 */
+
+#define QSIZE(entries)	(((entries) + 1) * QUEUE_ENTRY_LEN)
+
+			qpti->res = sparc_dvma_malloc(QSIZE(RES_QUEUE_LEN),
+						      "PTISP Response Queue");
+			qpti->req = sparc_dvma_malloc(QSIZE(QLOGICISP_REQ_QUEUE_LEN),
+						      "PTISP Request Queue");
+
+#undef QSIZE
+
+
+			/* Set adapter and per-device default values. */
+			qlogicpti_set_hostdev_defaults(qpti);
+
+			/* Load the firmware. */
+			if(qlogicpti_load_firmware(qpti))
+				panic("PTI Qlogic/ISP firmware load failed");
+
+			/* Check the PTI status reg. */
+			if(qlogicpti_verify_tmon(qpti))
+				panic("PTI Qlogic/ISP tmon verification failed");
+
+			/* Reset the ISP and init res/req queues. */
+			if(qlogicpti_reset_hardware(qpti_host))
+				panic("PTI Qlogic/ISP cannot be reset");
+
+			printk("(Firmware v%d.%d) [%s Wide, using %s interface]\n",
+			       qpti->fware_majrev, qpti->fware_minrev,
+			       (qpti->ultra ? "Ultra" : "Fast"),
+			       (qpti->differential ? "differential" : "single ended"));
+
+			nqptis_in_use++;
+		}
+	}
+	printk("QPTI: Total of %d PTI Qlogic/ISP hosts found, %d actually in use.\n",
+	       nqptis, nqptis_in_use);
+	qptis_running = nqptis_in_use;
+	return nqptis;
+}
+
+int qlogicpti_release(struct Scsi_Host *host)
+{
+	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, NULL);
+	unmapioaddr((unsigned long)qregs);
+	unmapioaddr((unsigned long)qpti->sreg);
+
+	return 0;
+}
+
+const char *qlogicpti_info(struct Scsi_Host *host)
+{
+	static char buf[80];
+	struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
+
+	sprintf(buf, "PTI Qlogic,ISP SBUS SCSI irq %d regs at %08lx",
+		host->irq, (unsigned long) qpti->qregs);
+	return buf;
+}
+
+/* I am a certified frobtronicist. */
+static inline void marker_frob(struct Command_Entry *cmd)
+{
+	struct Marker_Entry *marker = (struct Marker_Entry *) cmd;
+
+	memset(marker, 0, sizeof(struct Marker_Entry));
+	marker->hdr.entry_cnt = 1;
+	marker->hdr.entry_type = ENTRY_MARKER;
+	marker->modifier = SYNC_ALL;
+	marker->rsvd = 0;
+}
+
+static inline void cmd_frob(struct Command_Entry *cmd, Scsi_Cmnd *Cmnd,
+			    struct qlogicpti *qpti)
+{
+	memset(cmd, 0, sizeof(struct Command_Entry));
+	cmd->hdr.entry_cnt = 1;
+	cmd->hdr.entry_type = ENTRY_COMMAND;
+	cmd->handle = (u_int) Cmnd;          /* magic mushroom */
+	cmd->target_id = Cmnd->target;
+	cmd->target_lun = Cmnd->lun;
+	cmd->cdb_length = Cmnd->cmd_len;
+	cmd->control_flags = 0;
+	if(Cmnd->device->tagged_supported) {
+		if(qpti->cmd_count[Cmnd->target] == 0)
+			qpti->tag_ages[Cmnd->target] = jiffies;
+		if((jiffies - qpti->tag_ages[Cmnd->target]) > (5*HZ)) {
+			cmd->control_flags = CFLAG_ORDERED_TAG;
+			qpti->tag_ages[Cmnd->target] = jiffies;
+		} else
+			cmd->control_flags = CFLAG_SIMPLE_TAG;
+	}
+	if((Cmnd->cmnd[0] == WRITE_6) ||
+	   (Cmnd->cmnd[0] == WRITE_10) ||
+	   (Cmnd->cmnd[0] == WRITE_12))
+		cmd->control_flags |= CFLAG_WRITE;
+	else
+		cmd->control_flags |= CFLAG_READ;
+	cmd->time_out = 30;
+	memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len);
+}
+
+/* Do it to it baby. */
+static inline u_int load_cmd(Scsi_Cmnd *Cmnd, struct Command_Entry *cmd,
+			     struct qlogicpti *qpti, struct qlogicpti_regs *qregs,
+			     u_int in_ptr, u_int out_ptr)
+{
+	struct dataseg * ds;
+	struct scatterlist *sg;
+	int sg_count = Cmnd->use_sg;
+	int i, n;
+
+	if(sg_count) {
+		mmu_get_scsi_sgl((struct mmu_sglist *)Cmnd->buffer, (Cmnd->use_sg - 1),
+				 qpti->qdev->my_bus);
+
+		cmd->segment_cnt = sg_count;
+		sg = (struct scatterlist *) Cmnd->request_buffer;
+		ds = cmd->dataseg;
+
+		/* Fill in first four sg entries: */
+		n = sg_count;
+		if(n > 4)
+			n = 4;
+		for(i = 0; i < n; i++, sg++) {
+			ds[i].d_base = (u_int) sg->dvma_address;
+			ds[i].d_count = (u_int) sg->length;
+		}
+		sg_count -= 4;
+		while(sg_count > 0) {
+			struct Continuation_Entry *cont;
+
+			++cmd->hdr.entry_cnt;
+			cont = (struct Continuation_Entry *) &qpti->req[in_ptr];
+			in_ptr = NEXT_REQ_PTR(in_ptr);
+			if(in_ptr == out_ptr) {
+				printk(KERN_EMERG "qlogicpti: Unexpected request queue overflow\n");
+				return -1;
+			}
+			cont->hdr.entry_type = ENTRY_CONTINUATION;
+			cont->hdr.entry_cnt = 0;
+			cont->hdr.sys_def_1 = 0;
+			cont->hdr.flags = 0;
+			cont->reserved = 0;
+			ds = cont->dataseg;
+			n = sg_count;
+			if(n > 7)
+				n = 7;
+			for(i = 0; i < n; i++, sg++) {
+				ds[i].d_base = (u_int) sg->dvma_address;
+				ds[i].d_count = (u_int) sg->length;
+			}
+			sg_count -= n;
+		}
+	} else {
+		Cmnd->SCp.ptr = mmu_get_scsi_one((char *)Cmnd->request_buffer,
+						 Cmnd->request_bufflen,
+						 qpti->qdev->my_bus);
+
+		cmd->dataseg[0].d_base = (u_int) Cmnd->SCp.ptr;
+		cmd->dataseg[0].d_count = Cmnd->request_bufflen;
+		cmd->segment_cnt = 1;
+	}
+	qpti->cmd_count[Cmnd->target]++;
+	qregs->mbox4 = in_ptr;
+	qpti->req_in_ptr = in_ptr;
+	return in_ptr;
+}
+
+static inline void update_can_queue(struct Scsi_Host *host, u_int in_ptr, u_int out_ptr)
+{
+	int num_free = QLOGICISP_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr);
+	host->can_queue = host->host_busy + num_free;
+	host->sg_tablesize = QLOGICISP_MAX_SG(num_free);
+}
+
+/*
+ * The middle SCSI layer ensures that queuecommand never gets invoked
+ * concurrently with itself or the interrupt handler (though the
+ * interrupt handler may call this routine as part of
+ * request-completion handling).
+ *
+ * "This code must fly." -davem
+ */
+int qlogicpti_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
+{
+	struct Scsi_Host *host = Cmnd->host;
+	struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
+	struct qlogicpti_regs *qregs = qpti->qregs;
+	u_int in_ptr = qpti->req_in_ptr;
+	u_int out_ptr = qregs->mbox4;
+	struct Command_Entry *cmd = (struct Command_Entry *) &qpti->req[in_ptr];
+
+	Cmnd->scsi_done = done;
+	in_ptr = NEXT_REQ_PTR(in_ptr);
+	if(in_ptr == out_ptr) {
+		printk(KERN_EMERG "qlogicpti%d: request queue overflow\n", qpti->qpti_id);
+		return 1;
+	}
+	if(qpti->send_marker) {
+		marker_frob(cmd);
+		qpti->send_marker = 0;
+		if(NEXT_REQ_PTR(in_ptr) == out_ptr) {
+			qregs->mbox4 = in_ptr;
+			qpti->req_in_ptr = in_ptr;
+			printk(KERN_EMERG "qlogicpti%d: request queue overflow\n", qpti->qpti_id);
+			return 1;
+		}
+		cmd = (struct Command_Entry *) &qpti->req[in_ptr];
+		in_ptr = NEXT_REQ_PTR(in_ptr);
+	}
+	cmd_frob(cmd, Cmnd, qpti);
+	if((in_ptr = load_cmd(Cmnd, cmd, qpti, qregs, in_ptr, out_ptr)) == -1)
+		return 1;
+	update_can_queue(host, in_ptr, out_ptr);
+	return 0;
+}
+
+static int qlogicpti_return_status(struct Status_Entry *sts)
+{
+	int host_status = DID_ERROR;
+
+	switch(sts->completion_status) {
+	      case CS_COMPLETE:
+		host_status = DID_OK;
+		break;
+	      case CS_INCOMPLETE:
+		if (!(sts->state_flags & SF_GOT_BUS))
+			host_status = DID_NO_CONNECT;
+		else if (!(sts->state_flags & SF_GOT_TARGET))
+			host_status = DID_BAD_TARGET;
+		else if (!(sts->state_flags & SF_SENT_CDB))
+			host_status = DID_ERROR;
+		else if (!(sts->state_flags & SF_TRANSFERRED_DATA))
+			host_status = DID_ERROR;
+		else if (!(sts->state_flags & SF_GOT_STATUS))
+			host_status = DID_ERROR;
+		else if (!(sts->state_flags & SF_GOT_SENSE))
+			host_status = DID_ERROR;
+		break;
+	      case CS_DMA_ERROR:
+	      case CS_TRANSPORT_ERROR:
+		host_status = DID_ERROR;
+		break;
+	      case CS_RESET_OCCURRED:
+		host_status = DID_RESET;
+		break;
+	      case CS_ABORTED:
+		host_status = DID_ABORT;
+		break;
+	      case CS_TIMEOUT:
+		host_status = DID_TIME_OUT;
+		break;
+	      case CS_DATA_OVERRUN:
+	      case CS_COMMAND_OVERRUN:
+	      case CS_STATUS_OVERRUN:
+	      case CS_BAD_MESSAGE:
+	      case CS_NO_MESSAGE_OUT:
+	      case CS_EXT_ID_FAILED:
+	      case CS_IDE_MSG_FAILED:
+	      case CS_ABORT_MSG_FAILED:
+	      case CS_NOP_MSG_FAILED:
+	      case CS_PARITY_ERROR_MSG_FAILED:
+	      case CS_DEVICE_RESET_MSG_FAILED:
+	      case CS_ID_MSG_FAILED:
+	      case CS_UNEXP_BUS_FREE:
+		host_status = DID_ERROR;
+		break;
+	      case CS_DATA_UNDERRUN:
+		host_status = DID_OK;
+		break;
+	      default:
+		printk(KERN_EMERG "qlogicpti : unknown completion status 0x%04x\n",
+		       sts->completion_status);
+		host_status = DID_ERROR;
+		break;
+	}
+
+	return (sts->scsi_status & STATUS_MASK) | (host_status << 16);
+}
+
+static void qlogicpti_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	static int running = 0;
+	Scsi_Cmnd *Cmnd;
+	struct Status_Entry *sts;
+	struct qlogicpti *qpti;
+	u_int in_ptr, out_ptr;
+	int again;
+
+	/* It is ok to take irq's on one qpti while the other
+	 * is amidst the processing of a reset.
+	 */
+	running++;
+
+#if 0 /* XXX Investigate why resets cause this with one controller. */
+	if(running > qptis_running)
+		printk("qlogicpti_intr_handler: yieee, recursive interrupt!\n");
+#endif
+
+	/* Handle all ISP interrupts showing */
+repeat:
+	again = 0;
+	for_each_qlogicpti(qpti) {
+		if(qpti->qregs->sbus_stat & SBUS_STAT_RINT) {
+			struct qlogicpti_regs *qregs = qpti->qregs;
+
+			again = 1;
+			in_ptr = qregs->mbox5;
+			qregs->hcctrl = HCCTRL_CRIRQ;
+			if(qregs->sbus_semaphore & SBUS_SEMAPHORE_LCK) {
+				switch(qregs->mbox0) {
+				case ASYNC_SCSI_BUS_RESET:
+				case EXECUTION_TIMEOUT_RESET:
+					qpti->send_marker = 1;
+					break;
+				case INVALID_COMMAND:
+				case HOST_INTERFACE_ERROR:
+				case COMMAND_ERROR:
+				case COMMAND_PARAM_ERROR:
+					break;
+				}
+				qregs->sbus_semaphore = 0;
+			}
+
+			/* This looks like a network driver! */
+			out_ptr = qpti->res_out_ptr;
+			while(out_ptr != in_ptr) {
+				sts = (struct Status_Entry *) &qpti->res[out_ptr];
+				out_ptr = NEXT_RES_PTR(out_ptr);
+				Cmnd = (Scsi_Cmnd *) sts->handle; /* but_to_virt?!?! */
+				if(sts->completion_status == CS_RESET_OCCURRED ||
+				   sts->completion_status == CS_ABORTED ||
+				   (sts->status_flags & STF_BUS_RESET))
+					qpti->send_marker = 1;
+
+				if(sts->state_flags & SF_GOT_SENSE)
+					memcpy(Cmnd->sense_buffer, sts->req_sense_data,
+					       sizeof(Cmnd->sense_buffer));
+
+				if(sts->hdr.entry_type == ENTRY_STATUS)
+					Cmnd->result = qlogicpti_return_status(sts);
+				else
+					Cmnd->result = DID_ERROR << 16;
+
+				if(Cmnd->use_sg)
+					mmu_release_scsi_sgl((struct mmu_sglist *)
+							     Cmnd->buffer,
+							     Cmnd->use_sg - 1,
+							     qpti->qdev->my_bus);
+				else
+					mmu_release_scsi_one((char *)
+							     Cmnd->SCp.ptr,
+							     Cmnd->request_bufflen,
+							     qpti->qdev->my_bus);
+
+				qpti->cmd_count[Cmnd->target]--;
+				qregs->mbox5 = out_ptr;
+				Cmnd->scsi_done(Cmnd);
+			}
+			qpti->res_out_ptr = out_ptr;
+		}
+	}
+	if(again)
+		goto repeat;
+	running--;
+}
+
+int qlogicpti_abort(Scsi_Cmnd *Cmnd)
+{
+	u_short param[6];
+	struct Scsi_Host *host = Cmnd->host;
+	struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
+	int return_status = SCSI_ABORT_SUCCESS;
+
+	printk(KERN_EMERG "qlogicpti : Aborting cmd for tgt[%d] lun[%d]\n",
+	       (int)Cmnd->target, (int)Cmnd->lun);
+	qlogicpti_disable_irqs(qpti->qregs);
+	param[0] = MBOX_ABORT;
+	param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun;
+	param[2] = ((unsigned int)Cmnd) >> 16;
+	param[3] = ((unsigned int)Cmnd) & 0xffff;
+	if(qlogicpti_mbox_command(qpti, param, 0) ||
+	   (param[0] != MBOX_COMMAND_COMPLETE)) {
+		printk(KERN_EMERG "qlogicpti : scsi abort failure: %x\n", param[0]);
+		return_status = SCSI_ABORT_ERROR;
+	}
+	qlogicpti_enable_irqs(qpti->qregs);
+	return return_status;
+}
+
+int qlogicpti_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
+{
+	u_short param[6];
+	struct Scsi_Host *host = Cmnd->host;
+	struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
+	int return_status = SCSI_RESET_SUCCESS;
+
+	printk(KERN_EMERG "qlogicpti : Resetting SCSI bus!\n");
+	qlogicpti_disable_irqs(qpti->qregs);
+	param[0] = MBOX_BUS_RESET;
+	param[1] = qpti->host_param.bus_reset_delay;
+	if(qlogicpti_mbox_command(qpti, param, 0) ||
+	   (param[0] != MBOX_COMMAND_COMPLETE)) {
+		printk(KERN_EMERG "qlogicisp : scsi bus reset failure: %x\n", param[0]);
+		return_status = SCSI_RESET_ERROR;
+	}
+	qlogicpti_enable_irqs(qpti->qregs);
+	return return_status;
+}
+
+#ifdef MODULE
+Scsi_Host_Template driver_template = QLOGICPTI;
+
+#include "scsi_module.c"
+#endif /* MODULE */
diff -u --recursive --new-file v2.1.15/linux/drivers/scsi/qlogicpti.h linux/drivers/scsi/qlogicpti.h
--- v2.1.15/linux/drivers/scsi/qlogicpti.h	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/qlogicpti.h	Fri Dec 13 11:37:37 1996
@@ -0,0 +1,746 @@
+/* qlogicpti.h: Performance Technologies QlogicISP sbus card defines.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+#ifndef _QLOGICPTI_H
+#define _QLOGICPTI_H
+
+struct qlogicpti_regs {
+	/* SBUS control registers. */
+	volatile unsigned short  sbus_idlow;      /* SBUS ID, low bytes             */
+	volatile unsigned short  sbus_idhi;       /* SBUS ID, high bytes            */
+	volatile unsigned short  sbus_cfg0;       /* SBUS Config reg zero           */
+	volatile unsigned short  sbus_cfg1;       /* SBUS Config reg one            */
+	volatile unsigned short  sbus_ctrl;       /* SBUS Control reg               */
+	volatile unsigned short  sbus_stat;       /* SBUS Status reg                */
+	volatile unsigned short  sbus_semaphore;  /* SBUS Semaphore, p/v this...    */
+	unsigned char _unused0[18];               /* Reserved...                    */
+
+	/* Command DVMA control registers. */
+	volatile unsigned short  cmd_dma_cfg;     /* CMD DVMA Config reg            */
+	volatile unsigned short  cmd_dma_ctrl;    /* CMD DVMA Control reg           */
+	volatile unsigned short  cmd_dma_stat;    /* CMD DVMA Status reg            */
+	volatile unsigned short  cmd_dma_fstat;   /* CMD DVMA FIFO Status reg       */
+	volatile unsigned short  cmd_dma_cnt;     /* CMD DVMA Counter reg           */
+	unsigned short _unused1;                  /* Reserved...                    */
+	volatile unsigned short  cmd_dma_alow;    /* CMD DVMA Address low bytes     */
+	volatile unsigned short  cmd_dma_ahi;     /* CMD DVMA Address high bytes    */
+	unsigned char _unused2[16];               /* Reserved...                    */
+
+	/* Data DVMA control registers. */
+	volatile unsigned short  data_dma_cfg;    /* DATA DVMA Config reg           */
+	volatile unsigned short  data_dma_ctrl;   /* DATA DVMA Control reg          */
+	volatile unsigned short  data_dma_stat;   /* DATA DVMA Status reg           */
+	volatile unsigned short  data_dma_fstat;  /* DATA DVMA FIFO Status reg      */
+	volatile unsigned short  data_dma_clo;    /* DATA DVMA Counter low bytes    */
+	volatile unsigned short  data_dma_chi;    /* DATA DVMA Counter high bytes   */
+	volatile unsigned short  data_dma_alow;   /* DATA DVMA Address low bytes    */
+	volatile unsigned short  data_dma_ahi;    /* DATA DVMA Address high bytes   */
+	unsigned char _unused3[16];               /* Reserved...                    */
+
+	/* Data FIFO registers. */
+	volatile unsigned short  fcmd;            /* FIFO Command port              */
+	volatile unsigned short  fdata;           /* FIFO Data port                 */
+	unsigned char _unused4[28];               /* Reserved...                    */
+
+	/* Mailboxen. */
+	volatile unsigned short  mbox0;           /* MailBOX 0                      */
+	volatile unsigned short  mbox1;           /* MailBOX 1                      */
+	volatile unsigned short  mbox2;           /* MailBOX 2                      */
+	volatile unsigned short  mbox3;           /* MailBOX 3                      */
+	volatile unsigned short  mbox4;           /* MailBOX 4                      */
+	volatile unsigned short  mbox5;           /* MailBOX 5                      */
+	unsigned char _unused5[372];              /* Reserved...                    */
+
+	/* Scsi processor registers. */
+	volatile unsigned short  cpu_id;          /* PART ID                        */
+	volatile unsigned short  cpu_cfg1;        /* Config reg 1                   */
+	volatile unsigned short  cpu_cfg2;        /* Config reg 2                   */
+	volatile unsigned short  cpu_cfg3;        /* Config reg 3                   */
+	unsigned char _unused6[4];                /* Reserved...                    */
+	volatile unsigned short  cpu_pc;          /* Program Counter                */
+	unsigned short _unused7;                  /* Reserved...                    */
+	volatile unsigned short  cpu_rpc;         /* Return Program Counter         */
+	unsigned short _unused8;                  /* Reserved...                    */
+	volatile unsigned short  cpu_cmd;         /* Command                        */
+	unsigned short _unused9;                  /* Reserved...                    */
+	volatile unsigned short  cpu_irq;         /* IRQ status                     */
+	unsigned short _unused10;                 /* Reserved...                    */
+	volatile unsigned short  cpu_seq;         /* Sequence reg                   */
+	volatile unsigned short  cpu_gerr;        /* Gross Error reg (ESP lineage?) */
+	volatile unsigned short  cpu_exc;         /* Enable Exception reg           */
+	unsigned short _unused11;                 /* Reserved...                    */
+	volatile unsigned short  cpu_oride;       /* Override reg                   */
+	unsigned short _unused12;                 /* Reserved...                    */
+	volatile unsigned short  cpu_lbase;       /* Literal Base reg               */
+	unsigned short _unused13;                 /* Reserved...                    */
+	volatile unsigned short  cpu_uflags;      /* User Flags reg                 */
+	unsigned short _unused14;                 /* Reserved...                    */
+	volatile unsigned short  cpu_uexc;        /* User Exception reg             */
+	unsigned short _unused15;                 /* Reserved...                    */
+	volatile unsigned short  cpu_bkpt;        /* Breakpoint reg                 */
+	unsigned short _unused16[5];              /* Reserved...                    */
+	volatile unsigned short  cpu_sid;         /* SCSI ID reg                    */
+	volatile unsigned short  cpu_dcfg1;       /* Device Config 1                */
+	volatile unsigned short  cpu_dcfg2;       /* Device Config 2                */
+	unsigned short _unused17;                 /* Reserved...                    */
+	volatile unsigned short  cpu_pptr;        /* Phase Pointer                  */
+	unsigned short _unused18;                 /* Reserved...                    */
+	volatile unsigned short  cpu_bptr;        /* Buffer Pointer                 */
+	unsigned short _unused19;                 /* Reserved...                    */
+	volatile unsigned short  cpu_bcnt;        /* Buffer Counter                 */
+	volatile unsigned short  cpu_buf;         /* Buffer itself                  */
+	volatile unsigned short  cpu_bbyte;       /* Buffer Byte                    */
+	volatile unsigned short  cpu_bword;       /* Buffer Word                    */
+	unsigned short _unused20;                 /* Reserved...                    */
+	volatile unsigned short  cpu_fifo;        /* FIFO                           */
+	volatile unsigned short  cpu_fstat;       /* FIFO Status                    */
+	volatile unsigned short  cpu_ftop;        /* Top of FIFO                    */
+	volatile unsigned short  cpu_fbottom;     /* Bottom of FIFO                 */
+	unsigned short _unused21;                 /* Reserved...                    */
+	volatile unsigned short  cpu_treg;        /* Transfer reg                   */
+	unsigned short _unused22;                 /* Reserved...                    */
+	volatile unsigned short  cpu_clo;         /* Transfer Count low bytes       */
+	volatile unsigned short  cpu_chi;         /* Transfer Count high bytes      */
+	volatile unsigned short  cpu_cntlo;       /* Transfer Counter low bytes     */
+	volatile unsigned short  cpu_cnthi;       /* Transfer Counter low bytes     */
+	volatile unsigned short  cpu_adata;       /* Arbitration Data               */
+	volatile unsigned short  cpu_pctrl;       /* Pin Control                    */
+	volatile unsigned short  cpu_pdata;       /* Pin Data                       */
+	volatile unsigned short  cpu_pdiff;       /* Differential Pins              */
+	unsigned char _unused23[392];             /* Reserved...                    */
+
+	/* RISC processor registers. */
+	volatile unsigned short  risc_a;          /* Accumulator                    */
+	volatile unsigned short  risc_r[15];      /* General Purpose Registers      */
+	volatile unsigned short  risc_psr;        /* Processor Status Register      */
+	volatile unsigned short  risc_ivec;       /* Interrupt Vector               */
+	volatile unsigned short  risc_pcr;        /* Processor Control Register     */
+	volatile unsigned short  risc_raddr0;     /* RAM Addr reg 0                 */
+	volatile unsigned short  risc_raddr1;     /* RAM Addr reg 1                 */
+	volatile unsigned short  risc_lcr;        /* Loop Counter reg               */
+	volatile unsigned short  risc_pc;         /* Program Counter                */
+	volatile unsigned short  risc_mtreg;      /* Memory Timing reg              */
+	volatile unsigned short  risc_embreg;     /* External Memory Boundry reg    */
+	volatile unsigned short  risc_sp;         /* Stack Pointer                  */
+	volatile unsigned short  risc_hrev;       /* Hardware Revision              */
+	unsigned char _unused24[10];              /* Reserved...                    */
+
+	/* Generic control/command registers. */
+	volatile unsigned short  hcctrl;          /* Host cmd/control reg           */
+	volatile unsigned short  pbkpt0;          /* Processor Breakpoint 0         */
+	volatile unsigned short  pbkpt1;          /* Processor Breakpoint 1         */
+	volatile unsigned short  tcntrl;          /* Test Control reg               */
+	volatile unsigned short  tmreg;           /* Test Mode reg                  */
+};
+
+#define MAX_TARGETS	16
+#define MAX_LUNS	8
+
+/* With the qlogic interface, every queue slot can hold a SCSI
+ * command with up to 4 scatter/gather entries.  If we need more
+ * than 4 entries, continuation entries can be used that hold
+ * another 7 entries each.  Unlike for other drivers, this means
+ * that the maximum number of scatter/gather entries we can
+ * support at any given time is a function of the number of queue
+ * slots available.  That is, host->can_queue and host->sg_tablesize
+ * are dynamic and _not_ independent.  This all works fine because
+ * requests are queued serially and the scatter/gather limit is
+ * determined for each queue request anew.
+ */
+#define QLOGICISP_REQ_QUEUE_LEN	255	/* must be power of two - 1 */
+#define QLOGICISP_MAX_SG(ql)	(4 + ((ql) > 0) ? 7*((ql) - 1) : 0)
+
+#ifndef NULL
+#define NULL (0)
+#endif
+
+int qlogicpti_detect(Scsi_Host_Template *);
+int qlogicpti_release(struct Scsi_Host *);
+const char * qlogicpti_info(struct Scsi_Host *);
+int qlogicpti_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
+int qlogicpti_abort(Scsi_Cmnd *);
+int qlogicpti_reset(Scsi_Cmnd *, unsigned int);
+
+extern struct proc_dir_entry proc_scsi_qlogicpti;
+
+/* mailbox command complete status codes */
+#define MBOX_COMMAND_COMPLETE		0x4000
+#define INVALID_COMMAND			0x4001
+#define HOST_INTERFACE_ERROR		0x4002
+#define TEST_FAILED			0x4003
+#define COMMAND_ERROR			0x4005
+#define COMMAND_PARAM_ERROR		0x4006
+
+/* async event status codes */
+#define ASYNC_SCSI_BUS_RESET		0x8001
+#define SYSTEM_ERROR			0x8002
+#define REQUEST_TRANSFER_ERROR		0x8003
+#define RESPONSE_TRANSFER_ERROR		0x8004
+#define REQUEST_QUEUE_WAKEUP		0x8005
+#define EXECUTION_TIMEOUT_RESET		0x8006
+
+/* Am I fucking pedantic or what? */
+struct Entry_header {
+#ifdef __BIG_ENDIAN
+	u_char	entry_cnt;
+	u_char	entry_type;
+	u_char	flags;
+	u_char	sys_def_1;
+#else /* __LITTLE_ENDIAN */
+	u_char	entry_type;
+	u_char	entry_cnt;
+	u_char	sys_def_1;
+	u_char	flags;
+#endif
+};
+
+/* entry header type commands */
+#define ENTRY_COMMAND		1
+#define ENTRY_CONTINUATION	2
+#define ENTRY_STATUS		3
+#define ENTRY_MARKER		4
+#define ENTRY_EXTENDED_COMMAND	5
+
+/* entry header flag definitions */
+#define EFLAG_CONTINUATION	1
+#define EFLAG_BUSY		2
+#define EFLAG_BAD_HEADER	4
+#define EFLAG_BAD_PAYLOAD	8
+
+struct dataseg {
+	u_int			d_base;
+	u_int			d_count;
+};
+
+struct Command_Entry {
+	struct Entry_header	hdr;
+	u_int			handle;
+#ifdef __BIG_ENDIAN
+	u_char			target_id;
+	u_char			target_lun;
+#else /* __LITTLE_ENDIAN */
+	u_char			target_lun;
+	u_char			target_id;
+#endif
+	u_short			cdb_length;
+	u_short			control_flags;
+	u_short			rsvd;
+	u_short			time_out;
+	u_short			segment_cnt;
+	u_char			cdb[12];
+	struct dataseg		dataseg[4];
+};
+
+/* command entry control flag definitions */
+#define CFLAG_NODISC		0x01
+#define CFLAG_HEAD_TAG		0x02
+#define CFLAG_ORDERED_TAG	0x04
+#define CFLAG_SIMPLE_TAG	0x08
+#define CFLAG_TAR_RTN		0x10
+#define CFLAG_READ		0x20
+#define CFLAG_WRITE		0x40
+
+struct Ext_Command_Entry {
+	struct Entry_header	hdr;
+	u_int			handle;
+#ifdef __BIG_ENDIAN
+	u_char			target_id;
+	u_char			target_lun;
+#else /* __LITTLE_ENDIAN */
+	u_char			target_lun;
+	u_char			target_id;
+#endif
+	u_short			cdb_length;
+	u_short			control_flags;
+	u_short			rsvd;
+	u_short			time_out;
+	u_short			segment_cnt;
+	u_char			cdb[44];
+};
+
+struct Continuation_Entry {
+	struct Entry_header	hdr;
+	u_int			reserved;
+	struct dataseg		dataseg[7];
+};
+
+struct Marker_Entry {
+	struct Entry_header	hdr;
+	u_int			reserved;
+#ifdef __BIG_ENDIAN
+	u_char			target_id;
+	u_char			target_lun;
+#else /* __LITTLE_ENDIAN */
+	u_char			target_lun;
+	u_char			target_id;
+#endif
+#ifdef __BIG_ENDIAN
+	u_char			rsvd;
+	u_char			modifier;
+#else /* __LITTLE_ENDIAN */
+	u_char			modifier;
+	u_char			rsvd;
+#endif
+	u_char			rsvds[52];
+};
+
+/* marker entry modifier definitions */
+#define SYNC_DEVICE	0
+#define SYNC_TARGET	1
+#define SYNC_ALL	2
+
+struct Status_Entry {
+	struct Entry_header	hdr;
+	u_int			handle;
+	u_short			scsi_status;
+	u_short			completion_status;
+	u_short			state_flags;
+	u_short			status_flags;
+	u_short			time;
+	u_short			req_sense_len;
+	u_int			residual;
+	u_char			rsvd[8];
+	u_char			req_sense_data[32];
+};
+
+/* status entry completion status definitions */
+#define CS_COMPLETE			0x0000
+#define CS_INCOMPLETE			0x0001
+#define CS_DMA_ERROR			0x0002
+#define CS_TRANSPORT_ERROR		0x0003
+#define CS_RESET_OCCURRED		0x0004
+#define CS_ABORTED			0x0005
+#define CS_TIMEOUT			0x0006
+#define CS_DATA_OVERRUN			0x0007
+#define CS_COMMAND_OVERRUN		0x0008
+#define CS_STATUS_OVERRUN		0x0009
+#define CS_BAD_MESSAGE			0x000a
+#define CS_NO_MESSAGE_OUT		0x000b
+#define CS_EXT_ID_FAILED		0x000c
+#define CS_IDE_MSG_FAILED		0x000d
+#define CS_ABORT_MSG_FAILED		0x000e
+#define CS_REJECT_MSG_FAILED		0x000f
+#define CS_NOP_MSG_FAILED		0x0010
+#define CS_PARITY_ERROR_MSG_FAILED	0x0011
+#define CS_DEVICE_RESET_MSG_FAILED	0x0012
+#define CS_ID_MSG_FAILED		0x0013
+#define CS_UNEXP_BUS_FREE		0x0014
+#define CS_DATA_UNDERRUN		0x0015
+
+/* status entry state flag definitions */
+#define SF_GOT_BUS			0x0100
+#define SF_GOT_TARGET			0x0200
+#define SF_SENT_CDB			0x0400
+#define SF_TRANSFERRED_DATA		0x0800
+#define SF_GOT_STATUS			0x1000
+#define SF_GOT_SENSE			0x2000
+
+/* status entry status flag definitions */
+#define STF_DISCONNECT			0x0001
+#define STF_SYNCHRONOUS			0x0002
+#define STF_PARITY_ERROR		0x0004
+#define STF_BUS_RESET			0x0008
+#define STF_DEVICE_RESET		0x0010
+#define STF_ABORTED			0x0020
+#define STF_TIMEOUT			0x0040
+#define STF_NEGOTIATION			0x0080
+
+/* mailbox commands */
+#define MBOX_NO_OP			0x0000
+#define MBOX_LOAD_RAM			0x0001
+#define MBOX_EXEC_FIRMWARE		0x0002
+#define MBOX_DUMP_RAM			0x0003
+#define MBOX_WRITE_RAM_WORD		0x0004
+#define MBOX_READ_RAM_WORD		0x0005
+#define MBOX_MAILBOX_REG_TEST		0x0006
+#define MBOX_VERIFY_CHECKSUM		0x0007
+#define MBOX_ABOUT_FIRMWARE		0x0008
+#define MBOX_CHECK_FIRMWARE		0x000e
+#define MBOX_INIT_REQ_QUEUE		0x0010
+#define MBOX_INIT_RES_QUEUE		0x0011
+#define MBOX_EXECUTE_IOCB		0x0012
+#define MBOX_WAKE_UP			0x0013
+#define MBOX_STOP_FIRMWARE		0x0014
+#define MBOX_ABORT			0x0015
+#define MBOX_ABORT_DEVICE		0x0016
+#define MBOX_ABORT_TARGET		0x0017
+#define MBOX_BUS_RESET			0x0018
+#define MBOX_STOP_QUEUE			0x0019
+#define MBOX_START_QUEUE		0x001a
+#define MBOX_SINGLE_STEP_QUEUE		0x001b
+#define MBOX_ABORT_QUEUE		0x001c
+#define MBOX_GET_DEV_QUEUE_STATUS	0x001d
+#define MBOX_GET_FIRMWARE_STATUS	0x001f
+#define MBOX_GET_INIT_SCSI_ID		0x0020
+#define MBOX_GET_SELECT_TIMEOUT		0x0021
+#define MBOX_GET_RETRY_COUNT		0x0022
+#define MBOX_GET_TAG_AGE_LIMIT		0x0023
+#define MBOX_GET_CLOCK_RATE		0x0024
+#define MBOX_GET_ACT_NEG_STATE		0x0025
+#define MBOX_GET_ASYNC_DATA_SETUP_TIME	0x0026
+#define MBOX_GET_SBUS_PARAMS		0x0027
+#define MBOX_GET_TARGET_PARAMS		0x0028
+#define MBOX_GET_DEV_QUEUE_PARAMS	0x0029
+#define MBOX_SET_INIT_SCSI_ID		0x0030
+#define MBOX_SET_SELECT_TIMEOUT		0x0031
+#define MBOX_SET_RETRY_COUNT		0x0032
+#define MBOX_SET_TAG_AGE_LIMIT		0x0033
+#define MBOX_SET_CLOCK_RATE		0x0034
+#define MBOX_SET_ACTIVE_NEG_STATE	0x0035
+#define MBOX_SET_ASYNC_DATA_SETUP_TIME	0x0036
+#define MBOX_SET_SBUS_CONTROL_PARAMS	0x0037
+#define MBOX_SET_TARGET_PARAMS		0x0038
+#define MBOX_SET_DEV_QUEUE_PARAMS	0x0039
+
+struct host_param {
+	u_short		initiator_scsi_id;
+	u_short		bus_reset_delay;
+	u_short		retry_count;
+	u_short		retry_delay;
+	u_short		async_data_setup_time;
+	u_short		req_ack_active_negation;
+	u_short		data_line_active_negation;
+	u_short		data_dma_burst_enable;
+	u_short		command_dma_burst_enable;
+	u_short		tag_aging;
+	u_short		selection_timeout;
+	u_short		max_queue_depth;
+};
+
+/*
+ * Device Flags:
+ *
+ * Bit  Name
+ * ---------
+ *  7   Disconnect Privilege
+ *  6   Parity Checking
+ *  5   Wide Data Transfers
+ *  4   Synchronous Data Transfers
+ *  3   Tagged Queuing
+ *  2   Automatic Request Sense
+ *  1   Stop Queue on Check Condition
+ *  0   Renegotiate on Error
+ */
+
+struct dev_param {
+	u_short		device_flags;
+	u_short		execution_throttle;
+	u_short		synchronous_period;
+	u_short		synchronous_offset;
+	u_short		device_enable;
+	u_short		reserved; /* pad */
+};
+
+/*
+ * The result queue can be quite a bit smaller since continuation entries
+ * do not show up there:
+ */
+#define RES_QUEUE_LEN		255	/* Must be power of two - 1 */
+#define QUEUE_ENTRY_LEN		64
+
+#define NEXT_REQ_PTR(wheee)   (((wheee) + 1) & QLOGICISP_REQ_QUEUE_LEN)
+#define NEXT_RES_PTR(wheee)   (((wheee) + 1) & RES_QUEUE_LEN)
+#define PREV_REQ_PTR(wheee)   (((wheee) - 1) & QLOGICISP_REQ_QUEUE_LEN)
+#define PREV_RES_PTR(wheee)   (((wheee) - 1) & RES_QUEUE_LEN)
+
+struct pti_queue_entry {
+	char __opaque[QUEUE_ENTRY_LEN];
+};
+
+/* Software state for the driver. */
+struct qlogicpti {
+	/* These are the hot elements in the cache, so they come first. */
+	struct qlogicpti         *next;                 /* Next active adapter        */
+	struct qlogicpti_regs    *qregs;                /* Adapter registers          */
+	u_int	                  req_in_ptr;		/* index of next request slot */
+	u_int	                  res_out_ptr;		/* index of next result slot  */
+	struct pti_queue_entry   *res;                  /* Pointer to RESPONSE dvma   */
+	struct pti_queue_entry   *req;                  /* Pointer to REQUEST dvma    */
+	int                       cmd_count[MAX_TARGETS];
+	unsigned long             tag_ages[MAX_TARGETS];
+	long	                  send_marker;		/* must we send a marker?     */
+
+	/* The rest of the elements are unimportant for performance. */
+	u_char	                  fware_majrev, fware_minrev;
+	struct Scsi_Host         *qhost;
+	struct linux_sbus_device *qdev;
+	int                       qpti_id;
+	int                       scsi_id;
+	int                       prom_node;
+	char                      prom_name[64];
+	int                       irq;
+	char                      differential, ultra;
+	unsigned char             bursts;
+	struct	host_param        host_param;
+	struct	dev_param         dev_param[MAX_TARGETS];
+	
+	volatile unsigned char   *sreg;
+#define SREG_TPOWER               0x80   /* State of termpwr           */
+#define SREG_FUSE                 0x40   /* State of on board fuse     */
+#define SREG_PDISAB               0x20   /* Disable state for power on */
+#define SREG_DSENSE               0x10   /* Sense for differential     */
+#define SREG_IMASK                0x0c   /* Interrupt level            */
+#define SREG_SPMASK               0x03   /* Mask for switch pack       */
+	unsigned char             swsreg;
+
+#if 0
+	char	res[RES_QUEUE_LEN+1][QUEUE_ENTRY_LEN];
+	char	req[QLOGICISP_REQ_QUEUE_LEN+1][QUEUE_ENTRY_LEN];
+#endif
+};
+
+/* How to twiddle them bits... */
+
+/* SBUS config register zero. */
+#define SBUS_CFG0_HREVMASK      0x000f      /* To get the revision              */
+
+/* SBUS config register one. */
+#define SBUS_CFG1_EPAR          0x0100      /* Enable parity checking           */
+#define SBUS_CFG1_FMASK         0x00f0      /* Forth code cycle mask            */
+#define SBUS_CFG1_BENAB         0x0004      /* Burst dvma enable                */
+#define SBUS_CFG1_B64           0x0003      /* Enable 64byte bursts             */
+#define SBUS_CFG1_B32           0x0002      /* Enable 32byte bursts             */
+#define SBUS_CFG1_B16           0x0001      /* Enable 16byte bursts             */
+#define SBUS_CFG1_B8            0x0008      /* Enable 8byte bursts              */
+
+/* SBUS control register */
+#define SBUS_CTRL_EDIRQ         0x0020      /* Enable Data DVMA Interrupts      */
+#define SBUS_CTRL_ECIRQ         0x0010      /* Enable Command DVMA Interrupts   */
+#define SBUS_CTRL_ESIRQ         0x0008      /* Enable SCSI Processor Interrupts */
+#define SBUS_CTRL_ERIRQ         0x0004      /* Enable RISC Processor Interrupts */
+#define SBUS_CTRL_GENAB         0x0002      /* Global Interrupt Enable          */
+#define SBUS_CTRL_RESET         0x0001      /* Soft Reset                       */
+
+/* SBUS status register */
+#define SBUS_STAT_DINT          0x0020      /* Data DVMA IRQ pending            */
+#define SBUS_STAT_CINT          0x0010      /* Command DVMA IRQ pending         */
+#define SBUS_STAT_SINT          0x0008      /* SCSI Processor IRQ pending       */
+#define SBUS_STAT_RINT          0x0004      /* RISC Processor IRQ pending       */
+#define SBUS_STAT_GINT          0x0002      /* Global IRQ pending               */
+
+/* SBUS semaphore register */
+#define SBUS_SEMAPHORE_STAT     0x0002      /* Semaphore status bit             */
+#define SBUS_SEMAPHORE_LCK      0x0001      /* Semaphore lock bit               */
+
+/* DVMA config register */
+#define DMA_CFG_DVMAENAB        0x0008      /* Enable scsi cpu --> dma data     */
+#define DMA_CFG_EIRQ            0x0004      /* Enable interrupts to risc cpu    */
+#define DMA_CFG_EBURST          0x0002      /* Enable sbus dvma bursts          */
+#define DMA_CFG_DIRECTION       0x0001      /* DMA direction (0=fifo->ram)      */
+
+/* DVMA control register */
+#define DMA_CTRL_CSUSPEND       0x0010      /* DMA channel suspend              */
+#define DMA_CTRL_CCLEAR         0x0008      /* DMA channel clear and reset      */
+#define DMA_CTRL_FCLEAR         0x0004      /* DMA fifo clear                   */
+#define DMA_CTRL_CIRQ           0x0002      /* DMA irq clear                    */
+#define DMA_CTRL_DMASTART       0x0001      /* DMA transfer start               */
+
+/* DVMA status register */
+#define DMA_STAT_PFULL          0x00c0      /* Pipe full                        */
+#define DMA_STAT_PORUN          0x0080      /* Pipe overrun                     */
+#define DMA_STAT_PSTG1          0x0040      /* Pipe has stage 1 loaded          */
+#define DMA_STAT_PEMPTY         0x0000      /* Pipe is empty                    */
+#define DMA_STAT_CSUSP          0x0030      /* Channel suspended                */
+#define DMA_STAT_CTRAN          0x0020      /* Channel transfer in progress     */
+#define DMA_STAT_CACTIVE        0x0010      /* Channel active                   */
+#define DMA_STAT_CIDLE          0x0000      /* Channel idle                     */
+#define DMA_STAT_SPAR           0x0008      /* SBUS parity error                */
+#define DMA_STAT_SERR           0x0004      /* SBUS dma error                   */
+#define DMA_STAT_TCNT           0x0002      /* Terminal count expired           */
+#define DMA_STAT_IRQ            0x0001      /* DMA interrupt                    */
+
+/* DVMA FIFO status register */
+#define DMA_FSTAT_ORUN          0x0200      /* FIFO overrun                     */
+#define DMA_FSTAT_URUN          0x0100      /* FIFO underrun                    */
+#define DMA_FSTAT_CMASK         0x007f      /* FIFO count mask                  */
+
+/* SCSI processor config 1 register */
+#define CPU_CFG1_ASTIME         0xf000      /* Asynchronous setup time mask     */
+#define CPU_CFG1_STUNIT         0x0000      /* Selection time unit              */
+#define CPU_CFG1_STIMEO         0x0600      /* Selection timeout value          */
+#define CPU_CFG1_CFACT          0x00e0      /* Clock factor                     */
+#define CPU_CFG1_SID            0x000f      /* SCSI ID                          */
+
+/* SCSI processor config 2 register */
+#define CPU_CFG2_FDISAB         0x0040      /* SCSI filter disable              */
+#define CPU_CFG2_ERAPUPS        0x0020      /* Req/Ack pullup enable            */
+#define CPU_CFG2_EDPUPS         0x0010      /* Data active pullup enable        */
+#define CPU_CFG2_ECAUTO         0x0008      /* Autoload device config enable    */
+#define CPU_CFG2_ERESEL         0x0002      /* Enable reselections              */
+#define CPU_CFG2_ESEL           0x0001      /* Enable selections                */
+
+/* SCSI processor interrupt register */
+#define CPU_IRQ_PERR            0x8000      /* Parity error                     */
+#define CPU_IRQ_GERR            0x4000      /* Gross error                      */
+#define CPU_IRQ_FABORT          0x2000      /* Function abort                   */
+#define CPU_IRQ_CFAIL           0x1000      /* Condition failed                 */
+#define CPU_IRQ_FEMPTY          0x0800      /* FIFO empty                       */
+#define CPU_IRQ_BCZ             0x0400      /* Byte counter is zero             */
+#define CPU_IRQ_XZ              0x0200      /* Transfer counter is zero         */
+#define CPU_IRQ_IRQ             0x0080      /* SCSI processor interrupt pending */
+#define CPU_IRQ_CRUN            0x0040      /* Command is running               */
+#define CPU_IRQ_RCODE           0x000f      /* Return code for interrupt        */
+
+/* SCSI processor gross error register */
+#define CPU_GERR_ONZ            0x0040      /* Offset not zero                  */
+#define CPU_GERR_OUF            0x0020      /* Offset underflowed               */
+#define CPU_GERR_OOF            0x0010      /* Offset overflowed                */
+#define CPU_GERR_FUF            0x0008      /* FIFO underflowed                 */
+#define CPU_GERR_FOF            0x0004      /* FIFO overflowed                  */
+#define CPU_GERR_WERR           0x0002      /* Error on write                   */
+#define CPU_GERR_ILL            0x0001      /* Instruction was illegal          */
+
+/* SCSI processor exception register */
+#define CPU_EXC_UZERO           0x8000      /* User exception zero              */
+#define CPU_EXC_UONE            0x4000      /* User exception one               */
+#define CPU_EXC_BFREE           0x0200      /* Bus free                         */
+#define CPU_EXC_TATN            0x0100      /* ATN in target mode               */
+#define CPU_EXC_RESEL           0x0080      /* Reselect exception               */
+#define CPU_EXC_SEL             0x0040      /* Selection exception              */
+#define CPU_EXC_ARB             0x0020      /* Arbitration exception            */
+#define CPU_EXC_GERR            0x0010      /* Gross error exception            */
+#define CPU_EXC_RESET           0x0008      /* Bus reset exception              */
+
+/* SCSI processor override register */
+#define CPU_ORIDE_ETRIG         0x8000      /* External trigger enable          */
+#define CPU_ORIDE_STEP          0x4000      /* Single step mode enable          */
+#define CPU_ORIDE_BKPT          0x2000      /* Breakpoint reg enable            */
+#define CPU_ORIDE_PWRITE        0x1000      /* SCSI pin write enable            */
+#define CPU_ORIDE_OFORCE        0x0800      /* Force outputs on                 */
+#define CPU_ORIDE_LBACK         0x0400      /* SCSI loopback enable             */
+#define CPU_ORIDE_PTEST         0x0200      /* Parity test enable               */
+#define CPU_ORIDE_TENAB         0x0100      /* SCSI pins tristate enable        */
+#define CPU_ORIDE_TPINS         0x0080      /* SCSI pins enable                 */
+#define CPU_ORIDE_FRESET        0x0008      /* FIFO reset                       */
+#define CPU_ORIDE_CTERM         0x0004      /* Command terminate                */
+#define CPU_ORIDE_RREG          0x0002      /* Reset SCSI processor regs        */
+#define CPU_ORIDE_RMOD          0x0001      /* Reset SCSI processor module      */
+
+/* SCSI processor commands */
+#define CPU_CMD_BRESET          0x300b      /* Reset SCSI bus                   */
+
+/* SCSI processor user exception register */
+#define CPU_UEXC_ONE            0x0002      /* User exception one               */
+#define CPU_UEXC_ZERO           0x0001      /* User exception zero              */
+
+/* SCSI processor SCSI id register */
+#define CPU_SID_RSEID           0x0f00      /* Who is sel/resel'ing us          */
+#define CPU_SID_SID             0x000f      /* Selection ID                     */
+
+/* SCSI processor device config 1 */
+#define CPU_DCFG1_SHOLD         0x7000      /* Sync data hold                   */
+#define CPU_DCFG1_SSETUP        0x0f00      /* Sync data setup                  */
+#define CPU_DCFG1_SOFF          0x000f      /* Sync data offset                 */
+
+/* SCSI processor device config 2 */
+#define CPU_DCFG2_FMASK         0xf000      /* Device flags                     */
+#define CPU_DCFG2_EWIDE         0x0400      /* WIDE enable                      */
+#define CPU_DCFG2_EPAR          0x0200      /* Parity enable                    */
+#define CPU_DCFG2_EBLK          0x0100      /* Block mode transfer enable       */
+#define CPU_DCFG2_AMASK         0x0007      /* Assertion period mask            */
+
+/* SCSI processor phase pointer register */
+#define CPU_PPTR_STAT           0x1000      /* Status buf offset                */
+#define CPU_PPTR_MSGIN          0x0700      /* Msg-in buf offset                */
+#define CPU_PPTR_COM            0x00f0      /* Cmd buf offset                   */
+#define CPU_PPTR_MSGOUT         0x0007      /* Msg-out buf offset               */
+
+/* SCSI processor fifo status register */
+#define CPU_FSTAT_TFULL         0x8000      /* Top residue full                 */
+#define CPU_FSTAT_ARES          0x4000      /* Odd residue for wide transfer    */
+#define CPU_FSTAT_CMSK          0x001c      /* FIFO count mask                  */
+#define CPU_FSTAT_BRES          0x0001      /* Bottom residue full              */
+
+/* SCSI processor pin control register */
+#define CPU_PCTRL_PVALID        0x8000      /* Phase bits are valid             */
+#define CPU_PCTRL_PHI           0x0400      /* Parity bit high                  */
+#define CPU_PCTRL_PLO           0x0200      /* Parity bit low                   */
+#define CPU_PCTRL_REQ           0x0100      /* REQ bus signal                   */
+#define CPU_PCTRL_ACK           0x0080      /* ACK bus signal                   */
+#define CPU_PCTRL_RST           0x0040      /* RST bus signal                   */
+#define CPU_PCTRL_BSY           0x0020      /* BSY bus signal                   */
+#define CPU_PCTRL_SEL           0x0010      /* SEL bus signal                   */
+#define CPU_PCTRL_ATN           0x0008      /* ATN bus signal                   */
+#define CPU_PCTRL_MSG           0x0004      /* MSG bus signal                   */
+#define CPU_PCTRL_CD            0x0002      /* CD bus signal                    */
+#define CPU_PCTRL_IO            0x0001      /* IO bus signal                    */
+
+/* SCSI processor differential pins register */
+#define CPU_PDIFF_SENSE         0x0200      /* Differential sense               */
+#define CPU_PDIFF_MODE          0x0100      /* Differential mode                */
+#define CPU_PDIFF_OENAB         0x0080      /* Outputs enable                   */
+#define CPU_PDIFF_PMASK         0x007c      /* Differential control pins        */
+#define CPU_PDIFF_TGT           0x0002      /* Target mode enable               */
+#define CPU_PDIFF_INIT          0x0001      /* Initiator mode enable            */
+
+/* RISC processor status register */
+#define RISC_PSR_FTRUE          0x8000      /* Force true                       */
+#define RISC_PSR_LCD            0x4000      /* Loop counter shows done status   */
+#define RISC_PSR_RIRQ           0x2000      /* RISC irq status                  */
+#define RISC_PSR_TOFLOW         0x1000      /* Timer overflow (rollover)        */
+#define RISC_PSR_AOFLOW         0x0800      /* Arithmetic overflow              */
+#define RISC_PSR_AMSB           0x0400      /* Arithmetic big endian            */
+#define RISC_PSR_ACARRY         0x0200      /* Arithmetic carry                 */
+#define RISC_PSR_AZERO          0x0100      /* Arithmetic zero                  */
+#define RISC_PSR_ULTRA          0x0020      /* Ultra mode                       */
+#define RISC_PSR_DIRQ           0x0010      /* DVMA interrupt                   */
+#define RISC_PSR_SIRQ           0x0008      /* SCSI processor interrupt         */
+#define RISC_PSR_HIRQ           0x0004      /* Host interrupt                   */
+#define RISC_PSR_IPEND          0x0002      /* Interrupt pending                */
+#define RISC_PSR_FFALSE         0x0001      /* Force false                      */
+
+/* RISC processor memory timing register */
+#define RISC_MTREG_P1DFLT       0x1200      /* Default read/write timing, pg1   */
+#define RISC_MTREG_P0DFLT       0x0012      /* Default read/write timing, pg0   */
+#define RISC_MTREG_P1ULTRA      0x2300      /* Ultra-mode rw timing, pg1        */
+#define RISC_MTREG_P0ULTRA      0x0023      /* Ultra-mode rw timing, pg0        */
+
+/* Host command/ctrl register */
+#define HCCTRL_NOP              0x0000      /* CMD: No operation                */
+#define HCCTRL_RESET            0x1000      /* CMD: Reset RISC cpu              */
+#define HCCTRL_PAUSE            0x2000      /* CMD: Pause RISC cpu              */
+#define HCCTRL_REL              0x3000      /* CMD: Release paused RISC cpu     */
+#define HCCTRL_STEP             0x4000      /* CMD: Single step RISC cpu        */
+#define HCCTRL_SHIRQ            0x5000      /* CMD: Set host irq                */
+#define HCCTRL_CHIRQ            0x6000      /* CMD: Clear host irq              */
+#define HCCTRL_CRIRQ            0x7000      /* CMD: Clear RISC cpu irq          */
+#define HCCTRL_BKPT             0x8000      /* CMD: Breakpoint enables change   */
+#define HCCTRL_TMODE            0xf000      /* CMD: Enable test mode            */
+#define HCCTRL_HIRQ             0x0080      /* Host IRQ pending                 */
+#define HCCTRL_RRIP             0x0040      /* RISC cpu reset in happening now  */
+#define HCCTRL_RPAUSED          0x0020      /* RISC cpu is paused now           */
+#define HCCTRL_EBENAB           0x0010      /* External breakpoint enable       */
+#define HCCTRL_B1ENAB           0x0008      /* Breakpoint 1 enable              */
+#define HCCTRL_B0ENAB           0x0004      /* Breakpoint 0 enable              */
+
+#define QLOGICPTI {							   \
+	/* next */		NULL,					   \
+	/* usage_count */	NULL,					   \
+	/* proc dir */		NULL,					   \
+	/* procfs info */	NULL,					   \
+	/* name */		NULL,					   \
+	/* detect */		qlogicpti_detect,			   \
+	/* release */		qlogicpti_release,			   \
+	/* info */		qlogicpti_info,				   \
+	/* command */		NULL,					   \
+	/* queuecommand */	qlogicpti_queuecommand,			   \
+	/* abort */		qlogicpti_abort,			   \
+	/* reset */		qlogicpti_reset,			   \
+	/* slave_attach */	NULL,					   \
+	/* bios_param */	NULL,			   		   \
+	/* can_queue */		QLOGICISP_REQ_QUEUE_LEN,		   \
+	/* this_id */		7,					   \
+	/* sg_tablesize */	QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN), \
+	/* cmd_per_lun */	1,					   \
+	/* present */		0,					   \
+	/* unchecked_isa_dma */	0,					   \
+	/* use_clustering */	DISABLE_CLUSTERING			   \
+}
+
+/* For our interrupt engine. */
+#define for_each_qlogicpti(qp) \
+        for((qp) = qptichain; (qp); (qp) = (qp)->next)
+
+#endif /* !(_QLOGICPTI_H) */
diff -u --recursive --new-file v2.1.15/linux/drivers/scsi/qlogicpti_asm.c linux/drivers/scsi/qlogicpti_asm.c
--- v2.1.15/linux/drivers/scsi/qlogicpti_asm.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/scsi/qlogicpti_asm.c	Fri Dec 13 11:37:38 1996
@@ -0,0 +1,1132 @@
+/* Version 1.24 Initiator Firmware (Aug 8, 1996) */
+
+unsigned short risc_code_addr01 = 0x1000;
+
+unsigned short risc_code01[] = {
+	0x0078, 0x1030, 0x0000, 0x231f, 0x0000, 0x12ff, 0x2043, 0x4f50,
+	0x5952, 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932,
+	0x2c31, 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749,
+	0x4320, 0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049,
+	0x5350, 0x3130, 0x3030, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520,
+	0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, 0x312e, 0x3234, 0x2020,
+	0x20b9, 0x1212, 0x20c1, 0x0008, 0x2071, 0x0010, 0x70c3, 0x0004,
+	0x20c9, 0x3eff, 0x2089, 0x10c5, 0x70c7, 0x4953, 0x70cb, 0x5020,
+	0x70cf, 0x2020, 0x70d3, 0x0001, 0x3f00, 0x70d6, 0x2031, 0x0030,
+	0x2079, 0x3400, 0x7863, 0x0000, 0x2fa0, 0x2009, 0x032b, 0x2011,
+	0x0000, 0x20a9, 0x0040, 0x42a4, 0x8109, 0x00c0, 0x1051, 0x789b,
+	0x0101, 0x780b, 0x0002, 0x780f, 0x0002, 0x784f, 0x0bb8, 0x2069,
+	0x3440, 0x00a8, 0x1067, 0x681b, 0x003c, 0x0078, 0x1069, 0x681b,
+	0x0028, 0x6807, 0x0007, 0x680b, 0x00fa, 0x680f, 0x0008, 0x6813,
+	0x0005, 0x681f, 0x0000, 0x6823, 0x0006, 0x6817, 0x0008, 0x6827,
+	0x0000, 0x2069, 0x3500, 0x2011, 0x0020, 0x2009, 0x0010, 0x680b,
+	0x0c19, 0x680f, 0x0019, 0x6803, 0xdd00, 0x6807, 0x001a, 0x6a1a,
+	0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004, 0x8109, 0x00c0, 0x107f,
+	0x2069, 0x3580, 0x20a9, 0x0080, 0x6837, 0x0000, 0x680b, 0x0040,
+	0x6817, 0x0100, 0x681f, 0x0064, 0xade8, 0x0010, 0x0070, 0x10a2,
+	0x0078, 0x1094, 0x1078, 0x1a17, 0x1078, 0x2e4c, 0x1078, 0x1670,
+	0x1078, 0x32c0, 0x3200, 0xa085, 0x000d, 0x2090, 0x70c3, 0x0000,
+	0x0090, 0x10b9, 0x70c0, 0xa086, 0x0002, 0x00c0, 0x10b9, 0x1078,
+	0x11b8, 0x1078, 0x10e9, 0x1078, 0x17f8, 0x1078, 0x1989, 0x1078,
+	0x3187, 0x1078, 0x1766, 0x0078, 0x10b9, 0x10cd, 0x10cf, 0x1b6c,
+	0x1b6c, 0x2ea6, 0x2ea6, 0x1b6c, 0x1b6c, 0x0078, 0x10cd, 0x0078,
+	0x10cf, 0x0078, 0x10d1, 0x0078, 0x10d3, 0x7008, 0x800c, 0x00c8,
+	0x10e4, 0x7007, 0x0002, 0xa08c, 0x000c, 0x00c0, 0x10e5, 0x8004,
+	0x8004, 0x00c8, 0x10e4, 0x087a, 0x097a, 0x70c3, 0x4002, 0x0078,
+	0x11bb, 0x0068, 0x1135, 0x2061, 0x0000, 0x6018, 0xa084, 0x0001,
+	0x00c0, 0x1135, 0x7814, 0xa005, 0x00c0, 0x10fa, 0x0010, 0x1136,
+	0x0078, 0x1135, 0x2009, 0x3468, 0x2104, 0xa005, 0x00c0, 0x1135,
+	0x7814, 0xa086, 0x0001, 0x00c0, 0x1107, 0x1078, 0x1529, 0x7817,
+	0x0000, 0x2009, 0x346f, 0x2104, 0xa065, 0x0040, 0x1123, 0x2009,
+	0x346a, 0x211c, 0x8108, 0x2114, 0x8108, 0x2104, 0xa210, 0xa399,
+	0x0000, 0x2009, 0x001c, 0x6083, 0x0103, 0x1078, 0x1600, 0x00c0,
+	0x112f, 0x1078, 0x1667, 0x2009, 0x346f, 0x200b, 0x0000, 0x2009,
+	0x3469, 0x2104, 0x200b, 0x0000, 0xa005, 0x0040, 0x1133, 0x2001,
+	0x4005, 0x0078, 0x11ba, 0x0078, 0x11b8, 0x007c, 0x70c3, 0x0000,
+	0x70c7, 0x0000, 0x70cb, 0x0000, 0x70cf, 0x0000, 0x70c0, 0xa0bc,
+	0xffc0, 0x00c0, 0x1186, 0x2038, 0x0079, 0x1146, 0x11b8, 0x1203,
+	0x11d1, 0x1203, 0x1254, 0x1254, 0x11c8, 0x157f, 0x125f, 0x11c4,
+	0x11d5, 0x11d7, 0x11d9, 0x11db, 0x1584, 0x11c4, 0x1265, 0x1281,
+	0x1537, 0x1579, 0x11dd, 0x1468, 0x148a, 0x14a2, 0x14c5, 0x1421,
+	0x142f, 0x1443, 0x1457, 0x12ed, 0x11c4, 0x129d, 0x12a4, 0x12a9,
+	0x12ae, 0x12b4, 0x12b9, 0x12be, 0x12c3, 0x12c8, 0x12cc, 0x12e1,
+	0x11c4, 0x11c4, 0x11c4, 0x11c4, 0x11c4, 0x12f9, 0x1302, 0x1311,
+	0x1337, 0x1341, 0x1348, 0x136e, 0x137d, 0x138c, 0x139e, 0x1406,
+	0x11c4, 0x11c4, 0x11c4, 0x11c4, 0x11c4, 0x1416, 0xa0bc, 0xffa0,
+	0x00c0, 0x11c4, 0x2038, 0xa084, 0x001f, 0x0079, 0x118f, 0x11c4,
+	0x11c4, 0x11c4, 0x11c4, 0x11c4, 0x11c4, 0x11c4, 0x11c4, 0x11c4,
+	0x11c4, 0x11c4, 0x11c4, 0x11c4, 0x11c4, 0x11c4, 0x11c4, 0x11c4,
+	0x11c4, 0x11c4, 0x11c4, 0x11c4, 0x11c4, 0x11c4, 0x11c4, 0x11c4,
+	0x11c4, 0x15dc, 0x15e6, 0x15ea, 0x15f8, 0x11c4, 0x11c4, 0x72ca,
+	0x71c6, 0x2001, 0x4006, 0x0078, 0x11ba, 0x73ce, 0x72ca, 0x71c6,
+	0x2001, 0x4000, 0x70c2, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091,
+	0x5000, 0x2091, 0x4080, 0x007c, 0x70c3, 0x4001, 0x0078, 0x11bb,
+	0x2099, 0x0041, 0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0078,
+	0x11b8, 0x70c4, 0x70c3, 0x0004, 0x007a, 0x0078, 0x11b8, 0x0078,
+	0x11b8, 0x0078, 0x11b8, 0x0078, 0x11b8, 0x2091, 0x8000, 0x70c3,
+	0x0000, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3,
+	0x0001, 0x3f00, 0x70d6, 0x2079, 0x0000, 0x781b, 0x0001, 0x2031,
+	0x0030, 0x2059, 0x1000, 0x2029, 0x0457, 0x2051, 0x0470, 0x2061,
+	0x0472, 0x20b9, 0xffff, 0x20c1, 0x0000, 0x2091, 0x5000, 0x2091,
+	0x4080, 0x0078, 0x0455, 0x71d0, 0x72c8, 0x73cc, 0x70c4, 0x20a0,
+	0x2098, 0x2031, 0x0030, 0x81ff, 0x0040, 0x11b8, 0x7007, 0x0004,
+	0x731a, 0x721e, 0x2051, 0x0012, 0x2049, 0x1232, 0x2041, 0x11b8,
+	0x7003, 0x0002, 0xa786, 0x0001, 0x00c0, 0x1224, 0x2049, 0x1240,
+	0x2041, 0x124c, 0x7003, 0x0003, 0x7017, 0x0000, 0x810b, 0x7112,
+	0x00c8, 0x122c, 0x7017, 0x0001, 0x7007, 0x0001, 0xa786, 0x0001,
+	0x0040, 0x1240, 0x700c, 0xa084, 0x007f, 0x8004, 0x2009, 0x0020,
+	0xa102, 0x0942, 0x094a, 0x20a8, 0x26a0, 0x53a6, 0x0078, 0x10d5,
+	0x700c, 0xa084, 0x007f, 0x0040, 0x1240, 0x80ac, 0x0048, 0x1240,
+	0x2698, 0x53a5, 0x0078, 0x10d5, 0x700c, 0xa084, 0x007f, 0x80ac,
+	0x2698, 0x53a5, 0x0078, 0x11b8, 0x71c4, 0x70c8, 0x2114, 0xa79e,
+	0x0004, 0x00c0, 0x125c, 0x200a, 0x72ca, 0x0078, 0x11b7, 0x70c7,
+	0x0001, 0x70cb, 0x0018, 0x0078, 0x11b8, 0x70c4, 0x72c8, 0x73cc,
+	0x74d0, 0x70c6, 0x72ca, 0x73ce, 0x74d2, 0xa005, 0x0040, 0x127b,
+	0x8001, 0x7872, 0x7a7a, 0x7b7e, 0x7c76, 0x7898, 0xa084, 0xfffc,
+	0x789a, 0x0078, 0x127f, 0x7898, 0xa085, 0x0001, 0x789a, 0x0078,
+	0x11b8, 0x70c4, 0x72c8, 0x73cc, 0x74d4, 0x70c6, 0x72ca, 0x73ce,
+	0x74d6, 0xa005, 0x0040, 0x1297, 0x8001, 0x7886, 0x7a8e, 0x7b92,
+	0x7c8a, 0x7898, 0xa084, 0xfcff, 0x789a, 0x0078, 0x129b, 0x7898,
+	0xa085, 0x0100, 0x789a, 0x0078, 0x11b8, 0x2009, 0x3459, 0x210c,
+	0x2011, 0x042c, 0x0078, 0x11b6, 0x2009, 0x3441, 0x210c, 0x0078,
+	0x11b7, 0x2009, 0x3442, 0x210c, 0x0078, 0x11b7, 0x2061, 0x3440,
+	0x610c, 0x6210, 0x0078, 0x11b6, 0x2009, 0x3445, 0x210c, 0x0078,
+	0x11b7, 0x2009, 0x3446, 0x210c, 0x0078, 0x11b7, 0x2009, 0x3447,
+	0x210c, 0x0078, 0x11b7, 0x2009, 0x3448, 0x210c, 0x0078, 0x11b7,
+	0x7908, 0x7a0c, 0x0078, 0x11b6, 0x71c4, 0x8107, 0xa084, 0x000f,
+	0x8003, 0x8003, 0x8003, 0xa0e8, 0x3500, 0x6a00, 0x6804, 0xa084,
+	0x0008, 0x0040, 0x12de, 0x6b08, 0x0078, 0x12df, 0x6b0c, 0x0078,
+	0x11b5, 0x77c4, 0x1078, 0x1681, 0x2091, 0x8000, 0x6b1c, 0x6a14,
+	0x2091, 0x8001, 0x2708, 0x0078, 0x11b5, 0x77c4, 0x1078, 0x1681,
+	0x2091, 0x8000, 0x6908, 0x6a18, 0x6b10, 0x2091, 0x8001, 0x0078,
+	0x11b5, 0x71c4, 0xa182, 0x0010, 0x00c8, 0x11b0, 0x1078, 0x1a9b,
+	0x0078, 0x11b5, 0x71c4, 0xa182, 0x0010, 0x00c8, 0x11b0, 0x2011,
+	0x3441, 0x2204, 0x007e, 0x2112, 0x1078, 0x1a54, 0x017f, 0x0078,
+	0x11b7, 0x71c4, 0x2011, 0x132f, 0x20a9, 0x0008, 0x2204, 0xa106,
+	0x0040, 0x1321, 0x8210, 0x0070, 0x131f, 0x0078, 0x1316, 0x0078,
+	0x11b0, 0xa292, 0x132f, 0x027e, 0x2011, 0x3442, 0x2204, 0x2112,
+	0x017f, 0x007e, 0x1078, 0x1a60, 0x017f, 0x0078, 0x11b7, 0x03e8,
+	0x00fa, 0x01f4, 0x02ee, 0x0064, 0x0019, 0x0032, 0x004b, 0x2061,
+	0x3440, 0x610c, 0x6210, 0x70c4, 0x600e, 0x70c8, 0x6012, 0x0078,
+	0x11b6, 0x2061, 0x3440, 0x6114, 0x70c4, 0x6016, 0x0078, 0x11b7,
+	0x71c4, 0x2011, 0x0004, 0x2019, 0x1212, 0xa186, 0x0028, 0x0040,
+	0x1361, 0x2011, 0x0005, 0x2019, 0x1212, 0xa186, 0x0032, 0x0040,
+	0x1361, 0x2011, 0x0006, 0x2019, 0x2323, 0xa186, 0x003c, 0x00c0,
+	0x11b0, 0x2061, 0x3440, 0x6018, 0x007e, 0x611a, 0x23b8, 0x1078,
+	0x1a71, 0x1078, 0x32c0, 0x017f, 0x0078, 0x11b7, 0x71c4, 0xa184,
+	0xffcf, 0x00c0, 0x11b0, 0x2011, 0x3447, 0x2204, 0x2112, 0x007e,
+	0x1078, 0x1a93, 0x017f, 0x0078, 0x11b7, 0x71c4, 0xa182, 0x0010,
+	0x00c8, 0x11b0, 0x2011, 0x3448, 0x2204, 0x007e, 0x2112, 0x1078,
+	0x1a82, 0x017f, 0x0078, 0x11b7, 0x71c4, 0x72c8, 0xa184, 0xfffd,
+	0x00c0, 0x11af, 0xa284, 0xfffd, 0x00c0, 0x11af, 0x2100, 0x7908,
+	0x780a, 0x2200, 0x7a0c, 0x780e, 0x0078, 0x11b6, 0x71c4, 0x8107,
+	0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e8, 0x3500, 0x2019,
+	0x0000, 0x72c8, 0x6800, 0x007e, 0xa226, 0x0040, 0x13cd, 0x6a02,
+	0xa484, 0x2000, 0x0040, 0x13b6, 0xa39d, 0x0010, 0xa484, 0x1000,
+	0x0040, 0x13bc, 0xa39d, 0x0008, 0xa484, 0x4000, 0x0040, 0x13cd,
+	0x810f, 0xa284, 0x4000, 0x0040, 0x13c9, 0x1078, 0x1ab5, 0x0078,
+	0x13cd, 0x1078, 0x1aa7, 0x0078, 0x13cd, 0x72cc, 0x82ff, 0x0040,
+	0x13ff, 0x6808, 0xa206, 0x0040, 0x13ff, 0xa2a4, 0x00ff, 0x2061,
+	0x3440, 0x6118, 0xa186, 0x0028, 0x0040, 0x13e6, 0xa186, 0x0032,
+	0x0040, 0x13ec, 0xa186, 0x003c, 0x0040, 0x13f2, 0xa482, 0x0064,
+	0x0048, 0x13fc, 0x0078, 0x13f6, 0xa482, 0x0050, 0x0048, 0x13fc,
+	0x0078, 0x13f6, 0xa482, 0x0043, 0x0048, 0x13fc, 0x71c4, 0x71c6,
+	0x027f, 0x72ca, 0x0078, 0x11b1, 0x6a0a, 0xa39d, 0x000a, 0x6804,
+	0xa305, 0x6806, 0x027f, 0x6b0c, 0x0078, 0x11b5, 0x77c4, 0x1078,
+	0x1681, 0x2091, 0x8000, 0x6a14, 0x6b1c, 0x2091, 0x8001, 0x70c8,
+	0x6816, 0x70cc, 0x681e, 0x2708, 0x0078, 0x11b5, 0x71c4, 0x72c8,
+	0x73cc, 0xa182, 0x0010, 0x00c8, 0x11b0, 0x1078, 0x1ac3, 0x0078,
+	0x11b5, 0x77c4, 0x1078, 0x1681, 0x2091, 0x8000, 0x6a08, 0xa295,
+	0x0002, 0x6a0a, 0x2091, 0x8001, 0x2708, 0x0078, 0x11b6, 0x77c4,
+	0x1078, 0x1681, 0x2091, 0x8000, 0x6a08, 0xa294, 0xfff9, 0x6a0a,
+	0x6804, 0xa005, 0x0040, 0x143e, 0x1078, 0x19f8, 0x2091, 0x8001,
+	0x2708, 0x0078, 0x11b6, 0x77c4, 0x1078, 0x1681, 0x2091, 0x8000,
+	0x6a08, 0xa295, 0x0004, 0x6a0a, 0x6804, 0xa005, 0x0040, 0x1452,
+	0x1078, 0x19f8, 0x2091, 0x8001, 0x2708, 0x0078, 0x11b6, 0x77c4,
+	0x2041, 0x0001, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000,
+	0x1078, 0x168e, 0x2091, 0x8001, 0x2708, 0x6a08, 0x0078, 0x11b6,
+	0x77c4, 0x72c8, 0x73cc, 0x77c6, 0x72ca, 0x73ce, 0x1078, 0x1707,
+	0x00c0, 0x1486, 0x6818, 0xa005, 0x0040, 0x1480, 0x2708, 0x1078,
+	0x1ad3, 0x00c0, 0x1480, 0x7817, 0xffff, 0x2091, 0x8001, 0x007c,
+	0x2091, 0x8001, 0x2001, 0x4005, 0x0078, 0x11ba, 0x2091, 0x8001,
+	0x0078, 0x11b8, 0x77c4, 0x77c6, 0x2061, 0x3440, 0x60a3, 0x0003,
+	0x67b6, 0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091,
+	0x8000, 0x1078, 0x168e, 0x2091, 0x8001, 0x7817, 0xffff, 0x1078,
+	0x19f8, 0x007c, 0x77c8, 0x77ca, 0x77c4, 0x77c6, 0xa7bc, 0xff00,
+	0x2061, 0x3440, 0x60a3, 0x0002, 0x67b6, 0x7817, 0xffff, 0x1078,
+	0x19f8, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0010, 0x2091,
+	0x8000, 0x1078, 0x168e, 0x70c8, 0x6836, 0x8738, 0xa784, 0x0007,
+	0x00c0, 0x14b9, 0x2091, 0x8001, 0x007c, 0x7898, 0xa084, 0x0003,
+	0x00c0, 0x14e9, 0x2039, 0x0000, 0x2041, 0x0021, 0x2049, 0x0004,
+	0x2051, 0x0008, 0x1078, 0x1681, 0x2091, 0x8000, 0x6808, 0xa80d,
+	0x690a, 0x2091, 0x8001, 0x8738, 0xa784, 0x0007, 0x00c0, 0x14d2,
+	0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0,
+	0x14d2, 0x2091, 0x8000, 0x2069, 0x0100, 0x6830, 0xa084, 0x0040,
+	0x0040, 0x1512, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, 0xa084,
+	0x0004, 0x0040, 0x14ff, 0x0070, 0x14ff, 0x0078, 0x14f6, 0x684b,
+	0x0009, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0001, 0x0040, 0x150c,
+	0x0070, 0x150c, 0x0078, 0x1503, 0x20a9, 0x00fa, 0x0070, 0x1512,
+	0x0078, 0x150e, 0x2079, 0x3400, 0x7817, 0x0001, 0x2061, 0x3440,
+	0x60a3, 0x0001, 0x60c3, 0x000f, 0x7898, 0xa085, 0x0002, 0x789a,
+	0x6808, 0xa084, 0xfffd, 0x680a, 0x681b, 0x0046, 0x2091, 0x8001,
+	0x007c, 0x7898, 0xa084, 0xfffd, 0x789a, 0xa084, 0x0001, 0x00c0,
+	0x1533, 0x1078, 0x1749, 0x71c4, 0x71c6, 0x794a, 0x007c, 0x74c4,
+	0x73c8, 0x72cc, 0x74c6, 0x73ca, 0x72ce, 0x2079, 0x3400, 0x2009,
+	0x0040, 0x1078, 0x165e, 0x0040, 0x1575, 0x1078, 0x162e, 0x0040,
+	0x154d, 0x1078, 0x1667, 0x0078, 0x1575, 0x6010, 0x7817, 0xffff,
+	0x2009, 0x3468, 0x200b, 0x0005, 0x8108, 0x200b, 0x0000, 0x8108,
+	0x230a, 0x8108, 0x220a, 0x8108, 0x240a, 0x8108, 0x200a, 0x8108,
+	0x200b, 0x0000, 0x8108, 0x2c0a, 0xa02e, 0x2530, 0x0e7e, 0x1078,
+	0x2e25, 0x0e7f, 0x6592, 0x65a2, 0x6696, 0x66a6, 0x60ab, 0x0000,
+	0x60af, 0x0000, 0x1078, 0x19f8, 0x007c, 0x70c3, 0x4005, 0x0078,
+	0x11bb, 0x71c4, 0x70c7, 0x0000, 0x7906, 0x0078, 0x11b8, 0x71c4,
+	0x71c6, 0x2168, 0x0078, 0x1586, 0x2069, 0x1000, 0x690c, 0xa016,
+	0x2d04, 0xa210, 0x8d68, 0x8109, 0x00c0, 0x1588, 0xa285, 0x0000,
+	0x00c0, 0x1596, 0x70c3, 0x4000, 0x0078, 0x1598, 0x70c3, 0x4003,
+	0x70ca, 0x0078, 0x11bb, 0x71c4, 0x72c8, 0x73cc, 0x2100, 0xa184,
+	0xfffc, 0x00c0, 0x11c4, 0x2100, 0x0079, 0x15a6, 0x15bd, 0x15d2,
+	0x15d4, 0x15d6, 0x70c3, 0x4003, 0x71ce, 0x72d2, 0x73d6, 0x0078,
+	0x15b9, 0x70c3, 0x4000, 0x70cf, 0x0000, 0x70d3, 0x0000, 0x70d7,
+	0x0000, 0x77c6, 0x71ca, 0x0078, 0x11b8, 0x2031, 0x15d8, 0x2624,
+	0x8630, 0x2412, 0x2204, 0xa446, 0x00c0, 0x15aa, 0xa484, 0xffff,
+	0x00c0, 0x15bf, 0x2031, 0x15d8, 0x8210, 0x8319, 0xa384, 0xffff,
+	0x00c0, 0x15bf, 0x0078, 0x15b1, 0x0078, 0x15b1, 0x0078, 0x15b1,
+	0x5555, 0xaaaa, 0xffff, 0x0000, 0x7960, 0x71c6, 0x71c4, 0xa182,
+	0x0003, 0x00c8, 0x11b0, 0x7962, 0x0078, 0x11b8, 0x7960, 0x71c6,
+	0x0078, 0x11b8, 0x7954, 0x71c6, 0x71c4, 0x7956, 0x7958, 0x71ca,
+	0x71c8, 0x795a, 0x795c, 0x71ce, 0x71cc, 0x795e, 0x0078, 0x11b8,
+	0x7954, 0x71c6, 0x7958, 0x71ca, 0x795c, 0x71ce, 0x0078, 0x11b8,
+	0x700c, 0xa084, 0x007f, 0x0040, 0x160c, 0x7007, 0x0004, 0x7004,
+	0xa084, 0x0004, 0x00c0, 0x1607, 0x7017, 0x0000, 0x7112, 0x721a,
+	0x731e, 0x8108, 0x810c, 0x81a9, 0x8c98, 0x20a1, 0x0030, 0x6080,
+	0x20a2, 0x53a6, 0x780c, 0xa085, 0x0000, 0x7002, 0x7007, 0x0001,
+	0x7108, 0x8104, 0x00c8, 0x1620, 0x7007, 0x0002, 0xa184, 0x000c,
+	0x710c, 0xa184, 0x0300, 0x7003, 0x0000, 0x007c, 0x700c, 0xa084,
+	0x007f, 0x0040, 0x163a, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004,
+	0x00c0, 0x1635, 0x7017, 0x0000, 0x7112, 0x721a, 0x731e, 0x2099,
+	0x0030, 0x8108, 0x81ac, 0x780c, 0xa085, 0x0001, 0x7002, 0x7007,
+	0x0001, 0x7008, 0x800c, 0x00c8, 0x1649, 0x7007, 0x0002, 0xa08c,
+	0x000c, 0x00c0, 0x165b, 0x710c, 0xa184, 0x0300, 0x00c0, 0x165b,
+	0x2ca0, 0x53a5, 0xa006, 0x7003, 0x0000, 0x007c, 0x7850, 0xa065,
+	0x0040, 0x1666, 0x2c04, 0x7852, 0x2063, 0x0000, 0x007c, 0x0f7e,
+	0x2079, 0x3400, 0x7850, 0x2062, 0x2c00, 0x7852, 0x0f7f, 0x007c,
+	0x2011, 0x3f00, 0x7a52, 0x2019, 0x042c, 0x8319, 0x0040, 0x167e,
+	0xa280, 0x002e, 0x2012, 0x2010, 0x0078, 0x1675, 0x2013, 0x0000,
+	0x007c, 0xa784, 0x0f00, 0x800c, 0xa784, 0x0007, 0x8003, 0x8003,
+	0x8003, 0x8003, 0xa105, 0xa0e8, 0x3580, 0x007c, 0x1078, 0x1681,
+	0x2900, 0x682a, 0x2a00, 0x682e, 0x6808, 0xa084, 0xffef, 0xa80d,
+	0x690a, 0x2009, 0x344f, 0x210c, 0x6804, 0xa005, 0x0040, 0x16ab,
+	0xa116, 0x00c0, 0x16ab, 0x2060, 0x6000, 0x6806, 0x017e, 0x200b,
+	0x0000, 0x0078, 0x16ae, 0x2009, 0x0000, 0x017e, 0x6804, 0xa065,
+	0x0040, 0x16bd, 0x6000, 0x6806, 0x1078, 0x16ce, 0x1078, 0x17ac,
+	0x6810, 0x8001, 0x6812, 0x00c0, 0x16ae, 0x017f, 0x6902, 0x6906,
+	0x007c, 0xa065, 0x0040, 0x16cd, 0x6098, 0x609b, 0x0000, 0x2008,
+	0x1078, 0x1667, 0x2100, 0x0078, 0x16c1, 0x007c, 0x6003, 0x0103,
+	0x20a9, 0x001c, 0xac80, 0x0004, 0x20a0, 0x2001, 0x0000, 0x40a4,
+	0x6828, 0x6016, 0x682c, 0x601e, 0x007c, 0x0e7e, 0x2071, 0x3440,
+	0x7040, 0xa08c, 0x0080, 0x00c0, 0x16eb, 0xa088, 0x3480, 0x2d0a,
+	0x8000, 0x7042, 0xa006, 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0x3440,
+	0x2009, 0x3480, 0x7240, 0x8221, 0x8211, 0x0048, 0x1705, 0x2104,
+	0x8108, 0xad06, 0x00c0, 0x16f4, 0x8119, 0x211e, 0x8108, 0x8318,
+	0x8211, 0x00c8, 0x16fd, 0x7442, 0xa006, 0x0e7f, 0x007c, 0x1078,
+	0x1681, 0x2091, 0x8000, 0x6804, 0x781e, 0xa065, 0x0040, 0x1748,
+	0x0078, 0x1718, 0x2c00, 0x781e, 0x6000, 0xa065, 0x0040, 0x1748,
+	0x600c, 0xa306, 0x00c0, 0x1712, 0x6008, 0xa206, 0x00c0, 0x1712,
+	0x2c28, 0x6804, 0xac06, 0x00c0, 0x172f, 0x6000, 0x2060, 0x6806,
+	0xa005, 0x00c0, 0x172f, 0x6803, 0x0000, 0x0078, 0x1739, 0x6400,
+	0x781c, 0x2060, 0x6402, 0xa486, 0x0000, 0x00c0, 0x1739, 0x2c00,
+	0x6802, 0x2560, 0x1078, 0x16ce, 0x6017, 0x0005, 0x601f, 0x0020,
+	0x1078, 0x17ac, 0x6810, 0x8001, 0x6812, 0x2001, 0xffff, 0xa005,
+	0x007c, 0x2039, 0x0000, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051,
+	0x0008, 0x2091, 0x8000, 0x1078, 0x168e, 0x8738, 0xa784, 0x0007,
+	0x00c0, 0x1753, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784,
+	0x0f00, 0x00c0, 0x1753, 0x2091, 0x8001, 0x007c, 0x2061, 0x0000,
+	0x6018, 0xa084, 0x0001, 0x00c0, 0x1773, 0x78ac, 0x78af, 0x0000,
+	0xa005, 0x00c0, 0x1774, 0x007c, 0xa08c, 0xfff0, 0x0040, 0x177a,
+	0x1078, 0x1b4e, 0x0079, 0x177c, 0x178c, 0x178e, 0x1794, 0x1798,
+	0x178c, 0x179c, 0x178c, 0x178c, 0x178c, 0x178c, 0x17a2, 0x17a6,
+	0x178c, 0x178c, 0x178c, 0x178c, 0x1078, 0x1b4e, 0x1078, 0x1749,
+	0x2001, 0x8001, 0x0078, 0x11ba, 0x2001, 0x8003, 0x0078, 0x11ba,
+	0x2001, 0x8004, 0x0078, 0x11ba, 0x1078, 0x1749, 0x2001, 0x8006,
+	0x0078, 0x11ba, 0x2001, 0x800c, 0x0078, 0x11ba, 0x1078, 0x1749,
+	0x2001, 0x800d, 0x0078, 0x11ba, 0x2c04, 0x6082, 0x2c08, 0x2063,
+	0x0000, 0x7864, 0x8000, 0x7866, 0x7868, 0xa005, 0x796a, 0x0040,
+	0x17bc, 0x2c02, 0x0078, 0x17bd, 0x796e, 0x007c, 0x0c7e, 0x2061,
+	0x3400, 0x6883, 0x0103, 0x2d08, 0x206b, 0x0000, 0x6064, 0x8000,
+	0x6066, 0x6068, 0xa005, 0x616a, 0x0040, 0x17d1, 0x2d02, 0x0078,
+	0x17d2, 0x616e, 0x0c7f, 0x007c, 0x1078, 0x17e5, 0x0040, 0x17e4,
+	0x0c7e, 0x6098, 0xa065, 0x0040, 0x17df, 0x1078, 0x16c1, 0x0c7f,
+	0x609b, 0x0000, 0x1078, 0x1667, 0x007c, 0x786c, 0xa065, 0x0040,
+	0x17f7, 0x2091, 0x8000, 0x7864, 0x8001, 0x7866, 0x2c04, 0x786e,
+	0xa005, 0x00c0, 0x17f5, 0x786a, 0x8000, 0x2091, 0x8001, 0x007c,
+	0x7898, 0xa005, 0x00c0, 0x1846, 0x7974, 0x70d0, 0x0005, 0x0005,
+	0x72d0, 0xa206, 0x00c0, 0x17fd, 0x2200, 0xa106, 0x00c0, 0x1814,
+	0x7804, 0xa005, 0x0040, 0x1846, 0x7807, 0x0000, 0x0068, 0x1846,
+	0x2091, 0x4080, 0x0078, 0x1846, 0x1078, 0x165e, 0x0040, 0x1846,
+	0x7a7c, 0x7b78, 0x8107, 0x8004, 0x8004, 0xa210, 0xa399, 0x0000,
+	0x2009, 0x0040, 0x1078, 0x162e, 0x0040, 0x183d, 0x1078, 0x1667,
+	0x7880, 0x8000, 0x7882, 0xa086, 0x0002, 0x00c0, 0x1846, 0x2091,
+	0x8000, 0x78af, 0x0002, 0x7883, 0x0000, 0x7898, 0xa085, 0x0003,
+	0x789a, 0x2091, 0x8001, 0x0078, 0x1846, 0x7883, 0x0000, 0x1078,
+	0x1973, 0x6000, 0xa084, 0x0007, 0x0079, 0x1847, 0x007c, 0x184f,
+	0x185e, 0x187e, 0x184f, 0x1890, 0x184f, 0x184f, 0x184f, 0x2039,
+	0x0400, 0x78a8, 0xa705, 0x78aa, 0x6004, 0xa705, 0x6006, 0x1078,
+	0x18ce, 0x6018, 0x78a6, 0x1078, 0x195b, 0x007c, 0x78a8, 0xa084,
+	0x0100, 0x0040, 0x1865, 0x0078, 0x184f, 0x78ab, 0x0000, 0x6000,
+	0x8007, 0xa084, 0x00ff, 0x789e, 0x8001, 0x609b, 0x0000, 0x0040,
+	0x187b, 0x1078, 0x18ce, 0x0040, 0x187b, 0x78a8, 0xa085, 0x0100,
+	0x78aa, 0x0078, 0x187d, 0x1078, 0x18f2, 0x007c, 0x78a8, 0xa08c,
+	0x0e00, 0x00c0, 0x1887, 0xa084, 0x0100, 0x00c0, 0x1889, 0x0078,
+	0x184f, 0x1078, 0x18ce, 0x00c0, 0x188f, 0x1078, 0x18f2, 0x007c,
+	0x78a8, 0xa084, 0x0100, 0x0040, 0x1897, 0x0078, 0x184f, 0x78ab,
+	0x0000, 0x6710, 0x20a9, 0x0001, 0x6014, 0xa084, 0x00ff, 0xa005,
+	0x0040, 0x18b4, 0xa7bc, 0xff00, 0x20a9, 0x0008, 0xa08e, 0x0001,
+	0x0040, 0x18b4, 0x2039, 0x0000, 0x20a9, 0x0080, 0xa08e, 0x0002,
+	0x0040, 0x18b4, 0x0078, 0x18cb, 0x1078, 0x1681, 0x2d00, 0x2091,
+	0x8000, 0x682b, 0x0000, 0x682f, 0x0000, 0x6808, 0xa084, 0xffde,
+	0x680a, 0x2d00, 0xa080, 0x0010, 0x2068, 0x2091, 0x8001, 0x0070,
+	0x18cb, 0x0078, 0x18b7, 0x1078, 0x1667, 0x007c, 0x78a0, 0xa06d,
+	0x00c0, 0x18d9, 0x2c00, 0x78a2, 0x78a6, 0x609b, 0x0000, 0x0078,
+	0x18e5, 0x2c00, 0x689a, 0x609b, 0x0000, 0x78a2, 0x2d00, 0x6002,
+	0x78a4, 0xad06, 0x00c0, 0x18e5, 0x6002, 0x789c, 0x8001, 0x789e,
+	0x00c0, 0x18f1, 0x78a8, 0xa084, 0x0000, 0x78aa, 0x78a4, 0x2060,
+	0xa006, 0x007c, 0xa02e, 0x2530, 0x6118, 0xa184, 0x0060, 0x619e,
+	0x0040, 0x18fe, 0x0e7e, 0x1078, 0x2e25, 0x0e7f, 0x6592, 0x65a2,
+	0x6696, 0x66a6, 0x60ab, 0x0000, 0x60af, 0x0000, 0x6710, 0x1078,
+	0x1681, 0x2091, 0x8000, 0x6808, 0xa084, 0x0001, 0x0040, 0x1920,
+	0x2091, 0x8001, 0x1078, 0x16ce, 0x2091, 0x8000, 0x1078, 0x17ac,
+	0x2091, 0x8001, 0x78a3, 0x0000, 0x78a7, 0x0000, 0x0078, 0x195a,
+	0x6020, 0xa096, 0x0001, 0x00c0, 0x1927, 0x8000, 0x6022, 0x6a10,
+	0x6814, 0x2091, 0x8001, 0xa202, 0x0048, 0x1936, 0x0040, 0x1936,
+	0x2039, 0x0200, 0x1078, 0x195b, 0x0078, 0x195a, 0x2c08, 0x2091,
+	0x8000, 0x6800, 0xa065, 0x0040, 0x193e, 0x6102, 0x6902, 0x00c0,
+	0x1942, 0x6906, 0x2160, 0x6003, 0x0000, 0x6810, 0x8000, 0x6812,
+	0x2091, 0x8001, 0x6808, 0xa08c, 0x0040, 0x0040, 0x1954, 0xa086,
+	0x0040, 0x680a, 0x1078, 0x16dd, 0x1078, 0x19f8, 0x78a7, 0x0000,
+	0x78a3, 0x0000, 0x007c, 0x6004, 0xa705, 0x6006, 0x2091, 0x8000,
+	0x1078, 0x17ac, 0x2091, 0x8001, 0x78a4, 0xa065, 0x0040, 0x196e,
+	0x6098, 0x78a6, 0x609b, 0x0000, 0x0078, 0x195e, 0x78a3, 0x0000,
+	0x78a7, 0x0000, 0x007c, 0x7970, 0x7874, 0x8000, 0xa10a, 0x00c8,
+	0x197a, 0xa006, 0x7876, 0x70d2, 0x7804, 0xa005, 0x0040, 0x1988,
+	0x8001, 0x7806, 0x00c0, 0x1988, 0x0068, 0x1988, 0x2091, 0x4080,
+	0x007c, 0x0068, 0x19a1, 0x2029, 0x0000, 0x786c, 0xa065, 0x0040,
+	0x199c, 0x1078, 0x19a2, 0x0040, 0x199c, 0x1078, 0x19b8, 0x00c0,
+	0x199c, 0x8528, 0x0078, 0x198d, 0x85ff, 0x0040, 0x19a1, 0x2091,
+	0x4080, 0x007c, 0x7b84, 0x7988, 0x72d4, 0x0005, 0x0005, 0x70d4,
+	0xa206, 0x00c0, 0x19a4, 0x2200, 0xa102, 0x00c0, 0x19b2, 0x2300,
+	0xa005, 0x007c, 0x0048, 0x19b6, 0xa302, 0x007c, 0x8002, 0x007c,
+	0x1078, 0x19ea, 0x2009, 0x001c, 0x6024, 0xa005, 0x0040, 0x19c2,
+	0x2009, 0x0040, 0x1078, 0x1600, 0x0040, 0x19db, 0x7894, 0x8000,
+	0x7896, 0xa086, 0x0002, 0x00c0, 0x19e9, 0x2091, 0x8000, 0x78af,
+	0x0003, 0x7897, 0x0000, 0x7898, 0xa085, 0x0300, 0x789a, 0x2091,
+	0x8001, 0x0078, 0x19e9, 0x7897, 0x0000, 0x1078, 0x17d4, 0x7984,
+	0x7888, 0x8000, 0xa10a, 0x00c8, 0x19e6, 0xa006, 0x788a, 0x70d6,
+	0xa006, 0x007c, 0x8107, 0x8004, 0x8004, 0x7a90, 0x7b8c, 0xa210,
+	0xa399, 0x0000, 0x007c, 0x2009, 0x3468, 0x2091, 0x8000, 0x200a,
+	0x0f7e, 0x2079, 0x0100, 0x2009, 0x3440, 0x2091, 0x8000, 0x2104,
+	0xa086, 0x0000, 0x00c0, 0x1a13, 0x2009, 0x3412, 0x2104, 0xa005,
+	0x00c0, 0x1a13, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x1a13, 0x0018,
+	0x1a13, 0x781b, 0x0044, 0x2091, 0x8001, 0x0f7f, 0x007c, 0x127e,
+	0x2091, 0x2300, 0x2071, 0x3440, 0x2079, 0x0100, 0x2019, 0x2d1f,
+	0x20a1, 0x012b, 0x2304, 0xa005, 0x0040, 0x1a2f, 0x789a, 0x8318,
+	0x23ac, 0x8318, 0x2398, 0x53a6, 0x3318, 0x0078, 0x1a22, 0x789b,
+	0x0020, 0x20a9, 0x0010, 0x78af, 0x0000, 0x78af, 0x0220, 0x0070,
+	0x1a3b, 0x0078, 0x1a33, 0x7003, 0x0000, 0x1078, 0x1b3a, 0x7004,
+	0xa084, 0x000f, 0xa085, 0x6280, 0x7806, 0x780f, 0x9200, 0x7843,
+	0x00d8, 0x7853, 0x0080, 0x780b, 0x0008, 0x7047, 0x347f, 0x7043,
+	0x0000, 0x127f, 0x2000, 0x007c, 0xa18c, 0x000f, 0x2011, 0x0101,
+	0x2204, 0xa084, 0xfff0, 0xa105, 0x2012, 0x1078, 0x1b3a, 0x007c,
+	0x2011, 0x0101, 0x20a9, 0x0009, 0x810b, 0x0070, 0x1a69, 0x0078,
+	0x1a64, 0xa18c, 0x0e00, 0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012,
+	0x007c, 0x2009, 0x0101, 0x20a9, 0x0005, 0x8213, 0x0070, 0x1a7a,
+	0x0078, 0x1a75, 0xa294, 0x00e0, 0x2104, 0xa084, 0xff1f, 0xa205,
+	0x200a, 0x007c, 0x2011, 0x0101, 0x20a9, 0x000c, 0x810b, 0x0070,
+	0x1a8b, 0x0078, 0x1a86, 0xa18c, 0xf000, 0x2204, 0xa084, 0x0fff,
+	0xa105, 0x2012, 0x007c, 0x2011, 0x0102, 0x2204, 0xa084, 0xffcf,
+	0xa105, 0x2012, 0x007c, 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e,
+	0x2061, 0x0100, 0x609a, 0x62ac, 0x63ac, 0x0c7f, 0x007c, 0x8103,
+	0x8003, 0xa080, 0x0022, 0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4,
+	0xa084, 0xffdf, 0x60ae, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080,
+	0x0022, 0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, 0xa085, 0x0020,
+	0x60ae, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e,
+	0x2061, 0x0100, 0x609a, 0x60a4, 0x62ae, 0x2010, 0x60a4, 0x63ae,
+	0x2018, 0x0c7f, 0x007c, 0x0c7e, 0x0e7e, 0x6818, 0xa005, 0x0040,
+	0x1b16, 0x2061, 0x3e80, 0x1078, 0x1b1c, 0x0040, 0x1b04, 0x20a9,
+	0x0000, 0x2061, 0x3d80, 0x0c7e, 0x1078, 0x1b1c, 0x0040, 0x1af0,
+	0x0c7f, 0x8c60, 0x0070, 0x1aee, 0x0078, 0x1ae3, 0x0078, 0x1b16,
+	0x007f, 0xa082, 0x3d80, 0x2071, 0x3440, 0x70ba, 0x601c, 0xa085,
+	0x0800, 0x601e, 0x2091, 0x8001, 0x71b6, 0x2001, 0x0004, 0x70a2,
+	0x1078, 0x19f3, 0x0078, 0x1b12, 0x2071, 0x3440, 0x601c, 0xa085,
+	0x0800, 0x601e, 0x2091, 0x8001, 0x71b6, 0x2001, 0x0006, 0x70a2,
+	0x1078, 0x19f3, 0x2001, 0x0000, 0x0078, 0x1b18, 0x2001, 0x0001,
+	0xa005, 0x0e7f, 0x0c7f, 0x007c, 0x2091, 0x8000, 0x2c04, 0xa005,
+	0x0040, 0x1b35, 0x2060, 0x600c, 0xa306, 0x00c0, 0x1b32, 0x6008,
+	0xa206, 0x00c0, 0x1b32, 0x6010, 0xa106, 0x00c0, 0x1b32, 0xa006,
+	0x0078, 0x1b39, 0x6000, 0x0078, 0x1b1f, 0xa085, 0x0001, 0x2091,
+	0x8001, 0x007c, 0x2011, 0x3441, 0x220c, 0xa18c, 0x000f, 0x2011,
+	0x013b, 0x2204, 0xa084, 0x0100, 0x0040, 0x1b4d, 0x2019, 0x0112,
+	0x201b, 0x1000, 0x2021, 0xff80, 0x2122, 0x007c, 0x0068, 0x1b4e,
+	0x007e, 0x2071, 0x0000, 0x7018, 0xa084, 0x0001, 0x00c0, 0x1b53,
+	0x007f, 0x2e08, 0x2071, 0x0010, 0x70ca, 0x007f, 0x70c6, 0x70c3,
+	0x8002, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x007f,
+	0x2070, 0x007f, 0x0078, 0x1b6a, 0x107e, 0x007e, 0x127e, 0x2091,
+	0x2300, 0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0xa594, 0x003f, 0xa484,
+	0x4000, 0x0040, 0x1b81, 0xa784, 0x007c, 0x00c0, 0x2ceb, 0x1078,
+	0x1b4e, 0xa49c, 0x000f, 0xa382, 0x0004, 0x0050, 0x1b89, 0x1078,
+	0x1b4e, 0x8507, 0xa084, 0x000f, 0x0079, 0x1b8e, 0x1f8e, 0x202f,
+	0x2055, 0x226e, 0x24d4, 0x251c, 0x2555, 0x25d0, 0x262a, 0x26ae,
+	0x1bb4, 0x1b9e, 0x1df7, 0x1ec1, 0x24b3, 0x1b9e, 0x1078, 0x1b4e,
+	0x0018, 0x1b71, 0x127f, 0x2091, 0x8001, 0x007f, 0x107f, 0x007c,
+	0x7003, 0x0000, 0x703f, 0x0000, 0x7030, 0xa005, 0x0040, 0x1bb2,
+	0x7033, 0x0000, 0x0018, 0x1b71, 0x705c, 0xa005, 0x00c0, 0x1c5b,
+	0x70a0, 0xa084, 0x0007, 0x0079, 0x1bbd, 0x1c7a, 0x1bc5, 0x1bd3,
+	0x1bf4, 0x1c1a, 0x1c46, 0x1c44, 0x1bc5, 0x7808, 0xa084, 0xfffd,
+	0x780a, 0x2009, 0x0046, 0x1078, 0x2393, 0x00c0, 0x1bd1, 0x7003,
+	0x0004, 0x0078, 0x1ba0, 0x1078, 0x2cad, 0x00c0, 0x1bf2, 0x70b4,
+	0x8007, 0x789b, 0x007e, 0x78aa, 0x789b, 0x0010, 0x78ab, 0x000c,
+	0x789b, 0x0060, 0x78ab, 0x0001, 0x785b, 0x0004, 0x2009, 0x00f7,
+	0x1078, 0x2391, 0x00c0, 0x1bf2, 0x7003, 0x0004, 0x70c3, 0x000f,
+	0x7033, 0x3470, 0x0078, 0x1ba0, 0x1078, 0x2cad, 0x00c0, 0x1c18,
+	0x71b4, 0x8107, 0x789b, 0x007e, 0x78aa, 0x789b, 0x0010, 0xa18c,
+	0x0007, 0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060,
+	0x78ab, 0x0002, 0x785b, 0x0004, 0x2009, 0x00f7, 0x1078, 0x2391,
+	0x00c0, 0x1c18, 0x7003, 0x0004, 0x70c3, 0x000f, 0x7033, 0x3470,
+	0x0078, 0x1ba0, 0x1078, 0x2cad, 0x00c0, 0x1c42, 0x71b4, 0x8107,
+	0x789b, 0x007e, 0x78aa, 0x789b, 0x0010, 0xa18c, 0x0007, 0xa18d,
+	0x00c0, 0x79aa, 0x78ab, 0x0020, 0x71b8, 0x79aa, 0x78ab, 0x000d,
+	0x789b, 0x0060, 0x78ab, 0x0004, 0x785b, 0x0004, 0x2009, 0x00f7,
+	0x1078, 0x2391, 0x00c0, 0x1c42, 0x7003, 0x0004, 0x70c3, 0x000f,
+	0x7033, 0x3470, 0x0078, 0x1ba0, 0x0078, 0x1bf4, 0x1078, 0x2cad,
+	0x00c0, 0x1ba0, 0x70bc, 0x2068, 0x789b, 0x0010, 0x6810, 0xa084,
+	0x0007, 0xa085, 0x0080, 0x78aa, 0x6e18, 0x2041, 0x0001, 0x2001,
+	0x0004, 0x0078, 0x1d82, 0x1078, 0x2cad, 0x00c0, 0x1ba0, 0x789b,
+	0x0010, 0x705c, 0x2068, 0x6f10, 0x1078, 0x2bfc, 0x6008, 0xa085,
+	0x0010, 0x600a, 0x6810, 0xa084, 0x0007, 0xa085, 0x0080, 0x78aa,
+	0x2031, 0x0020, 0x2041, 0x0001, 0x1078, 0x2d0c, 0x2001, 0x0003,
+	0x0078, 0x1d6d, 0x0018, 0x1b71, 0x7440, 0xa485, 0x0000, 0x0040,
+	0x1c94, 0xa080, 0x3480, 0x2030, 0x7144, 0x8108, 0xa12a, 0x0048,
+	0x1c8b, 0x2009, 0x3480, 0x2164, 0x6504, 0x85ff, 0x00c0, 0x1ca1,
+	0x8421, 0x00c0, 0x1c85, 0x7146, 0x7003, 0x0000, 0x703f, 0x0000,
+	0x0078, 0x1ba0, 0x7640, 0xa6b0, 0x3480, 0x7144, 0x2600, 0x0078,
+	0x1c90, 0x7146, 0x2568, 0x2558, 0x753e, 0x2c50, 0x6034, 0xa085,
+	0x0000, 0x00c0, 0x1c9e, 0x6708, 0x7736, 0xa784, 0x013f, 0x0040,
+	0x1cd3, 0xa784, 0x0021, 0x00c0, 0x1c9e, 0xa784, 0x0002, 0x0040,
+	0x1cc0, 0xa784, 0x0004, 0x0040, 0x1c9e, 0xa7bc, 0xfffb, 0x670a,
+	0xa784, 0x0008, 0x00c0, 0x1c9e, 0xa784, 0x0010, 0x00c0, 0x1c9e,
+	0xa784, 0x0100, 0x0040, 0x1cd3, 0x6018, 0xa005, 0x00c0, 0x1c9e,
+	0xa7bc, 0xfeff, 0x670a, 0x681f, 0x0000, 0x6e18, 0xa684, 0x000e,
+	0x6118, 0x0040, 0x1ce3, 0x601c, 0xa102, 0x0048, 0x1ce6, 0x0040,
+	0x1ce6, 0x0078, 0x1c9a, 0x81ff, 0x00c0, 0x1c9a, 0xa784, 0x0080,
+	0x00c0, 0x1cec, 0x700c, 0x6022, 0xa7bc, 0xff7f, 0x670a, 0x6b10,
+	0x8307, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x3500,
+	0x2060, 0x2048, 0x704a, 0x6000, 0x704e, 0x6004, 0x7052, 0x2a60,
+	0x0018, 0x1b71, 0x789b, 0x0010, 0xa046, 0x1078, 0x2cad, 0x00c0,
+	0x1ba0, 0x6b10, 0xa39c, 0x0007, 0xa39d, 0x00c0, 0x704c, 0xa084,
+	0x8000, 0x0040, 0x1d17, 0xa684, 0x0001, 0x0040, 0x1d19, 0xa39c,
+	0xffbf, 0xa684, 0x0010, 0x0040, 0x1d1f, 0xa39d, 0x0020, 0x7baa,
+	0x8840, 0xa684, 0x000e, 0x00c0, 0x1d2a, 0xa7bd, 0x0010, 0x670a,
+	0x0078, 0x1d6b, 0x714c, 0xa18c, 0x0800, 0x0040, 0x2870, 0x2011,
+	0x0021, 0x8004, 0x8004, 0x0048, 0x1d41, 0x2011, 0x0022, 0x8004,
+	0x0048, 0x1d41, 0x2011, 0x0020, 0x8004, 0x0048, 0x1d41, 0x0040,
+	0x1d6b, 0x7aaa, 0x8840, 0x1078, 0x2cc6, 0x6a10, 0x610c, 0x8108,
+	0xa18c, 0x00ff, 0xa1e0, 0x3d80, 0x2c64, 0x8cff, 0x0040, 0x1d62,
+	0x6010, 0xa206, 0x00c0, 0x1d4c, 0x60b4, 0x8001, 0x60b6, 0x00c0,
+	0x1d47, 0x0c7e, 0x2a60, 0x6008, 0xa085, 0x0100, 0x600a, 0x0c7f,
+	0x0078, 0x1c7a, 0x1078, 0x2cad, 0x00c0, 0x1ba0, 0x2a60, 0x610e,
+	0x79aa, 0x8840, 0x712e, 0x2001, 0x0001, 0x007e, 0x7150, 0xa184,
+	0x0018, 0x0040, 0x1d81, 0xa184, 0x0010, 0x0040, 0x1d7b, 0x1078,
+	0x2a33, 0x00c0, 0x1d81, 0xa184, 0x0008, 0x0040, 0x1d81, 0x1078,
+	0x294d, 0x007f, 0x7002, 0xa68c, 0x0060, 0x88ff, 0x0040, 0x1d8a,
+	0xa18d, 0x0004, 0x795a, 0x69b2, 0x789b, 0x0060, 0x2800, 0x78aa,
+	0x789b, 0x0061, 0x6814, 0xa085, 0x8000, 0x6816, 0x78aa, 0x157e,
+	0x137e, 0x147e, 0x20a1, 0x012c, 0x789b, 0x0000, 0x8000, 0x80ac,
+	0xad80, 0x000a, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x6810,
+	0x8007, 0x789b, 0x007e, 0x78aa, 0x6d90, 0x7dd6, 0x7dde, 0x6e94,
+	0x7ed2, 0x7eda, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x1db9, 0x0098,
+	0x1dc1, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x2cc6, 0x0078,
+	0x1ba8, 0x7200, 0xa284, 0x0007, 0xa086, 0x0001, 0x00c0, 0x1dce,
+	0x781b, 0x0049, 0x1078, 0x2cc6, 0x0078, 0x1ddf, 0x6ab0, 0xa295,
+	0x2000, 0x7a5a, 0x781b, 0x0049, 0x1078, 0x2cc6, 0x7200, 0x2500,
+	0xa605, 0x0040, 0x1ddf, 0xa284, 0x0007, 0x1079, 0x1ded, 0xad80,
+	0x0008, 0x7032, 0xa284, 0x0007, 0xa086, 0x0001, 0x00c0, 0x1deb,
+	0x6018, 0x8000, 0x601a, 0x0078, 0x1ba0, 0x1df5, 0x2ffc, 0x2ffc,
+	0x2feb, 0x2ffc, 0x1df5, 0x1df5, 0x1df5, 0x1078, 0x1b4e, 0x7808,
+	0xa084, 0xfffd, 0x780a, 0x0f7e, 0x2079, 0x3400, 0x7898, 0x0f7f,
+	0xa084, 0x0001, 0x0040, 0x1e1d, 0x70a0, 0xa086, 0x0001, 0x00c0,
+	0x1e0c, 0x70a2, 0x0078, 0x1ea5, 0x70a0, 0xa086, 0x0005, 0x00c0,
+	0x1e1b, 0x70bc, 0x2068, 0x6817, 0x0004, 0x6813, 0x0000, 0x681c,
+	0xa085, 0x0008, 0x681e, 0x70a3, 0x0000, 0x157e, 0x2011, 0x0004,
+	0x71a0, 0xa186, 0x0001, 0x0040, 0x1e3f, 0xa186, 0x0007, 0x00c0,
+	0x1e2f, 0x2009, 0x342b, 0x200b, 0x0005, 0x0078, 0x1e3f, 0x2009,
+	0x3413, 0x2104, 0x2009, 0x3412, 0x200a, 0x2009, 0x342b, 0x200b,
+	0x0001, 0x70a3, 0x0000, 0x70a7, 0x0001, 0x0078, 0x1e41, 0x70a3,
+	0x0000, 0x1078, 0x2e0e, 0x20a9, 0x0010, 0x2039, 0x0000, 0x1078,
+	0x2b01, 0xa7b8, 0x0100, 0x0070, 0x1e4f, 0x0078, 0x1e47, 0x7000,
+	0x2020, 0x0079, 0x1e53, 0x1e81, 0x1e6a, 0x1e6a, 0x1e5d, 0x1e81,
+	0x1e81, 0x1e5b, 0x1e5b, 0x1078, 0x1b4e, 0x2021, 0x3457, 0x2404,
+	0xa005, 0x0040, 0x1e6a, 0xad06, 0x00c0, 0x1e6a, 0x6800, 0x2022,
+	0x0078, 0x1e7a, 0x681c, 0xa084, 0x0001, 0x00c0, 0x1e76, 0x6f10,
+	0x1078, 0x2bfc, 0x1078, 0x283d, 0x0078, 0x1e7a, 0x7054, 0x2060,
+	0x6800, 0x6002, 0x6a16, 0x681c, 0xa085, 0x0008, 0x681e, 0x1078,
+	0x17be, 0x2021, 0x3e80, 0x1078, 0x1eab, 0x2021, 0x3457, 0x1078,
+	0x1eab, 0x20a9, 0x0000, 0x2021, 0x3d80, 0x1078, 0x1eab, 0x8420,
+	0x0070, 0x1e94, 0x0078, 0x1e8d, 0x20a9, 0x0080, 0x2061, 0x3580,
+	0x6018, 0x6110, 0xa102, 0x6012, 0x601b, 0x0000, 0xace0, 0x0010,
+	0x0070, 0x1ea4, 0x0078, 0x1e98, 0x157f, 0x7003, 0x0000, 0x703f,
+	0x0000, 0x0078, 0x1ba0, 0x047e, 0x2404, 0xa005, 0x0040, 0x1ebd,
+	0x2068, 0x6800, 0x007e, 0x6a16, 0x681c, 0xa085, 0x0008, 0x681e,
+	0x1078, 0x17be, 0x007f, 0x0078, 0x1ead, 0x047f, 0x2023, 0x0000,
+	0x007c, 0xa282, 0x0003, 0x0050, 0x1ec7, 0x1078, 0x1b4e, 0x2300,
+	0x0079, 0x1eca, 0x1ecd, 0x1f40, 0x1f4e, 0xa282, 0x0002, 0x0040,
+	0x1ed3, 0x1078, 0x1b4e, 0x70a0, 0x70a3, 0x0000, 0x70c3, 0x0000,
+	0x0079, 0x1eda, 0x1ee2, 0x1ee2, 0x1ee4, 0x1f18, 0x287b, 0x1ee2,
+	0x1f18, 0x1ee2, 0x1078, 0x1b4e, 0x77b4, 0x1078, 0x2b01, 0x77b4,
+	0xa7bc, 0x0f00, 0x1078, 0x2bfc, 0x6018, 0xa005, 0x0040, 0x1f0f,
+	0x2021, 0x3e80, 0x2009, 0x0004, 0x2011, 0x0010, 0x1078, 0x1f69,
+	0x0040, 0x1f0f, 0x157e, 0x20a9, 0x0000, 0x2021, 0x3d80, 0x047e,
+	0x2009, 0x0004, 0x2011, 0x0010, 0x1078, 0x1f69, 0x047f, 0x0040,
+	0x1f0e, 0x8420, 0x0070, 0x1f0e, 0x0078, 0x1eff, 0x157f, 0x8738,
+	0xa784, 0x0007, 0x00c0, 0x1eea, 0x0078, 0x1ba8, 0x0078, 0x1ba8,
+	0x77b4, 0x1078, 0x2bfc, 0x6018, 0xa005, 0x0040, 0x1f3e, 0x2021,
+	0x3e80, 0x2009, 0x0005, 0x2011, 0x0020, 0x1078, 0x1f69, 0x0040,
+	0x1f3e, 0x157e, 0x20a9, 0x0000, 0x2021, 0x3d80, 0x047e, 0x2009,
+	0x0005, 0x2011, 0x0020, 0x1078, 0x1f69, 0x047f, 0x0040, 0x1f3d,
+	0x8420, 0x0070, 0x1f3d, 0x0078, 0x1f2e, 0x157f, 0x0078, 0x1ba8,
+	0x2200, 0x0079, 0x1f43, 0x1f46, 0x1f48, 0x1f48, 0x1078, 0x1b4e,
+	0x70a3, 0x0000, 0x70a7, 0x0001, 0x0078, 0x1ba0, 0x2200, 0x0079,
+	0x1f51, 0x1f56, 0x1f48, 0x1f54, 0x1078, 0x1b4e, 0x1078, 0x23a0,
+	0x7000, 0xa086, 0x0001, 0x00c0, 0x2813, 0x1078, 0x2853, 0x6008,
+	0xa084, 0xffef, 0x600a, 0x1078, 0x2806, 0x0040, 0x2813, 0x0078,
+	0x1c7a, 0x2404, 0xa005, 0x0040, 0x1f8a, 0x2068, 0x2d04, 0x007e,
+	0x6810, 0xa706, 0x0040, 0x1f78, 0x2d20, 0x007f, 0x0078, 0x1f6a,
+	0x007f, 0x2022, 0x6916, 0x681c, 0xa205, 0x681e, 0x1078, 0x17be,
+	0x6010, 0x8001, 0x6012, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078,
+	0x2853, 0x007c, 0xa085, 0x0001, 0x0078, 0x1f89, 0x2300, 0x0079,
+	0x1f91, 0x1f96, 0x1f94, 0x1fd5, 0x1078, 0x1b4e, 0x78e4, 0xa005,
+	0x00d0, 0x1fb9, 0x0018, 0x1fb9, 0x2008, 0xa084, 0x0030, 0x00c0,
+	0x1fa5, 0x781b, 0x0049, 0x0078, 0x1ba0, 0x78ec, 0xa084, 0x0003,
+	0x0040, 0x1fa1, 0x2100, 0xa084, 0x0007, 0x0079, 0x1faf, 0x1fc3,
+	0x1fc9, 0x1fbd, 0x1fb7, 0x2ca7, 0x2ca7, 0x1fb7, 0x1fcf, 0x1078,
+	0x1b4e, 0x2001, 0x0003, 0x0078, 0x2282, 0x1078, 0x2ae4, 0x781b,
+	0x0055, 0x0078, 0x1ba0, 0x1078, 0x2ae4, 0x781b, 0x00dc, 0x0078,
+	0x1ba0, 0x1078, 0x2ae4, 0x781b, 0x00e3, 0x0078, 0x1ba0, 0x1078,
+	0x2ae4, 0x781b, 0x009d, 0x0078, 0x1ba0, 0xa584, 0x000f, 0x00c0,
+	0x1ff4, 0x1078, 0x23a0, 0x7000, 0x0079, 0x1fde, 0x1fe6, 0x1fe8,
+	0x1fe6, 0x2813, 0x2813, 0x2813, 0x1fe6, 0x1fe6, 0x1078, 0x1b4e,
+	0x1078, 0x2853, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x2806,
+	0x0040, 0x2813, 0x0078, 0x1c7a, 0x78e4, 0xa005, 0x00d0, 0x1fb9,
+	0x0018, 0x1fb9, 0x2008, 0xa084, 0x0030, 0x00c0, 0x2003, 0x781b,
+	0x0049, 0x0078, 0x1ba0, 0x78ec, 0xa084, 0x0003, 0x0040, 0x1fff,
+	0x2100, 0xa184, 0x0007, 0x0079, 0x200d, 0x201d, 0x2023, 0x2017,
+	0x2015, 0x2ca7, 0x2ca7, 0x2015, 0x2c9f, 0x1078, 0x1b4e, 0x1078,
+	0x2aec, 0x781b, 0x0055, 0x0078, 0x1ba0, 0x1078, 0x2aec, 0x781b,
+	0x00dc, 0x0078, 0x1ba0, 0x1078, 0x2aec, 0x781b, 0x00e3, 0x0078,
+	0x1ba0, 0x1078, 0x2aec, 0x781b, 0x009d, 0x0078, 0x1ba0, 0x2300,
+	0x0079, 0x2032, 0x2037, 0x2035, 0x2039, 0x1078, 0x1b4e, 0x0078,
+	0x25d0, 0x6817, 0x0008, 0x78a3, 0x0000, 0x79e4, 0xa184, 0x0030,
+	0x0040, 0x25d0, 0x78ec, 0xa084, 0x0003, 0x0040, 0x25d0, 0xa184,
+	0x0007, 0x0079, 0x204b, 0x1fc3, 0x1fc9, 0x1fbd, 0x2c7f, 0x2ca7,
+	0x2ca7, 0x2053, 0x2c9f, 0x1078, 0x1b4e, 0xa282, 0x0005, 0x0050,
+	0x205b, 0x1078, 0x1b4e, 0x2300, 0x0079, 0x205e, 0x2061, 0x2256,
+	0x2262, 0x2200, 0x0079, 0x2064, 0x2069, 0x206b, 0x207e, 0x2069,
+	0x223b, 0x1078, 0x1b4e, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff,
+	0xa082, 0x0020, 0x0048, 0x2ac5, 0xa08a, 0x0004, 0x00c8, 0x2ac5,
+	0x0079, 0x207a, 0x2ac5, 0x2ac5, 0x2ac5, 0x2a73, 0x789b, 0x0018,
+	0x79a8, 0xa184, 0x0080, 0x0040, 0x2093, 0xa184, 0x0018, 0x0040,
+	0x208f, 0x0078, 0x2ac5, 0x7000, 0xa005, 0x00c0, 0x2089, 0x2011,
+	0x0003, 0x0078, 0x26bc, 0xa184, 0x00ff, 0xa08a, 0x0010, 0x00c8,
+	0x2ac5, 0x0079, 0x209b, 0x20ad, 0x20ab, 0x20c3, 0x20c5, 0x214a,
+	0x2ac5, 0x2ac5, 0x214c, 0x2ac5, 0x2ac5, 0x2237, 0x2237, 0x2ac5,
+	0x2ac5, 0x2ac5, 0x2239, 0x1078, 0x1b4e, 0xa684, 0x1000, 0x0040,
+	0x20ba, 0x2001, 0x0300, 0x8000, 0x8000, 0x783a, 0x781b, 0x009a,
+	0x0078, 0x1ba0, 0x6814, 0xa084, 0x8000, 0x0040, 0x20c1, 0x6817,
+	0x0003, 0x0078, 0x2c7f, 0x1078, 0x1b4e, 0x691c, 0x691e, 0xa684,
+	0x1800, 0x00c0, 0x20df, 0x681c, 0xa084, 0x0001, 0x00c0, 0x20e7,
+	0x6814, 0xa086, 0x0008, 0x00c0, 0x20d7, 0x6817, 0x0000, 0xa684,
+	0x0400, 0x0040, 0x2146, 0x781b, 0x0058, 0x0078, 0x1ba0, 0xa684,
+	0x1000, 0x0040, 0x20e7, 0x781b, 0x0058, 0x0078, 0x1ba0, 0xa684,
+	0x0060, 0x0040, 0x2142, 0xa684, 0x0800, 0x0040, 0x2142, 0xa684,
+	0x8000, 0x00c0, 0x20f5, 0x0078, 0x210f, 0xa6b4, 0x7fff, 0x7e5a,
+	0x6eb2, 0x789b, 0x0074, 0x7aac, 0x79ac, 0x78ac, 0x801b, 0x00c8,
+	0x2102, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x6b94,
+	0x2100, 0xa302, 0x68ae, 0x6b90, 0x2200, 0xa303, 0x68aa, 0xa684,
+	0x4000, 0x0040, 0x2117, 0xa6b4, 0xbfff, 0x7e5a, 0x6eb2, 0xa006,
+	0x1078, 0x30a0, 0x6aac, 0x69a8, 0x6c94, 0x6b90, 0x2200, 0xa105,
+	0x0040, 0x2126, 0x2200, 0xa422, 0x2100, 0xa31b, 0x7cd2, 0x7bd6,
+	0x2300, 0xa405, 0x00c0, 0x2134, 0xa6b5, 0x4000, 0x7e5a, 0x6eb2,
+	0x781b, 0x0067, 0x0078, 0x1ba0, 0x781b, 0x0067, 0x2200, 0xa115,
+	0x00c0, 0x213e, 0x1078, 0x2ffc, 0x0078, 0x1ba0, 0x1078, 0x3029,
+	0x0078, 0x1ba0, 0x781b, 0x006a, 0x0078, 0x1ba0, 0x781b, 0x0058,
+	0x0078, 0x1ba0, 0x1078, 0x1b4e, 0x0078, 0x21a9, 0x691c, 0xa184,
+	0x0100, 0x0040, 0x2164, 0xa18c, 0xfeff, 0x691e, 0x0c7e, 0x7048,
+	0x2060, 0x6000, 0xa084, 0xefff, 0x6002, 0x6004, 0xa084, 0xfff5,
+	0x6006, 0x0c7f, 0x0078, 0x2198, 0xa184, 0x0200, 0x0040, 0x2198,
+	0xa18c, 0xfdff, 0x691e, 0x0c7e, 0x7048, 0x2060, 0x6000, 0xa084,
+	0xdfff, 0x6002, 0x6004, 0xa084, 0xffef, 0x6006, 0x2008, 0x2c48,
+	0x0c7f, 0xa184, 0x0008, 0x0040, 0x2198, 0x1078, 0x2bf8, 0x1078,
+	0x294d, 0x88ff, 0x0040, 0x2198, 0x789b, 0x0060, 0x2800, 0x78aa,
+	0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2194,
+	0x781b, 0x0055, 0x0078, 0x1ba0, 0x781b, 0x0069, 0x0078, 0x1ba0,
+	0x7e58, 0xa684, 0x0400, 0x00c0, 0x21a1, 0x781b, 0x0058, 0x0078,
+	0x1ba0, 0x781b, 0x006a, 0x0078, 0x1ba0, 0x0078, 0x2acb, 0x0078,
+	0x2acb, 0x2019, 0x0000, 0x7990, 0xa18c, 0x0007, 0x0040, 0x21a7,
+	0x789b, 0x0010, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001, 0x00c0,
+	0x21cc, 0x2300, 0x7ca8, 0xa400, 0x2018, 0xa102, 0x0040, 0x21c4,
+	0x0048, 0x21c4, 0x0078, 0x21c6, 0x0078, 0x214e, 0x24a8, 0x7aa8,
+	0x00f0, 0x21c6, 0x0078, 0x21b2, 0xa284, 0x00f0, 0xa086, 0x0020,
+	0x00c0, 0x2228, 0x8318, 0x8318, 0x2300, 0xa102, 0x0040, 0x21dc,
+	0x0048, 0x21dc, 0x0078, 0x2225, 0xa286, 0x0023, 0x0040, 0x21a7,
+	0x6818, 0xa084, 0xfff1, 0x681a, 0x7e58, 0xa684, 0xfff1, 0xa085,
+	0x0010, 0x2030, 0x7e5a, 0x6008, 0xa085, 0x0010, 0x600a, 0x0c7e,
+	0x7048, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xa184, 0x0010,
+	0x0040, 0x2200, 0x1078, 0x2bf8, 0x1078, 0x2a33, 0x0078, 0x220f,
+	0x0c7e, 0x7048, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xa184,
+	0x0008, 0x0040, 0x2198, 0x1078, 0x2bf8, 0x1078, 0x294d, 0x88ff,
+	0x0040, 0x2198, 0x789b, 0x0060, 0x2800, 0x78aa, 0xa6b5, 0x0004,
+	0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2221, 0x781b, 0x0055, 0x0078,
+	0x1ba0, 0x781b, 0x0069, 0x0078, 0x1ba0, 0x7aa8, 0x0078, 0x21b2,
+	0x8318, 0x2300, 0xa102, 0x0040, 0x2231, 0x0048, 0x2231, 0x0078,
+	0x21b2, 0xa284, 0x0080, 0x00c0, 0x2ad1, 0x0078, 0x2acb, 0x0078,
+	0x2ad1, 0x0078, 0x2ac5, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff,
+	0xa08e, 0x0001, 0x0040, 0x2246, 0x1078, 0x1b4e, 0x7aa8, 0xa294,
+	0x00ff, 0x78a8, 0xa084, 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x2ac5,
+	0x0079, 0x2252, 0x2ac5, 0x28a0, 0x2ac5, 0x29ce, 0xa282, 0x0000,
+	0x00c0, 0x225c, 0x1078, 0x1b4e, 0x1078, 0x2ae4, 0x781b, 0x0069,
+	0x0078, 0x1ba0, 0xa282, 0x0003, 0x00c0, 0x2268, 0x1078, 0x1b4e,
+	0x1078, 0x2af4, 0x781b, 0x0069, 0x0078, 0x1ba0, 0xa282, 0x0004,
+	0x0050, 0x2274, 0x1078, 0x1b4e, 0x2300, 0x0079, 0x2277, 0x227a,
+	0x2351, 0x237b, 0xa286, 0x0003, 0x0040, 0x2280, 0x1078, 0x1b4e,
+	0x2001, 0x0000, 0x703a, 0x7000, 0xa084, 0x0007, 0x0079, 0x2288,
+	0x2290, 0x2292, 0x2292, 0x2471, 0x2499, 0x243b, 0x2290, 0x2290,
+	0x1078, 0x1b4e, 0xa684, 0x1000, 0x00c0, 0x229a, 0x1078, 0x2e0e,
+	0x0040, 0x232b, 0x7868, 0xa08c, 0x00ff, 0x0040, 0x22e2, 0xa186,
+	0x0008, 0x00c0, 0x22b1, 0x1078, 0x2853, 0x6008, 0xa084, 0xffef,
+	0x600a, 0x1078, 0x2806, 0x0040, 0x22e2, 0x1078, 0x2e0e, 0x0078,
+	0x22c9, 0xa186, 0x0028, 0x00c0, 0x22e2, 0x1078, 0x2e0e, 0x6008,
+	0xa084, 0xffef, 0x600a, 0x6018, 0xa005, 0x0040, 0x22c9, 0x8001,
+	0x601a, 0xa005, 0x0040, 0x22c9, 0x8001, 0xa005, 0x0040, 0x22c9,
+	0x601e, 0x681c, 0xa084, 0x0001, 0x0040, 0x1ba8, 0x681c, 0xa084,
+	0xfffe, 0x681e, 0x7054, 0x0c7e, 0x2060, 0x6800, 0x6002, 0x0c7f,
+	0x6004, 0x6802, 0xa005, 0x2d00, 0x00c0, 0x22df, 0x6002, 0x6006,
+	0x0078, 0x1ba8, 0x017e, 0x1078, 0x23a0, 0x017f, 0xa684, 0xdf00,
+	0x681a, 0x6827, 0x0000, 0x6f10, 0x81ff, 0x0040, 0x232b, 0xa186,
+	0x0002, 0x00c0, 0x2323, 0xa684, 0x0800, 0x00c0, 0x22ff, 0xa684,
+	0x0060, 0x0040, 0x22ff, 0x78d8, 0x7adc, 0x682e, 0x6a2a, 0x8717,
+	0xa294, 0x000f, 0x8213, 0x8213, 0x8213, 0xa290, 0x3500, 0xa290,
+	0x0000, 0x221c, 0xa384, 0x0100, 0x00c0, 0x2310, 0x0078, 0x2316,
+	0x8210, 0x2204, 0xa085, 0x0018, 0x2012, 0x8211, 0xa384, 0x0400,
+	0x0040, 0x2323, 0x689c, 0xa084, 0x0100, 0x00c0, 0x2323, 0x1078,
+	0x23fa, 0x0078, 0x1ba8, 0xa186, 0x0018, 0x0040, 0x232b, 0xa186,
+	0x0014, 0x0040, 0x1ba8, 0x6912, 0x6814, 0xa084, 0x8000, 0x0040,
+	0x2333, 0x7038, 0x6816, 0xa68c, 0xdf00, 0x691a, 0x1078, 0x2844,
+	0x1078, 0x2853, 0x00c0, 0x2340, 0x6008, 0xa084, 0xffef, 0x600a,
+	0x681c, 0xa084, 0x0001, 0x00c0, 0x2349, 0x1078, 0x283d, 0x0078,
+	0x234d, 0x7054, 0x2060, 0x6800, 0x6002, 0x1078, 0x17be, 0x0078,
+	0x1ba8, 0xa282, 0x0004, 0x0048, 0x2357, 0x1078, 0x1b4e, 0x2200,
+	0x0079, 0x235a, 0x235e, 0x2360, 0x2366, 0x2360, 0x1078, 0x1b4e,
+	0x1078, 0x2ae4, 0x781b, 0x0069, 0x0078, 0x1ba0, 0x7890, 0x8007,
+	0x8001, 0xa084, 0x0007, 0xa080, 0x0018, 0x789a, 0x79a8, 0xa18c,
+	0x00ff, 0xa186, 0x0003, 0x0040, 0x2377, 0x0078, 0x2ac5, 0x781b,
+	0x006a, 0x0078, 0x1ba0, 0x681c, 0xa085, 0x0004, 0x681e, 0x82ff,
+	0x00c0, 0x2386, 0x1078, 0x2ae4, 0x0078, 0x238d, 0x8211, 0x0040,
+	0x238b, 0x1078, 0x1b4e, 0x1078, 0x2af4, 0x781b, 0x0069, 0x0078,
+	0x1ba0, 0x1078, 0x2cc6, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x239d,
+	0x0018, 0x239d, 0x791a, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c,
+	0xa684, 0x0060, 0x00c0, 0x23aa, 0x682f, 0x0000, 0x682b, 0x0000,
+	0x0078, 0x23f9, 0xa684, 0x0800, 0x00c0, 0x23b1, 0x1078, 0x2e0e,
+	0x007c, 0xa684, 0x0020, 0x0040, 0x23d3, 0x78d0, 0x8003, 0x00c8,
+	0x23bf, 0xa006, 0x1078, 0x30a0, 0x78d4, 0x1078, 0x3103, 0xa684,
+	0x4000, 0x0040, 0x23c9, 0x682f, 0x0000, 0x682b, 0x0000, 0x0078,
+	0x23ae, 0x7038, 0xa005, 0x00c0, 0x23cd, 0x79d8, 0x7adc, 0x692e,
+	0x6a2a, 0x0078, 0x23ae, 0xa684, 0x4000, 0x0040, 0x23dd, 0x682f,
+	0x0000, 0x682b, 0x0000, 0x0078, 0x23ae, 0x7038, 0xa005, 0x00c0,
+	0x23e3, 0x703b, 0x0007, 0x79d8, 0x7adc, 0x78d0, 0x80f3, 0x00c8,
+	0x23ea, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x692e,
+	0x6a2a, 0x2100, 0xa205, 0x00c0, 0x23f7, 0x0078, 0x23ae, 0x1078,
+	0x30a0, 0x007c, 0xa384, 0x0200, 0x0040, 0x2402, 0x6008, 0xa085,
+	0x0002, 0x600a, 0x6817, 0x0006, 0x6a28, 0x692c, 0x6a3a, 0x693e,
+	0x682b, 0x0300, 0x682f, 0x0000, 0x6833, 0x2000, 0x6893, 0x0000,
+	0x6897, 0x0020, 0x7000, 0x0079, 0x2415, 0x241d, 0x241f, 0x2428,
+	0x241d, 0x241d, 0x241d, 0x241d, 0x241d, 0x1078, 0x1b4e, 0x681c,
+	0xa084, 0x0001, 0x00c0, 0x2428, 0x1078, 0x283d, 0x0078, 0x242e,
+	0x7054, 0x2c50, 0x2060, 0x6800, 0x6002, 0x2a60, 0x2021, 0x3457,
+	0x2404, 0xa005, 0x0040, 0x2437, 0x2020, 0x0078, 0x2430, 0x2d22,
+	0x206b, 0x0000, 0x007c, 0x77b4, 0x1078, 0x2b01, 0xa7bc, 0x0f00,
+	0x1078, 0x2bfc, 0x6018, 0xa005, 0x0040, 0x246a, 0x0d7e, 0x2001,
+	0x3e90, 0x2068, 0x0d7f, 0x2021, 0x3e80, 0x2009, 0x0004, 0x2011,
+	0x0010, 0x1078, 0x1f69, 0x0040, 0x246a, 0x157e, 0x20a9, 0x0000,
+	0x2021, 0x3d80, 0x047e, 0x2009, 0x0004, 0x2011, 0x0010, 0x1078,
+	0x1f69, 0x047f, 0x0040, 0x2469, 0x8420, 0x0070, 0x2469, 0x0078,
+	0x245a, 0x157f, 0x8738, 0xa784, 0x0007, 0x00c0, 0x2440, 0x0078,
+	0x1ba8, 0x1078, 0x2844, 0x1078, 0x2853, 0x6827, 0x0000, 0x789b,
+	0x000e, 0x6f10, 0x6813, 0x0002, 0x1078, 0x30d4, 0xa684, 0x0800,
+	0x0040, 0x2486, 0x6918, 0xa18d, 0x2000, 0x691a, 0x6814, 0xa084,
+	0x8000, 0x0040, 0x248d, 0x6817, 0x0000, 0x2021, 0x3457, 0x6800,
+	0x2022, 0x6a38, 0x693c, 0x6a2a, 0x692e, 0x1078, 0x17be, 0x0078,
+	0x1ba8, 0x1078, 0x23a0, 0x6827, 0x0000, 0x789b, 0x000e, 0x6f10,
+	0x1078, 0x2ccb, 0xa08c, 0x00ff, 0x6912, 0x6814, 0xa084, 0x8000,
+	0x0040, 0x24ac, 0x7038, 0x6816, 0xa68c, 0xdf00, 0x691a, 0x70a3,
+	0x0000, 0x0078, 0x1ba8, 0xa006, 0x1078, 0x2e0e, 0x6813, 0x0000,
+	0x6817, 0x0001, 0xa68c, 0xdf00, 0x691a, 0x6827, 0x0000, 0x7000,
+	0x0079, 0x24c2, 0x24ca, 0x24cc, 0x24cc, 0x24ce, 0x24ce, 0x24ce,
+	0x24ca, 0x24ca, 0x1078, 0x1b4e, 0x1078, 0x2853, 0x6008, 0xa084,
+	0xffef, 0x600a, 0x0078, 0x281e, 0x2300, 0x0079, 0x24d7, 0x24da,
+	0x24dc, 0x251a, 0x1078, 0x1b4e, 0x7000, 0x0079, 0x24df, 0x24e7,
+	0x24e9, 0x24e9, 0x24f4, 0x24e9, 0x24fb, 0x24e7, 0x24e7, 0x1078,
+	0x1b4e, 0xa684, 0x2000, 0x00c0, 0x24f4, 0xa6b5, 0x2000, 0x7e5a,
+	0x1078, 0x2ffc, 0x0078, 0x2c7f, 0x6814, 0xa084, 0x8000, 0x0040,
+	0x24fb, 0x6817, 0x0007, 0x2009, 0x3418, 0x210c, 0xa186, 0x0000,
+	0x0040, 0x2510, 0xa186, 0x0001, 0x0040, 0x2514, 0x2009, 0x342b,
+	0x200b, 0x000b, 0x70a3, 0x0001, 0x781b, 0x0046, 0x0078, 0x1ba0,
+	0x781b, 0x00dd, 0x0078, 0x1ba0, 0x2009, 0x342b, 0x200b, 0x000a,
+	0x0078, 0x1ba0, 0x1078, 0x1b4e, 0x2300, 0x0079, 0x251f, 0x2522,
+	0x2524, 0x2547, 0x1078, 0x1b4e, 0x7000, 0x0079, 0x2527, 0x252f,
+	0x2531, 0x2531, 0x253c, 0x2531, 0x2543, 0x252f, 0x252f, 0x1078,
+	0x1b4e, 0xa684, 0x2000, 0x00c0, 0x253c, 0xa6b5, 0x2000, 0x7e5a,
+	0x1078, 0x2ffc, 0x0078, 0x2c7f, 0x6814, 0xa084, 0x8000, 0x0040,
+	0x2543, 0x6817, 0x0007, 0x781b, 0x00e4, 0x0078, 0x1ba0, 0x681c,
+	0xa085, 0x0004, 0x681e, 0x1078, 0x2c4a, 0xa6b5, 0x0800, 0x1078,
+	0x2ae4, 0x781b, 0x0069, 0x0078, 0x1ba0, 0x2300, 0x0079, 0x2558,
+	0x255b, 0x255d, 0x255f, 0x1078, 0x1b4e, 0x1078, 0x1b4e, 0xa684,
+	0x0400, 0x00c0, 0x257e, 0x782b, 0x3009, 0x789b, 0x0060, 0x78ab,
+	0x0000, 0xa684, 0xfffb, 0x785a, 0x79e4, 0xa184, 0x0020, 0x0040,
+	0x2576, 0x78ec, 0xa084, 0x0003, 0x00c0, 0x257a, 0x2001, 0x0014,
+	0x0078, 0x2282, 0xa184, 0x0007, 0x0079, 0x25b6, 0x7a90, 0xa294,
+	0x0007, 0x789b, 0x0060, 0x79a8, 0x81ff, 0x0040, 0x25b4, 0x789b,
+	0x0010, 0x7ba8, 0xa384, 0x0001, 0x00c0, 0x25a5, 0x7ba8, 0x7ba8,
+	0xa386, 0x0001, 0x00c0, 0x2598, 0x2009, 0xfff7, 0x0078, 0x259e,
+	0xa386, 0x0003, 0x00c0, 0x25a5, 0x2009, 0xffef, 0x0c7e, 0x7048,
+	0x2060, 0x6004, 0xa104, 0x6006, 0x0c7f, 0x789b, 0x0060, 0x78ab,
+	0x0000, 0xa684, 0xfffb, 0x785a, 0x782b, 0x3009, 0x691c, 0xa18c,
+	0xfdff, 0xa18c, 0xfeff, 0x691e, 0x0078, 0x2c7f, 0x1fc3, 0x1fc9,
+	0x25c0, 0x25c8, 0x25be, 0x25be, 0x25be, 0x2c7f, 0x1078, 0x1b4e,
+	0x691c, 0xa18c, 0xfdff, 0xa18c, 0xfeff, 0x691e, 0x0078, 0x2c87,
+	0x691c, 0xa18c, 0xfdff, 0xa18c, 0xfeff, 0x691e, 0x0078, 0x2c7f,
+	0x79e4, 0xa184, 0x0030, 0x0040, 0x25da, 0x78ec, 0xa084, 0x0003,
+	0x00c0, 0x25e2, 0x6814, 0xa085, 0x8000, 0x6816, 0x2001, 0x0014,
+	0x0078, 0x2282, 0xa184, 0x0007, 0x0079, 0x25e6, 0x2c7f, 0x2c7f,
+	0x25ee, 0x2c7f, 0x2ca7, 0x2ca7, 0x2c7f, 0x2c7f, 0xa684, 0x0400,
+	0x00c0, 0x261f, 0x681c, 0xa084, 0x0001, 0x0040, 0x2c87, 0xa68c,
+	0x2060, 0xa18c, 0xfffb, 0x795a, 0x69b2, 0x789b, 0x0060, 0x78ab,
+	0x0000, 0x789b, 0x0061, 0x6814, 0xa085, 0x8000, 0x6816, 0x78aa,
+	0x157e, 0x137e, 0x147e, 0x20a1, 0x012c, 0x789b, 0x0000, 0x8000,
+	0x80ac, 0xad80, 0x000a, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f,
+	0x6810, 0x8007, 0x789b, 0x007e, 0x78aa, 0x0078, 0x2c87, 0x6814,
+	0xa084, 0x8000, 0x0040, 0x2626, 0x6817, 0x0008, 0x781b, 0x00d8,
+	0x0078, 0x1ba0, 0x2300, 0x0079, 0x262d, 0x2632, 0x26ac, 0x2630,
+	0x1078, 0x1b4e, 0x7000, 0xa084, 0x0007, 0x0079, 0x2637, 0x263f,
+	0x2641, 0x265d, 0x263f, 0x263f, 0x243b, 0x263f, 0x263f, 0x1078,
+	0x1b4e, 0x691c, 0xa18d, 0x0001, 0x691e, 0x6800, 0x6006, 0xa005,
+	0x00c0, 0x264b, 0x6002, 0x6818, 0xa084, 0x000e, 0x0040, 0x2657,
+	0x7014, 0x68b6, 0x712c, 0xa188, 0x3d80, 0x0078, 0x2659, 0x2009,
+	0x3e80, 0x2104, 0x6802, 0x2d0a, 0x7156, 0x691c, 0x691e, 0x6eb2,
+	0xa684, 0x0060, 0x0040, 0x26aa, 0xa684, 0x0800, 0x00c0, 0x266e,
+	0x6890, 0x6894, 0x1078, 0x2e0e, 0x0078, 0x26aa, 0xa684, 0x0020,
+	0x0040, 0x2680, 0xa006, 0x1078, 0x30a0, 0x78d0, 0x8003, 0x00c8,
+	0x267c, 0x78d4, 0x1078, 0x3103, 0x79d8, 0x7adc, 0x0078, 0x2684,
+	0x1078, 0x2c09, 0x1078, 0x30a0, 0xa684, 0x8000, 0x0040, 0x26aa,
+	0xa684, 0x7fff, 0x68b2, 0x789b, 0x0074, 0x1078, 0x2ccb, 0x2010,
+	0x1078, 0x2ccb, 0x2008, 0xa684, 0x0020, 0x00c0, 0x26a2, 0x1078,
+	0x2ccb, 0x801b, 0x00c8, 0x269d, 0x8000, 0xa084, 0x003f, 0xa108,
+	0xa291, 0x0000, 0x6b94, 0x2100, 0xa302, 0x68ae, 0x6b90, 0x2200,
+	0xa303, 0x68aa, 0x0078, 0x1ba8, 0x0078, 0x2ad1, 0x7033, 0x0000,
+	0xa282, 0x0005, 0x0050, 0x26b6, 0x1078, 0x1b4e, 0x2300, 0x0079,
+	0x26b9, 0x26bc, 0x26c6, 0x26e9, 0x2200, 0x0079, 0x26bf, 0x26c4,
+	0x2ad1, 0x26c4, 0x2712, 0x2763, 0x1078, 0x1b4e, 0x7000, 0xa086,
+	0x0001, 0x00c0, 0x26d3, 0x1078, 0x2853, 0x1078, 0x2e0e, 0x7034,
+	0x600a, 0x0078, 0x26d8, 0x7000, 0xa086, 0x0003, 0x0040, 0x26cd,
+	0x7003, 0x0005, 0x2001, 0x3e90, 0x2068, 0x703e, 0x7032, 0x2200,
+	0x0079, 0x26e2, 0x2ad1, 0x26e7, 0x2712, 0x26e7, 0x2ad1, 0x1078,
+	0x1b4e, 0x7000, 0xa086, 0x0001, 0x00c0, 0x26f6, 0x1078, 0x2853,
+	0x1078, 0x2e0e, 0x7034, 0x600a, 0x0078, 0x26fb, 0x7000, 0xa086,
+	0x0003, 0x0040, 0x26f0, 0x7003, 0x0005, 0x2001, 0x3e90, 0x2068,
+	0x703e, 0x7032, 0x2200, 0x0079, 0x2705, 0x270c, 0x270a, 0x270c,
+	0x270a, 0x270c, 0x1078, 0x1b4e, 0x1078, 0x2af4, 0x781b, 0x0069,
+	0x0078, 0x1ba0, 0x7000, 0xa086, 0x0001, 0x00c0, 0x271f, 0x1078,
+	0x2853, 0x1078, 0x2e0e, 0x7034, 0x600a, 0x0078, 0x2724, 0x7000,
+	0xa086, 0x0003, 0x0040, 0x2719, 0x7003, 0x0002, 0x7a80, 0xa294,
+	0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, 0x0007, 0xa215, 0x2069,
+	0x3e80, 0x2d04, 0x2d08, 0x7156, 0x2068, 0xa005, 0x0040, 0x273f,
+	0x6810, 0xa206, 0x0040, 0x2758, 0x6800, 0x0078, 0x2732, 0x7003,
+	0x0005, 0x2001, 0x3e90, 0x2068, 0x703e, 0x7032, 0x157e, 0x20a9,
+	0x002e, 0x2003, 0x0000, 0x8000, 0x0070, 0x2750, 0x0078, 0x2749,
+	0x157f, 0x6a12, 0x68b3, 0x0700, 0x681f, 0x0800, 0x6823, 0x0003,
+	0x6eb0, 0x7e5a, 0x681c, 0xa084, 0x0c00, 0x0040, 0x27b9, 0x1078,
+	0x2aec, 0x0078, 0x27b9, 0x7000, 0xa086, 0x0001, 0x00c0, 0x2770,
+	0x1078, 0x2853, 0x1078, 0x2e0e, 0x7034, 0x600a, 0x0078, 0x2775,
+	0x7000, 0xa086, 0x0003, 0x0040, 0x276a, 0x7003, 0x0002, 0x7a80,
+	0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, 0x0007, 0xa215,
+	0x79a8, 0x79a8, 0xa18c, 0x00ff, 0xa1e8, 0x3d80, 0x2d04, 0x2d08,
+	0x7156, 0x2068, 0xa005, 0x0040, 0x2794, 0x6810, 0xa206, 0x0040,
+	0x27ad, 0x6800, 0x0078, 0x2787, 0x7003, 0x0005, 0x2001, 0x3e90,
+	0x2068, 0x703e, 0x7032, 0x157e, 0x20a9, 0x002e, 0x2003, 0x0000,
+	0x8000, 0x0070, 0x27a5, 0x0078, 0x279e, 0x157f, 0x6a12, 0x68b3,
+	0x0700, 0x681f, 0x0800, 0x6823, 0x0003, 0x6eb0, 0x7e5a, 0x681c,
+	0xa084, 0x0c00, 0x0040, 0x27b9, 0x1078, 0x2ae8, 0x7e58, 0x0078,
+	0x27b9, 0x027e, 0x8207, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003,
+	0xa080, 0x3500, 0x2060, 0x704a, 0x6000, 0x704e, 0x6004, 0x7052,
+	0xa684, 0x0060, 0x0040, 0x27ea, 0x6b94, 0x6c90, 0x69a8, 0x68ac,
+	0xa105, 0x00c0, 0x27db, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0x1078,
+	0x2ffc, 0x0078, 0x27ea, 0x68ac, 0xa31a, 0x2100, 0xa423, 0x2400,
+	0xa305, 0x0040, 0x27ea, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0x68ac,
+	0x1078, 0x3029, 0x077f, 0x1078, 0x2bfc, 0x2009, 0x006a, 0xa684,
+	0x0008, 0x0040, 0x27f5, 0x2009, 0x0069, 0xa6b5, 0x2000, 0x7e5a,
+	0x791a, 0x2d00, 0x703e, 0x8207, 0xa084, 0x000f, 0x8003, 0x8003,
+	0x8003, 0xa080, 0x3500, 0x2048, 0x0078, 0x1ba0, 0x6020, 0xa005,
+	0x0040, 0x2812, 0x8001, 0x6022, 0x6008, 0xa085, 0x0008, 0x600a,
+	0x7010, 0x6026, 0x007c, 0xa006, 0x1078, 0x2e0e, 0x6813, 0x0000,
+	0x6817, 0x0001, 0x681f, 0x0040, 0x681b, 0x0100, 0x7000, 0xa084,
+	0x0007, 0x0079, 0x2823, 0x282b, 0x282d, 0x282d, 0x2839, 0x2835,
+	0x282b, 0x282b, 0x282b, 0x1078, 0x1b4e, 0x1078, 0x2844, 0x1078,
+	0x283d, 0x1078, 0x17be, 0x0078, 0x1ba8, 0x70a3, 0x0000, 0x0078,
+	0x1ba8, 0x6817, 0x0000, 0x0078, 0x2471, 0x6800, 0xa005, 0x00c0,
+	0x2842, 0x6002, 0x6006, 0x007c, 0x6010, 0xa005, 0x0040, 0x284d,
+	0x8001, 0x00d0, 0x284d, 0x1078, 0x1b4e, 0x6012, 0x6008, 0xa084,
+	0xffef, 0x600a, 0x007c, 0x6018, 0xa005, 0x0040, 0x2859, 0x8001,
+	0x601a, 0x007c, 0x1078, 0x2cc6, 0x6814, 0xa084, 0x8000, 0x0040,
+	0x2863, 0x6817, 0x0018, 0x0078, 0x2894, 0x1078, 0x2cc6, 0x6814,
+	0xa084, 0x8000, 0x0040, 0x286e, 0x6817, 0x0019, 0x0078, 0x2894,
+	0x1078, 0x2cc6, 0x6814, 0xa084, 0x8000, 0x0040, 0x2879, 0x6817,
+	0x001a, 0x0078, 0x2894, 0x71b8, 0xa18c, 0x00ff, 0xa1e8, 0x3d80,
+	0x2d04, 0x2d08, 0x2068, 0xa005, 0x00c0, 0x2888, 0x0078, 0x1ba8,
+	0x6810, 0x72b4, 0xa206, 0x0040, 0x2890, 0x6800, 0x0078, 0x2881,
+	0x6800, 0x200a, 0x6817, 0x0005, 0x681b, 0x0000, 0x681f, 0x0020,
+	0x1078, 0x2844, 0x1078, 0x283d, 0x1078, 0x17be, 0x0078, 0x1ba8,
+	0xa282, 0x0003, 0x00c0, 0x2ac5, 0x7da8, 0xa5ac, 0x00ff, 0x7ea8,
+	0xa6b4, 0x00ff, 0x691c, 0xa18d, 0x0080, 0x691e, 0xa184, 0x0100,
+	0x0040, 0x2900, 0xa18c, 0xfeff, 0x691e, 0xa6b4, 0x00ff, 0x0040,
+	0x28ea, 0xa682, 0x000f, 0x0048, 0x28c1, 0x0040, 0x28c1, 0x2031,
+	0x000f, 0x852b, 0x852b, 0x1078, 0x2b7f, 0x0040, 0x28cb, 0x1078,
+	0x299a, 0x0078, 0x28f3, 0x1078, 0x2b3a, 0x0c7e, 0x2960, 0x6004,
+	0xa084, 0xfff5, 0x6006, 0x1078, 0x29be, 0x0c7f, 0x691c, 0xa18d,
+	0x0100, 0x691e, 0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400,
+	0x00c0, 0x28e6, 0x781b, 0x0055, 0x0078, 0x1ba0, 0x781b, 0x0069,
+	0x0078, 0x1ba0, 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5, 0x6006,
+	0x1078, 0x29be, 0x0c7f, 0x7e58, 0xa684, 0x0400, 0x00c0, 0x28fc,
+	0x781b, 0x0058, 0x0078, 0x1ba0, 0x781b, 0x006a, 0x0078, 0x1ba0,
+	0x0c7e, 0x7048, 0x2060, 0x6100, 0xa18c, 0x1000, 0x0040, 0x2940,
+	0x6208, 0x8217, 0xa294, 0x00ff, 0xa282, 0x000f, 0x0048, 0x2914,
+	0x0040, 0x2914, 0x2011, 0x000f, 0x2600, 0xa202, 0x00c8, 0x2919,
+	0x2230, 0x6208, 0xa294, 0x00ff, 0x7018, 0xa086, 0x0028, 0x00c0,
+	0x2929, 0xa282, 0x0019, 0x00c8, 0x292f, 0x2011, 0x0019, 0x0078,
+	0x292f, 0xa282, 0x000c, 0x00c8, 0x292f, 0x2011, 0x000c, 0x2200,
+	0xa502, 0x00c8, 0x2934, 0x2228, 0x1078, 0x2b3e, 0x852b, 0x852b,
+	0x1078, 0x2b7f, 0x0040, 0x2940, 0x1078, 0x299a, 0x0078, 0x2944,
+	0x1078, 0x2b3a, 0x1078, 0x29be, 0x7858, 0xa085, 0x0004, 0x785a,
+	0x0c7f, 0x781b, 0x0069, 0x0078, 0x1ba0, 0x0c7e, 0x2960, 0x6000,
+	0xa084, 0x1000, 0x00c0, 0x2968, 0x6010, 0xa084, 0x000f, 0x00c0,
+	0x2962, 0xa18c, 0x0002, 0x00c0, 0x2962, 0xa18c, 0xfff5, 0x6106,
+	0x0c7f, 0x007c, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, 0x298a,
+	0x6208, 0xa294, 0x00ff, 0x7018, 0xa086, 0x0028, 0x00c0, 0x2978,
+	0xa282, 0x0019, 0x00c8, 0x297e, 0x2011, 0x0019, 0x0078, 0x297e,
+	0xa282, 0x000c, 0x00c8, 0x297e, 0x2011, 0x000c, 0x6308, 0x831f,
+	0xa39c, 0x00ff, 0xa382, 0x000f, 0x0048, 0x298a, 0x0040, 0x298a,
+	0x2019, 0x000f, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001,
+	0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x681c, 0xa085, 0x0100, 0x681e,
+	0x0c7f, 0x007c, 0x0c7e, 0x7148, 0x2160, 0x2008, 0xa084, 0xfff0,
+	0xa635, 0x7e86, 0x6018, 0x789a, 0x7eae, 0x6612, 0x78a4, 0xa084,
+	0xfff8, 0xa18c, 0x0007, 0xa105, 0x78a6, 0x6016, 0x788a, 0xa6b4,
+	0x000f, 0x8637, 0x8204, 0x8004, 0xa084, 0x00ff, 0xa605, 0x600e,
+	0x6004, 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x007c, 0x0c7e, 0x7048,
+	0x2060, 0x6018, 0x789a, 0x78a4, 0xa084, 0xfff0, 0x78a6, 0x6012,
+	0x7884, 0xa084, 0xfff0, 0x7886, 0x0c7f, 0x007c, 0xa282, 0x0002,
+	0x00c0, 0x2ac5, 0x7aa8, 0x691c, 0xa18d, 0x0080, 0x691e, 0xa184,
+	0x0200, 0x0040, 0x2a13, 0xa18c, 0xfdff, 0x691e, 0xa294, 0x00ff,
+	0xa282, 0x0002, 0x00c8, 0x2ac5, 0x1078, 0x2a5a, 0x1078, 0x29be,
+	0xa980, 0x0001, 0x200c, 0x1078, 0x2bf8, 0x1078, 0x294d, 0x88ff,
+	0x0040, 0x2a06, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xa6b5,
+	0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2a02, 0x781b, 0x0055,
+	0x0078, 0x1ba0, 0x781b, 0x0069, 0x0078, 0x1ba0, 0x7e58, 0xa684,
+	0x0400, 0x00c0, 0x2a0f, 0x781b, 0x0058, 0x0078, 0x1ba0, 0x781b,
+	0x006a, 0x0078, 0x1ba0, 0xa282, 0x0002, 0x00c8, 0x2a1b, 0xa284,
+	0x0001, 0x0040, 0x2a25, 0x7148, 0xa188, 0x0000, 0x210c, 0xa18c,
+	0x2000, 0x00c0, 0x2a25, 0x2011, 0x0000, 0x1078, 0x2b2c, 0x1078,
+	0x2a5a, 0x1078, 0x29be, 0x7858, 0xa085, 0x0004, 0x785a, 0x781b,
+	0x0069, 0x0078, 0x1ba0, 0x0c7e, 0x027e, 0x2960, 0x6000, 0x2011,
+	0x0001, 0xa084, 0x2000, 0x00c0, 0x2a4a, 0x6014, 0xa084, 0x0040,
+	0x00c0, 0x2a48, 0xa18c, 0xffef, 0x6106, 0xa006, 0x0078, 0x2a57,
+	0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003,
+	0x7aaa, 0xa8c0, 0x0004, 0x681c, 0xa085, 0x0200, 0x681e, 0x027f,
+	0x0c7f, 0x007c, 0x0c7e, 0x7048, 0x2060, 0x82ff, 0x0040, 0x2a62,
+	0x2011, 0x0040, 0x6018, 0xa080, 0x0002, 0x789a, 0x78a4, 0xa084,
+	0xffbf, 0xa205, 0x78a6, 0x6016, 0x788a, 0x6004, 0xa084, 0xffef,
+	0x6006, 0x0c7f, 0x007c, 0xa684, 0x0020, 0x0040, 0x2ac1, 0x7888,
+	0xa084, 0x0040, 0x0040, 0x2ac1, 0x78a8, 0x8001, 0x0040, 0x2a80,
+	0x7bb8, 0xa384, 0x003f, 0x831b, 0x00c8, 0x2a87, 0x8000, 0xa005,
+	0x0040, 0x2aa8, 0x831b, 0x00c8, 0x2a90, 0x8001, 0x0040, 0x2abd,
+	0xa006, 0x1078, 0x30a0, 0x78b4, 0x1078, 0x3103, 0x0078, 0x2ac1,
+	0xa684, 0x4000, 0x0040, 0x2aa8, 0x78b8, 0x801b, 0x00c8, 0x2aa1,
+	0x8000, 0xa084, 0x003f, 0x00c0, 0x2abd, 0xa6b4, 0xbfff, 0x7e5a,
+	0x79d8, 0x7adc, 0x2001, 0x0001, 0xa108, 0x00c8, 0x2ab1, 0xa291,
+	0x0000, 0x79d2, 0x79da, 0x7ad6, 0x7ade, 0x1078, 0x30a0, 0x781b,
+	0x0067, 0x1078, 0x2f6a, 0x0078, 0x1ba0, 0x781b, 0x0067, 0x0078,
+	0x1ba0, 0x781b, 0x006a, 0x0078, 0x1ba0, 0x1078, 0x2af8, 0x781b,
+	0x0069, 0x0078, 0x1ba0, 0x1078, 0x2ae4, 0x781b, 0x0069, 0x0078,
+	0x1ba0, 0x6823, 0x0002, 0x1078, 0x2aec, 0x691c, 0xa18d, 0x0020,
+	0x691e, 0x6814, 0xa084, 0x8000, 0x0040, 0x2ae0, 0x6817, 0x0005,
+	0x781b, 0x0069, 0x0078, 0x1ba0, 0x2001, 0x0005, 0x0078, 0x2afa,
+	0x2001, 0x000c, 0x0078, 0x2afa, 0x2001, 0x0006, 0x0078, 0x2afa,
+	0x2001, 0x000d, 0x0078, 0x2afa, 0x2001, 0x0009, 0x0078, 0x2afa,
+	0x2001, 0x0007, 0x789b, 0x007f, 0x78aa, 0xa6b5, 0x0008, 0x7e5a,
+	0x007c, 0x077e, 0x873f, 0xa7bc, 0x000f, 0x873b, 0x873b, 0x8703,
+	0xa0e0, 0x3500, 0xa7b8, 0x0020, 0x7f9a, 0x79a4, 0xa184, 0x000f,
+	0x0040, 0x2b1a, 0xa184, 0xfff0, 0x78a6, 0x6012, 0x6004, 0xa085,
+	0x0008, 0x6006, 0x8738, 0x8738, 0x7f9a, 0x79a4, 0xa184, 0x0040,
+	0x0040, 0x2b2a, 0xa184, 0xffbf, 0x78a6, 0x6016, 0x6004, 0xa085,
+	0x0010, 0x6006, 0x077f, 0x007c, 0x789b, 0x0010, 0x78ab, 0x0001,
+	0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0060, 0x78ab,
+	0x0004, 0x007c, 0x2031, 0x0000, 0x2029, 0x0032, 0x789b, 0x0010,
+	0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa, 0x7eaa,
+	0x789b, 0x0060, 0x78ab, 0x0005, 0x007c, 0x157e, 0x8007, 0xa084,
+	0x00ff, 0x8003, 0x8003, 0xa080, 0x0020, 0x789a, 0x79a4, 0xa18c,
+	0xfff0, 0x2001, 0x3446, 0x2004, 0xa082, 0x0028, 0x0040, 0x2b68,
+	0x2021, 0x2bdf, 0x2019, 0x0014, 0x20a9, 0x000c, 0x0078, 0x2b6e,
+	0x2021, 0x2beb, 0x2019, 0x0019, 0x20a9, 0x000d, 0x2011, 0x0064,
+	0x2404, 0xa084, 0xfff0, 0xa106, 0x0040, 0x2b7d, 0x8420, 0x2300,
+	0xa210, 0x0070, 0x2b7d, 0x0078, 0x2b70, 0x157f, 0x007c, 0x157e,
+	0x2011, 0x3446, 0x2214, 0xa282, 0x0032, 0x0048, 0x2b93, 0x0040,
+	0x2b97, 0x2021, 0x2bd1, 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011,
+	0x0032, 0x0078, 0x2ba7, 0xa282, 0x0028, 0x0040, 0x2b9f, 0x2021,
+	0x2bdf, 0x2019, 0x0014, 0x20a9, 0x000c, 0x0078, 0x2ba5, 0x2021,
+	0x2beb, 0x2019, 0x0019, 0x20a9, 0x000d, 0x2011, 0x0064, 0x2200,
+	0xa502, 0x0040, 0x2bb7, 0x0048, 0x2bb7, 0x8420, 0x2300, 0xa210,
+	0x0070, 0x2bb4, 0x0078, 0x2ba7, 0x157f, 0xa006, 0x007c, 0x157f,
+	0xa582, 0x0064, 0x00c8, 0x2bc0, 0x7808, 0xa085, 0x0040, 0x780a,
+	0x78ec, 0xa084, 0x0300, 0x0040, 0x2bce, 0x2404, 0xa09e, 0x2002,
+	0x00c0, 0x2bce, 0x2001, 0x2101, 0x0078, 0x2bcf, 0x2404, 0xa005,
+	0x007c, 0x2002, 0x3002, 0x3202, 0x4203, 0x4403, 0x5404, 0x5604,
+	0x6605, 0x6805, 0x7806, 0x7a06, 0x0a07, 0x0c07, 0x0e07, 0x3202,
+	0x4202, 0x5202, 0x6202, 0x7202, 0x6605, 0x7605, 0x7805, 0x7a05,
+	0x7c05, 0x7e05, 0x7f05, 0x2202, 0x3202, 0x4202, 0x5202, 0x5404,
+	0x6404, 0x7404, 0x7604, 0x7804, 0x7a04, 0x7c04, 0x7e04, 0x7f04,
+	0x789b, 0x0010, 0xa046, 0x007c, 0xa784, 0x0f00, 0x800c, 0xa784,
+	0x0007, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xa0e0, 0x3580,
+	0x007c, 0x79d8, 0x7adc, 0x78d0, 0x801b, 0x00c8, 0x2c10, 0x8000,
+	0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x007c, 0x0f7e, 0x2079,
+	0x0100, 0x2009, 0x3440, 0x2091, 0x8000, 0x2104, 0x0079, 0x2c20,
+	0x2c46, 0x2c2a, 0x2c2a, 0x2c2a, 0x2c2a, 0x2c2a, 0x2c28, 0x2c28,
+	0x1078, 0x1b4e, 0x784b, 0x0004, 0x68b0, 0xa085, 0x4000, 0x68b2,
+	0x7858, 0xa085, 0x4000, 0x785a, 0x7830, 0xa084, 0x0080, 0x00c0,
+	0x2c46, 0x0018, 0x2c46, 0x6818, 0xa084, 0x0020, 0x00c0, 0x2c44,
+	0x781b, 0x00dd, 0x0078, 0x2c46, 0x781b, 0x00e4, 0x2091, 0x8001,
+	0x0f7f, 0x007c, 0x0c7e, 0x6810, 0x8007, 0xa084, 0x000f, 0x8003,
+	0x8003, 0x8003, 0xa0e0, 0x3500, 0x6004, 0xa084, 0x000a, 0x00c0,
+	0x2c7d, 0x6108, 0xa194, 0xff00, 0x0040, 0x2c7d, 0xa18c, 0x00ff,
+	0x2001, 0x0019, 0xa106, 0x0040, 0x2c6c, 0x2001, 0x0032, 0xa106,
+	0x0040, 0x2c70, 0x0078, 0x2c74, 0x2009, 0x0020, 0x0078, 0x2c76,
+	0x2009, 0x003f, 0x0078, 0x2c76, 0x2011, 0x0000, 0x2100, 0xa205,
+	0x600a, 0x6004, 0xa085, 0x0002, 0x6006, 0x0c7f, 0x007c, 0x781b,
+	0x006a, 0x0078, 0x1ba0, 0x781b, 0x0069, 0x0078, 0x1ba0, 0x781b,
+	0x0058, 0x0078, 0x1ba0, 0x781b, 0x0055, 0x0078, 0x1ba0, 0x781b,
+	0x00dd, 0x0078, 0x1ba0, 0x781b, 0x00dc, 0x0078, 0x1ba0, 0x781b,
+	0x00e4, 0x0078, 0x1ba0, 0x781b, 0x00e3, 0x0078, 0x1ba0, 0x781b,
+	0x009e, 0x0078, 0x1ba0, 0x781b, 0x009d, 0x0078, 0x1ba0, 0x70a3,
+	0x0001, 0x781b, 0x0046, 0x0078, 0x1ba0, 0x007e, 0x7830, 0xa084,
+	0x00c0, 0x00c0, 0x2cc4, 0x7808, 0xa084, 0xfffd, 0x780a, 0x0005,
+	0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, 0x0040, 0x2cc4,
+	0x7808, 0xa085, 0x0002, 0x780a, 0x007f, 0x007c, 0x7808, 0xa085,
+	0x0002, 0x780a, 0x007c, 0x7830, 0xa084, 0x0040, 0x00c0, 0x2ccb,
+	0x0098, 0x2cd4, 0x78ac, 0x007c, 0x7808, 0xa084, 0xfffd, 0x780a,
+	0x0005, 0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, 0x0040,
+	0x2ce3, 0x0098, 0x2ce1, 0x78ac, 0x007e, 0x7808, 0xa085, 0x0002,
+	0x780a, 0x007f, 0x007c, 0xa784, 0x0070, 0x0040, 0x2cef, 0x6817,
+	0x0003, 0x7858, 0xa084, 0x3f00, 0x681a, 0x682f, 0x0000, 0x682b,
+	0x0000, 0x784b, 0x0008, 0x78e4, 0xa005, 0x00d0, 0x1fb9, 0xa084,
+	0x0020, 0x0040, 0x1fb9, 0x78ec, 0xa084, 0x0003, 0x0040, 0x1fb9,
+	0x0018, 0x1fb9, 0x0078, 0x2acb, 0x0c7e, 0x6810, 0x8007, 0xa084,
+	0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x3500, 0x2060, 0x2048,
+	0x704a, 0x6000, 0x704e, 0x6004, 0x7052, 0x0c7f, 0x007c, 0x0020,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0062, 0x0009, 0x0014, 0x0014, 0x9847, 0x0014, 0x0014,
+	0x98f5, 0x98e7, 0x0014, 0x0014, 0x0080, 0x00bf, 0x0100, 0x0402,
+	0x2008, 0xf880, 0xa20a, 0x0014, 0x300b, 0xa20c, 0x0014, 0xa200,
+	0x8838, 0x817e, 0x842a, 0x84a0, 0x3806, 0x8839, 0x28c2, 0x9cc3,
+	0xa805, 0x0864, 0xa83b, 0x3008, 0x28c1, 0x9cc3, 0xa201, 0x300c,
+	0x2847, 0x8161, 0x846a, 0x8000, 0x84a4, 0x1856, 0x883a, 0xa808,
+	0x28e2, 0x9ca0, 0xa8f3, 0x0864, 0xa829, 0x300c, 0xa801, 0x3008,
+	0x28e1, 0x9ca0, 0x280d, 0xa204, 0x64c0, 0x67a0, 0x6fc0, 0x1814,
+	0x883b, 0x7023, 0x8576, 0x8677, 0xa80f, 0x786e, 0x883e, 0xa80c,
+	0x282b, 0xa205, 0x64a0, 0x67a0, 0x6fc0, 0x1814, 0x883b, 0x7023,
+	0x8576, 0x8677, 0xa801, 0x883e, 0x2069, 0x28c1, 0x9cc3, 0x2044,
+	0x2103, 0x20a2, 0x2081, 0xa8dc, 0xa207, 0x0014, 0xa203, 0x8000,
+	0x84a8, 0x85a4, 0x1872, 0x849a, 0x883c, 0x1fe2, 0xf601, 0xa208,
+	0x856e, 0x866f, 0x0704, 0x3008, 0x9ca0, 0x0014, 0xa202, 0x8000,
+	0x85a4, 0x3009, 0x84a8, 0x19e2, 0xf848, 0x8174, 0x86eb, 0x85eb,
+	0x872e, 0x87a9, 0x883f, 0x08e6, 0xa8f1, 0xf861, 0xa8e8, 0xf801,
+	0x0014, 0xf881, 0x0016, 0x85b2, 0x80f0, 0x9532, 0xfaa2, 0x1de2,
+	0x0014, 0x8532, 0xf221, 0x0014, 0x1de2, 0x84a8, 0xd6e0, 0x1fe6,
+	0x0014, 0xa206, 0x6865, 0x817f, 0x842a, 0x1dc1, 0x8823, 0x0016,
+	0x6042, 0x8008, 0xa8fa, 0x8000, 0x84a4, 0x8160, 0x842a, 0xf021,
+	0x3008, 0x84a8, 0x1dc6, 0x20d7, 0x8822, 0x0016, 0x8000, 0x2848,
+	0x1011, 0xa8fc, 0x3008, 0x8000, 0xa000, 0x2802, 0x1011, 0xa8fd,
+	0xa887, 0x3008, 0x283d, 0x1011, 0xa8fd, 0xa209, 0x0017, 0x300c,
+	0x8000, 0x85a4, 0x1de2, 0xdac1, 0x0014, 0x26e0, 0x873a, 0xfaa2,
+	0x19f2, 0x1fe2, 0x0014, 0xa20b, 0x0014, 0xa20d, 0x817e, 0x842a,
+	0x84a0, 0x3806, 0x0210, 0x9ccd, 0x0704, 0x0000, 0x127e, 0x2091,
+	0x2200, 0x2049, 0x2e0e, 0x7000, 0x7204, 0xa205, 0x720c, 0xa215,
+	0x7008, 0xa084, 0xfffd, 0xa205, 0x0040, 0x2e20, 0x1078, 0x2e68,
+	0x7003, 0x0000, 0x127f, 0x2000, 0x007c, 0x6424, 0x84ff, 0x0040,
+	0x2e42, 0x2c70, 0x2039, 0x2e47, 0x2704, 0xae68, 0x680c, 0xa630,
+	0x6808, 0xa529, 0x8421, 0x0040, 0x2e42, 0x8738, 0x2704, 0xa005,
+	0x00c0, 0x2e2d, 0x7098, 0xa075, 0x0040, 0x2e42, 0x2039, 0x2e44,
+	0x0078, 0x2e2c, 0x007c, 0x0000, 0x0004, 0x0008, 0x000c, 0x0010,
+	0x0014, 0x0018, 0x001c, 0x0000, 0x127e, 0x2091, 0x2200, 0x2079,
+	0x3400, 0x2071, 0x0010, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003,
+	0x0000, 0x2071, 0x0020, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003,
+	0x0000, 0x2049, 0x0000, 0x78b3, 0x0000, 0x127f, 0x2000, 0x007c,
+	0x2049, 0x2e68, 0x7004, 0x8004, 0x00c8, 0x2e90, 0x7007, 0x0012,
+	0x7108, 0x7008, 0xa106, 0x00c0, 0x2e70, 0xa184, 0x0030, 0x0040,
+	0x2e7d, 0xa086, 0x0030, 0x00c0, 0x2e70, 0x7000, 0xa084, 0x0001,
+	0x00c0, 0x2e90, 0x7008, 0xa084, 0x000c, 0x00c0, 0x2e90, 0x710c,
+	0xa184, 0x0300, 0x00c0, 0x2e90, 0xa184, 0x007f, 0x00c0, 0x2e68,
+	0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xa084, 0x0008, 0x00c0,
+	0x2e94, 0x7007, 0x0012, 0x7108, 0x8104, 0x0048, 0x2e99, 0x78b3,
+	0x0000, 0x7003, 0x0000, 0x2049, 0x0000, 0x007c, 0x107e, 0x007e,
+	0x127e, 0x157e, 0x2091, 0x2200, 0x7108, 0x1078, 0x2eb6, 0x157f,
+	0x127f, 0x2091, 0x8001, 0x007f, 0x107f, 0x007c, 0x7204, 0x2118,
+	0x7108, 0x700c, 0xa084, 0x0300, 0x00c0, 0x2ef8, 0xa184, 0x000c,
+	0x00c0, 0x2ef8, 0x8213, 0x8213, 0x8213, 0x8213, 0xa284, 0x0100,
+	0xa10d, 0x810b, 0x810b, 0x810f, 0xa184, 0x0007, 0x0079, 0x2ed0,
+	0x2eda, 0x2eea, 0x2ef8, 0x2eea, 0x2f0c, 0x2f0c, 0x2ef8, 0x2f0a,
+	0x1078, 0x1b4e, 0x7007, 0x0002, 0x8aff, 0x00c0, 0x2ee3, 0x2049,
+	0x0000, 0x0078, 0x2ee7, 0x1078, 0x3077, 0x00c0, 0x2ee3, 0x78b3,
+	0x0000, 0x007c, 0x7007, 0x0002, 0x8aff, 0x00c0, 0x2ef1, 0x0078,
+	0x2ef5, 0x1078, 0x3077, 0x00c0, 0x2ef1, 0x78b3, 0x0000, 0x007c,
+	0x7007, 0x0002, 0x1078, 0x2e68, 0x1078, 0x2c16, 0x6814, 0xa084,
+	0x8000, 0x0040, 0x2f05, 0x6817, 0x0002, 0x007c, 0x1078, 0x1b4e,
+	0x1078, 0x1b4e, 0x1078, 0x2f5c, 0x7210, 0x7114, 0x700c, 0xa09c,
+	0x007f, 0x2800, 0xa300, 0xa211, 0xa189, 0x0000, 0x78b0, 0xa005,
+	0x0040, 0x2f1e, 0x78b3, 0x0000, 0x0078, 0x2f41, 0x1078, 0x2f5c,
+	0x2704, 0x2c58, 0xac60, 0x630c, 0x2200, 0xa322, 0x6308, 0x2100,
+	0xa31b, 0x2400, 0xa305, 0x0040, 0x2f37, 0x00c8, 0x2f37, 0x8412,
+	0x8210, 0x830a, 0xa189, 0x0000, 0x2b60, 0x0078, 0x2f1e, 0x2b60,
+	0x8a07, 0xa7ba, 0x2e44, 0xa73d, 0x2c00, 0x6882, 0x6f86, 0x6c8e,
+	0x6b8a, 0x1078, 0x2e68, 0x007c, 0x8738, 0x2704, 0xa005, 0x00c0,
+	0x2f50, 0x6098, 0xa005, 0x0040, 0x2f59, 0x2060, 0x2039, 0x2e44,
+	0x8a51, 0x0040, 0x2f58, 0x7008, 0xa084, 0x00c0, 0xa086, 0x00c0,
+	0x007c, 0x2051, 0x0000, 0x007c, 0x8a50, 0x8739, 0x2704, 0xa004,
+	0x00c0, 0x2f69, 0x2039, 0x2e4a, 0x6000, 0xa064, 0x00c0, 0x2f69,
+	0x2d60, 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x6880,
+	0x2060, 0x6884, 0x6b88, 0x6c8c, 0x8057, 0xaad4, 0x00ff, 0xa084,
+	0x00ff, 0xa0b8, 0x2e44, 0x7e08, 0xa6b5, 0x000c, 0x6818, 0xa084,
+	0x0040, 0x0040, 0x2f85, 0xa6b5, 0x0001, 0x0f7e, 0x2079, 0x0100,
+	0x7858, 0x0f7f, 0xa084, 0x0040, 0x0040, 0x2f94, 0xa684, 0x0001,
+	0x00c0, 0x2f94, 0xa6b5, 0x0001, 0x7007, 0x0004, 0x7004, 0xa084,
+	0x0004, 0x00c0, 0x2f96, 0x7000, 0xa005, 0x0040, 0x2fa1, 0x1078,
+	0x1b4e, 0x2400, 0xa305, 0x00c0, 0x2fa7, 0x0078, 0x2fe4, 0x2c58,
+	0x2704, 0xac60, 0x6004, 0xa400, 0x007e, 0x701a, 0x6000, 0xa301,
+	0x701e, 0x2009, 0x04fd, 0x2104, 0xa086, 0x04fd, 0x007f, 0x00c0,
+	0x2fd4, 0xa084, 0x0001, 0x0040, 0x2fd4, 0xa684, 0x0001, 0x00c0,
+	0x2fd4, 0x7013, 0x0001, 0x7017, 0x0000, 0x7602, 0x7007, 0x0001,
+	0x78b3, 0x0001, 0xa4a0, 0x0001, 0xa399, 0x0000, 0x6004, 0xa400,
+	0x701a, 0x6000, 0xa301, 0x701e, 0x620c, 0x2400, 0xa202, 0x7012,
+	0x6208, 0x2300, 0xa203, 0x7016, 0x7602, 0x7007, 0x0001, 0x2b60,
+	0x1078, 0x2f44, 0x0078, 0x2fe6, 0x1078, 0x3077, 0x00c0, 0x2fe4,
+	0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f,
+	0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x2ff2, 0x7003,
+	0x0008, 0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200,
+	0x0d7f, 0x2049, 0x2ffc, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004,
+	0x00c0, 0x3005, 0x7000, 0xa005, 0x0040, 0x3010, 0x1078, 0x1b4e,
+	0x7e08, 0xa6b5, 0x000c, 0x6818, 0xa084, 0x0040, 0x0040, 0x301a,
+	0xa6b5, 0x0001, 0x6824, 0xa005, 0x0040, 0x3026, 0x2050, 0x2039,
+	0x2e47, 0x2d60, 0x1078, 0x3077, 0x00c0, 0x3022, 0x127f, 0x2000,
+	0x007c, 0x127e, 0x007e, 0x017e, 0x0d7e, 0x2091, 0x2200, 0x0d7f,
+	0x037f, 0x047f, 0x7e08, 0xa6b5, 0x000c, 0x6818, 0xa084, 0x0040,
+	0x0040, 0x303c, 0xa6b5, 0x0001, 0x2049, 0x3029, 0x6824, 0xa055,
+	0x0040, 0x3074, 0x2d70, 0x2e60, 0x2039, 0x2e47, 0x2704, 0xae68,
+	0x680c, 0xa422, 0x6808, 0xa31b, 0x0048, 0x3061, 0x8a51, 0x00c0,
+	0x3053, 0x1078, 0x1b4e, 0x8738, 0x2704, 0xa005, 0x00c0, 0x3047,
+	0x7098, 0xa075, 0x2060, 0x0040, 0x3074, 0x2039, 0x2e44, 0x0078,
+	0x3046, 0x8422, 0x8420, 0x831a, 0xa399, 0x0000, 0x690c, 0x2400,
+	0xa122, 0x6908, 0x2300, 0xa11b, 0x00c8, 0x3070, 0x1078, 0x1b4e,
+	0x2071, 0x0020, 0x0078, 0x2f94, 0x127f, 0x2000, 0x007c, 0x7008,
+	0xa084, 0x00c0, 0xa086, 0x00c0, 0x0040, 0x309f, 0x2704, 0xac08,
+	0x2104, 0x701e, 0x8108, 0x2104, 0x701a, 0x8108, 0x2104, 0x7016,
+	0x8108, 0x2104, 0x7012, 0x0f7e, 0x2079, 0x0100, 0x7858, 0x0f7f,
+	0xa084, 0x0040, 0x0040, 0x309a, 0xa684, 0x0001, 0x00c0, 0x309a,
+	0xa6b5, 0x0001, 0x7602, 0x7007, 0x0001, 0x1078, 0x2f44, 0x007c,
+	0x127e, 0x007e, 0x0d7e, 0x2091, 0x2200, 0x2049, 0x30a0, 0x0d7f,
+	0x087f, 0x7108, 0xa184, 0x00c0, 0x00c0, 0x30b6, 0x6824, 0xa005,
+	0x0040, 0x30c6, 0x1078, 0x2f0c, 0x0078, 0x30c6, 0x7108, 0x8104,
+	0x00c8, 0x30be, 0x1078, 0x2eb6, 0x0078, 0x30a9, 0x7007, 0x0010,
+	0x7108, 0x8104, 0x00c8, 0x30c0, 0x1078, 0x2eb6, 0x7008, 0xa086,
+	0x0002, 0x00c0, 0x30a9, 0x7000, 0xa005, 0x00c0, 0x30a9, 0x2049,
+	0x0000, 0x127f, 0x2000, 0x007c, 0x127e, 0x147e, 0x137e, 0x157e,
+	0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x2049, 0x30d4, 0xad80, 0x0010,
+	0x20a0, 0x2099, 0x0031, 0x700c, 0xa084, 0x007f, 0x6826, 0x7007,
+	0x0008, 0x7007, 0x0002, 0x7003, 0x0001, 0x0040, 0x30f2, 0x8000,
+	0x80ac, 0x53a5, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0,
+	0x30f4, 0x2049, 0x0000, 0x7003, 0x0000, 0x157f, 0x137f, 0x147f,
+	0x127f, 0x2000, 0x007c, 0x127e, 0x007e, 0x0d7e, 0x2091, 0x2200,
+	0x0d7f, 0x2049, 0x3103, 0x6880, 0x2060, 0x6884, 0x6b88, 0x6c8c,
+	0x8057, 0xaad4, 0x00ff, 0xa084, 0x00ff, 0xa0b8, 0x2e44, 0x7e08,
+	0xa6b5, 0x0004, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0,
+	0x311c, 0x2c58, 0x2704, 0xac60, 0x6004, 0xa400, 0x701a, 0x6000,
+	0xa301, 0x701e, 0x7013, 0x0001, 0x7017, 0x0000, 0x7602, 0x7007,
+	0x0001, 0x007f, 0x8007, 0x2009, 0x0031, 0x200a, 0x00a0, 0x3136,
+	0x7108, 0x7007, 0x0002, 0x810c, 0x00c8, 0x3136, 0x810c, 0x0048,
+	0x3143, 0x0078, 0x2ef8, 0xa4a0, 0x0001, 0xa399, 0x0000, 0x6b8a,
+	0x6c8e, 0x7007, 0x0004, 0x2049, 0x0000, 0x7003, 0x0000, 0x127f,
+	0x2000, 0x007c, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e,
+	0x00c8, 0x315b, 0xa200, 0x00f0, 0x3156, 0x8086, 0x818e, 0x007c,
+	0x157e, 0x20a9, 0x0010, 0xa005, 0x0040, 0x3181, 0xa11a, 0x00c8,
+	0x3181, 0x8213, 0x818d, 0x0048, 0x3174, 0xa11a, 0x00c8, 0x3175,
+	0x00f0, 0x3169, 0x0078, 0x3179, 0xa11a, 0x2308, 0x8210, 0x00f0,
+	0x3169, 0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, 0x157f,
+	0x007c, 0x007e, 0x3200, 0xa085, 0x0800, 0x0078, 0x317d, 0x00e0,
+	0x31c1, 0x2091, 0x6000, 0x7820, 0x8001, 0x7822, 0x00c0, 0x31bb,
+	0x7824, 0x7822, 0x2091, 0x8000, 0x2069, 0x3440, 0x6800, 0xa084,
+	0x0007, 0x0040, 0x31ab, 0xa086, 0x0002, 0x0040, 0x31ab, 0x6830,
+	0xa00d, 0x0040, 0x31ab, 0x2104, 0xa005, 0x0040, 0x31ab, 0x8001,
+	0x200a, 0x0040, 0x3277, 0x2061, 0x3580, 0x20a9, 0x0080, 0x6034,
+	0xa005, 0x0040, 0x31b5, 0x8001, 0x6036, 0xace0, 0x0010, 0x0070,
+	0x31bb, 0x0078, 0x31af, 0x1078, 0x31dc, 0x1078, 0x31c4, 0x1078,
+	0x3201, 0x2091, 0x8001, 0x007c, 0x783c, 0x8001, 0x783e, 0x00c0,
+	0x31db, 0x7840, 0x783e, 0x7848, 0xa005, 0x0040, 0x31db, 0x8001,
+	0x784a, 0x00c0, 0x31db, 0x0f7e, 0x2079, 0x0100, 0x1078, 0x2cc6,
+	0x0f7f, 0x1078, 0x19f8, 0x007c, 0x7834, 0x8001, 0x7836, 0x00c0,
+	0x3200, 0x7838, 0x7836, 0x2091, 0x8000, 0x7844, 0xa005, 0x00c0,
+	0x31eb, 0x2001, 0x0101, 0x8001, 0x7846, 0xa080, 0x3d80, 0x2040,
+	0x2004, 0xa065, 0x0040, 0x3200, 0x6020, 0xa005, 0x0040, 0x31fc,
+	0x8001, 0x6022, 0x0040, 0x3230, 0x6000, 0x2c40, 0x0078, 0x31f1,
+	0x007c, 0x7828, 0x8001, 0x782a, 0x00c0, 0x322f, 0x782c, 0x782a,
+	0x7830, 0xa005, 0x00c0, 0x320e, 0x2001, 0x0080, 0x8001, 0x7832,
+	0x8003, 0x8003, 0x8003, 0x8003, 0xa090, 0x3580, 0xa298, 0x0002,
+	0x2304, 0xa084, 0x0008, 0x0040, 0x322f, 0xa290, 0x0009, 0x2204,
+	0xa005, 0x0040, 0x3227, 0x8001, 0x2012, 0x00c0, 0x322f, 0x2304,
+	0xa084, 0xfff7, 0xa085, 0x0080, 0x201a, 0x1078, 0x19f8, 0x007c,
+	0x2069, 0x3440, 0x6800, 0xa005, 0x0040, 0x323a, 0x683c, 0xac06,
+	0x0040, 0x3277, 0x6017, 0x0006, 0x60b0, 0xa084, 0x3f00, 0x601a,
+	0x601c, 0xa084, 0x00ff, 0xa085, 0x0060, 0x601e, 0x6000, 0x2042,
+	0x6710, 0x6fb6, 0x1078, 0x1681, 0x6818, 0xa005, 0x0040, 0x3252,
+	0x8001, 0x681a, 0x6808, 0xa084, 0xffef, 0x680a, 0x6810, 0x8001,
+	0x00d0, 0x325c, 0x1078, 0x1b4e, 0x6812, 0x602f, 0x0000, 0x602b,
+	0x0000, 0x2c68, 0x1078, 0x17be, 0x2069, 0x3440, 0x2001, 0x0006,
+	0x68a2, 0x7944, 0xa184, 0x0100, 0x00c0, 0x3272, 0x69ba, 0x2001,
+	0x0004, 0x68a2, 0x1078, 0x19f3, 0x2091, 0x8001, 0x007c, 0x2009,
+	0x344f, 0x2164, 0x2069, 0x0100, 0x6017, 0x0006, 0x6858, 0xa084,
+	0x3f00, 0x601a, 0x601c, 0xa084, 0x00ff, 0xa085, 0x0048, 0x601e,
+	0x602f, 0x0000, 0x602b, 0x0000, 0x6830, 0xa084, 0x0040, 0x0040,
+	0x32b1, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0004,
+	0x0040, 0x329e, 0x0070, 0x329e, 0x0078, 0x3295, 0x684b, 0x0009,
+	0x20a9, 0x0014, 0x6848, 0xa084, 0x0001, 0x0040, 0x32ab, 0x0070,
+	0x32ab, 0x0078, 0x32a2, 0x20a9, 0x00fa, 0x0070, 0x32b1, 0x0078,
+	0x32ad, 0x6808, 0xa084, 0xfffd, 0x680a, 0x681b, 0x0046, 0x2009,
+	0x3468, 0x200b, 0x0007, 0x784c, 0x784a, 0x2091, 0x8001, 0x007c,
+	0x2079, 0x3400, 0x1078, 0x3309, 0x1078, 0x32d1, 0x1078, 0x32e6,
+	0x1078, 0x32fb, 0x7833, 0x0000, 0x7847, 0x0000, 0x784b, 0x0000,
+	0x007c, 0x2019, 0x000a, 0x2011, 0x3446, 0x2204, 0xa086, 0x0032,
+	0x0040, 0x32e3, 0x2019, 0x000c, 0x2204, 0xa086, 0x003c, 0x0040,
+	0x32e3, 0x2019, 0x0008, 0x7b2a, 0x7b2e, 0x007c, 0x2019, 0x0030,
+	0x2011, 0x3446, 0x2204, 0xa086, 0x0032, 0x0040, 0x32f8, 0x2019,
+	0x0039, 0x2204, 0xa086, 0x003c, 0x0040, 0x32f8, 0x2019, 0x0027,
+	0x7b36, 0x7b3a, 0x007c, 0x2019, 0x000d, 0x2011, 0x3446, 0x2204,
+	0xa086, 0x003c, 0x0040, 0x3306, 0x2019, 0x000a, 0x7b3e, 0x7b42,
+	0x007c, 0x2019, 0x2faf, 0x2011, 0x3446, 0x2204, 0xa086, 0x0032,
+	0x0040, 0x331b, 0x2019, 0x3971, 0x2204, 0xa086, 0x003c, 0x0040,
+	0x331b, 0x2019, 0x2626, 0x7b22, 0x7b26, 0x007c, 0xae5b
+};
+
+unsigned short risc_code_length01 = 0x231f;
diff -u --recursive --new-file v2.1.15/linux/fs/ext2/dir.c linux/fs/ext2/dir.c
--- v2.1.15/linux/fs/ext2/dir.c	Fri Nov 15 23:49:09 1996
+++ linux/fs/ext2/dir.c	Thu Dec 12 19:33:00 1996
@@ -211,7 +211,7 @@
 		offset = 0;
 		brelse (bh);
 	}
-	if (!IS_RDONLY(inode)) {
+	if (DO_UPDATE_ATIME(inode)) {
 		inode->i_atime = CURRENT_TIME;
 		inode->i_dirt = 1;
 	}
diff -u --recursive --new-file v2.1.15/linux/fs/ext2/symlink.c linux/fs/ext2/symlink.c
--- v2.1.15/linux/fs/ext2/symlink.c	Tue Oct 29 19:58:42 1996
+++ linux/fs/ext2/symlink.c	Thu Dec 12 19:33:00 1996
@@ -87,7 +87,7 @@
 		link = bh->b_data;
 	} else
 		link = (char *) inode->u.ext2_i.i_data;
-	if (!IS_RDONLY(inode)) {
+	if (DO_UPDATE_ATIME(inode)) {
 		inode->i_atime = CURRENT_TIME;
 		inode->i_dirt = 1;
 	}
@@ -128,7 +128,7 @@
 		i++;
 		put_user (c, buffer++);
 	}
-	if (!IS_RDONLY(inode)) {
+	if (DO_UPDATE_ATIME(inode)) {
 		inode->i_atime = CURRENT_TIME;
 		inode->i_dirt = 1;
 	}
diff -u --recursive --new-file v2.1.15/linux/fs/locks.c linux/fs/locks.c
--- v2.1.15/linux/fs/locks.c	Tue Oct 29 19:58:43 1996
+++ linux/fs/locks.c	Wed Dec 18 10:41:12 1996
@@ -125,8 +125,6 @@
 			   unsigned int wait);
 static int posix_locks_deadlock(struct task_struct *my_task,
 				struct task_struct *blocked_task);
-static void posix_remove_locks(struct file_lock **before, struct task_struct *task);
-static void flock_remove_locks(struct file_lock **before, struct file *filp);
 
 static struct file_lock *locks_alloc_lock(struct file_lock *fl);
 static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl);
@@ -272,26 +270,24 @@
 		return (error);
 
 	copy_from_user(&flock, l, sizeof(flock));
-	if ((flock.l_type == F_UNLCK) || (flock.l_type == F_EXLCK) ||
-	    (flock.l_type == F_SHLCK))
+	if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
 		return (-EINVAL);
 
 	if (!filp->f_inode || !posix_make_lock(filp, &file_lock, &flock))
 		return (-EINVAL);
 
-	if ((fl = filp->f_inode->i_flock) && (fl->fl_flags & FL_POSIX)) { 
-		while (fl != NULL) {
-			if (posix_locks_conflict(&file_lock, fl)) {
-				flock.l_pid = fl->fl_owner->pid;
-				flock.l_start = fl->fl_start;
-				flock.l_len = fl->fl_end == OFFSET_MAX ? 0 :
-					fl->fl_end - fl->fl_start + 1;
-				flock.l_whence = 0;
-				flock.l_type = fl->fl_type;
-				copy_to_user(l, &flock, sizeof(flock));
-				return (0);
-			}
-			fl = fl->fl_next;
+	for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {
+		if (!(fl->fl_flags & FL_POSIX))
+			continue;
+		if (posix_locks_conflict(&file_lock, fl)) {
+			flock.l_pid = fl->fl_owner->pid;
+			flock.l_start = fl->fl_start;
+			flock.l_len = fl->fl_end == OFFSET_MAX ? 0 :
+				fl->fl_end - fl->fl_start + 1;
+			flock.l_whence = 0;
+			flock.l_type = fl->fl_type;
+			copy_to_user(l, &flock, sizeof(flock));
+			return (0);
 		}
 	}
 
@@ -302,8 +298,6 @@
 
 /* Apply the lock described by l to an open file descriptor.
  * This implements both the F_SETLK and F_SETLKW commands of fcntl().
- * It also emulates flock() in a pretty broken way for older C
- * libraries.
  */
 int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
 {
@@ -345,35 +339,23 @@
 		return (-EINVAL);
 	
 	switch (flock.l_type) {
-	case F_RDLCK :
+	case F_RDLCK:
 		if (!(filp->f_mode & 1))
 			return (-EBADF);
 		break;
-	case F_WRLCK :
+	case F_WRLCK:
 		if (!(filp->f_mode & 2))
 			return (-EBADF);
 		break;
-	case F_SHLCK :
-	case F_EXLCK :
-#if 1
-/* warn a bit for now, but don't overdo it */
-{
-	static int count = 0;
-	if (!count) {
-		count=1;
+	case F_UNLCK:
+		break;
+	case F_SHLCK:
+	case F_EXLCK:
 		printk(KERN_WARNING
-		       "fcntl_setlk() called by process %d (%s) with broken flock() emulation\n",
+		       "fcntl_setlk(): process %d (%s) requested broken flock() emulation\n",
 		       current->pid, current->comm);
-	}
-}
-#endif
-		if (!(filp->f_mode & 3))
-			return (-EBADF);
-		break;
-	case F_UNLCK :
-		break;
 	default:
-		return -EINVAL;
+		return (-EINVAL);
 	}
 	
 	return (posix_lock_file(filp, &file_lock, cmd == F_SETLKW));
@@ -384,41 +366,18 @@
 void locks_remove_locks(struct task_struct *task, struct file *filp)
 {
 	struct file_lock *fl;
+	struct file_lock **before;
 
 	/* For POSIX locks we free all locks on this file for the given task.
 	 * For FLOCK we only free locks on this *open* file if it is the last
 	 * close on that file.
 	 */
-	if ((fl = filp->f_inode->i_flock) != NULL) {
-		if (fl->fl_flags & FL_POSIX)
-			posix_remove_locks(&filp->f_inode->i_flock, task);
-		else
-			flock_remove_locks(&filp->f_inode->i_flock, filp);
-	}
-
-	return;
-}
-
-static void posix_remove_locks(struct file_lock **before, struct task_struct *task)
-{
-	struct file_lock *fl;
-
-	while ((fl = *before) != NULL) {
-		if (fl->fl_owner == task)
-			locks_delete_lock(before, 0);
-		else
-			before = &fl->fl_next;
-	}
-
-	return;
-}
-
-static void flock_remove_locks(struct file_lock **before, struct file *filp)
-{
-	struct file_lock *fl;
+	before = &filp->f_inode->i_flock;
 
 	while ((fl = *before) != NULL) {
-		if ((fl->fl_file == filp) && (filp->f_count == 1))
+		if (((fl->fl_flags & FL_POSIX) && (fl->fl_owner == task)) ||
+		    ((fl->fl_flags & FL_FLOCK) && (fl->fl_file == filp) &&
+		     (filp->f_count == 1)))
 			locks_delete_lock(before, 0);
 		else
 			before = &fl->fl_next;
@@ -457,13 +416,11 @@
 
 	/* Search the lock list for this inode for any POSIX locks.
 	 */
-	if ((fl = inode->i_flock) == NULL || (fl->fl_flags & FL_FLOCK))
-		return (0);
-	
-	while (fl != NULL) {
+	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
+		if (!(fl->fl_flags & FL_POSIX))
+			continue;
 		if (fl->fl_owner != current)
 			return (-EAGAIN);
-		fl = fl->fl_next;
 	}
 	return (0);
 }
@@ -475,29 +432,22 @@
 	struct file_lock *fl;
 	struct file_lock tfl;
 
+	memset(&tfl, 0, sizeof(tfl));
+
 	tfl.fl_file = filp;
-	tfl.fl_nextlink = NULL;
-	tfl.fl_prevlink = NULL;
-	tfl.fl_next = NULL;
-	tfl.fl_nextblock = NULL;
-	tfl.fl_prevblock = NULL;
 	tfl.fl_flags = FL_POSIX | FL_ACCESS;
 	tfl.fl_owner = current;
-	tfl.fl_wait = NULL;
 	tfl.fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK;
 	tfl.fl_start = offset;
 	tfl.fl_end = offset + count - 1;
 
 repeat:
-	/* Check that there are locks, and that they're not FL_FLOCK locks.
-	 */
-	if ((fl = inode->i_flock) == NULL || (fl->fl_flags & FL_FLOCK))
-		return (0);
-	
 	/* Search the lock list for this inode for locks that conflict with
 	 * the proposed read/write.
 	 */
-	while (fl != NULL) {
+	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
+		if (!(fl->fl_flags & FL_POSIX))
+			continue;
 		/* Block for writes against a "read" lock,
 		 * and both reads and writes against a "write" lock.
 		 */
@@ -522,7 +472,6 @@
 				break;
 			goto repeat;
 		}
-		fl = fl->fl_next;
 	}
 	return (0);
 }
@@ -535,37 +484,31 @@
 {
 	off_t start;
 
+	memset(fl, 0, sizeof(*fl));
+	
 	fl->fl_flags = FL_POSIX;
 
 	switch (l->l_type) {
-	case F_RDLCK :
-	case F_WRLCK :
-	case F_UNLCK :
+	case F_RDLCK:
+	case F_WRLCK:
+	case F_UNLCK:
 		fl->fl_type = l->l_type;
 		break;
-	case F_SHLCK :
-		fl->fl_type = F_RDLCK;
-		fl->fl_flags |= FL_BROKEN;
-		break;
-	case F_EXLCK :
-		fl->fl_type = F_WRLCK;
-		fl->fl_flags |= FL_BROKEN;
-		break;
-	default :
+	default:
 		return (0);
 	}
 
 	switch (l->l_whence) {
-	case 0 : /*SEEK_SET*/
+	case 0: /*SEEK_SET*/
 		start = 0;
 		break;
-	case 1 : /*SEEK_CUR*/
+	case 1: /*SEEK_CUR*/
 		start = filp->f_pos;
 		break;
-	case 2 : /*SEEK_END*/
+	case 2: /*SEEK_END*/
 		start = filp->f_inode->i_size;
 		break;
-	default :
+	default:
 		return (0);
 	}
 
@@ -577,7 +520,6 @@
 	
 	fl->fl_file = filp;
 	fl->fl_owner = current;
-	fl->fl_wait = NULL;		/* just for cleanliness */
 
 	return (1);
 }
@@ -588,20 +530,22 @@
 static int flock_make_lock(struct file *filp, struct file_lock *fl,
 			   unsigned int cmd)
 {
+	memset(fl, 0, sizeof(*fl));
+
 	if (!filp->f_inode)	/* just in case */
 		return (0);
 
 	switch (cmd & ~LOCK_NB) {
-	case LOCK_SH :
+	case LOCK_SH:
 		fl->fl_type = F_RDLCK;
 		break;
-	case LOCK_EX :
+	case LOCK_EX:
 		fl->fl_type = F_WRLCK;
 		break;
-	case LOCK_UN :
+	case LOCK_UN:
 		fl->fl_type = F_UNLCK;
 		break;
-	default :
+	default:
 		return (0);
 	}
 
@@ -610,7 +554,6 @@
 	fl->fl_end = OFFSET_MAX;
 	fl->fl_file = filp;
 	fl->fl_owner = NULL;
-	fl->fl_wait = NULL;		/* just for cleanliness */
 	
 	return (1);
 }
@@ -623,7 +566,8 @@
 	/* POSIX locks owned by the same process do not conflict with
 	 * each other.
 	 */
-	if (caller_fl->fl_owner == sys_fl->fl_owner)
+	if (!(sys_fl->fl_flags & FL_POSIX) ||
+	    (caller_fl->fl_owner == sys_fl->fl_owner))
 		return (0);
 
 	return (locks_conflict(caller_fl, sys_fl));
@@ -637,7 +581,8 @@
 	/* FLOCK locks referring to the same filp do not conflict with
 	 * each other.
 	 */
-	if (caller_fl->fl_file == sys_fl->fl_file)
+	if (!(sys_fl->fl_flags & FL_FLOCK) ||
+	    (caller_fl->fl_file == sys_fl->fl_file))
 		return (0);
 
 	return (locks_conflict(caller_fl, sys_fl));
@@ -652,10 +597,10 @@
 		return (0);
 
 	switch (caller_fl->fl_type) {
-	case F_RDLCK :
+	case F_RDLCK:
 		return (sys_fl->fl_type == F_WRLCK);
 		
-	case F_WRLCK :
+	case F_WRLCK:
 		return (1);
 
 	default:
@@ -701,8 +646,9 @@
 	return (0);
 }
 
-/* Try to create a FLOCK lock on filp. We always insert new locks at
- * the head of the list.
+/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks at
+ * the head of the list, but that's secret knowledge known only to the next
+ * two functions.
  */
 static int flock_lock_file(struct file *filp, struct file_lock *caller,
 			   unsigned int wait)
@@ -713,11 +659,7 @@
 	int change = 0;
 
 	before = &filp->f_inode->i_flock;
-
-	if ((fl = *before) && (fl->fl_flags & FL_POSIX))
-		return (-EBUSY);
-
-	while ((fl = *before) != NULL) {
+	while (((fl = *before) != NULL) && (fl->fl_flags & FL_FLOCK)) {
 		if (caller->fl_file == fl->fl_file) {
 			if (caller->fl_type == fl->fl_type)
 				return (0);
@@ -736,39 +678,34 @@
 	if ((new_fl = locks_alloc_lock(caller)) == NULL)
 		return (-ENOLCK);
 repeat:
-	if ((fl = filp->f_inode->i_flock) && (fl->fl_flags & FL_POSIX)) {
-		locks_free_lock(new_fl);
-		return (-EBUSY);
-	}
-
-	while (fl != NULL) {
-		if (flock_locks_conflict(new_fl, fl)) {
-			if (!wait) {
-				locks_free_lock(new_fl);
-				return (-EAGAIN);
-			}
-			if (current->signal & ~current->blocked) {
-				/* Note: new_fl is not in any queue at this
-				 * point, so we must use locks_free_lock()
-				 * instead of locks_delete_lock()
-				 * 	Dmitry Gorodchanin 09/02/96.
-				 */
-				locks_free_lock(new_fl);
-				return (-ERESTARTSYS);
-			}
-			locks_insert_block(fl, new_fl);
-			interruptible_sleep_on(&new_fl->fl_wait);
-			locks_delete_block(fl, new_fl);
-			if (current->signal & ~current->blocked) {
-				/* Awakened by a signal. Free the new
-				 * lock and return an error.
-				 */
-				locks_free_lock(new_fl);
-				return (-ERESTARTSYS);
-			}
-			goto repeat;
+	for (fl = filp->f_inode->i_flock; (fl != NULL) && (fl->fl_flags & FL_FLOCK);
+	     fl = fl->fl_next) {
+		if (!flock_locks_conflict(new_fl, fl))
+			continue;
+		if (!wait) {
+			locks_free_lock(new_fl);
+			return (-EAGAIN);
+		}
+		if (current->signal & ~current->blocked) {
+			/* Note: new_fl is not in any queue at this
+			 * point, so we must use locks_free_lock()
+			 * instead of locks_delete_lock()
+			 * 	Dmitry Gorodchanin 09/02/96.
+			 */
+			locks_free_lock(new_fl);
+			return (-ERESTARTSYS);
 		}
-		fl = fl->fl_next;
+		locks_insert_block(fl, new_fl);
+		interruptible_sleep_on(&new_fl->fl_wait);
+		locks_delete_block(fl, new_fl);
+		if (current->signal & ~current->blocked) {
+			/* Awakened by a signal. Free the new
+			 * lock and return an error.
+			 */
+			locks_free_lock(new_fl);
+			return (-ERESTARTSYS);
+		}
+		goto repeat;
 	}
 	locks_insert_lock(&filp->f_inode->i_flock, new_fl);
 	return (0);
@@ -796,27 +733,25 @@
 	struct file_lock **before;
 	int added = 0;
 
-repeat:
-	if ((fl = filp->f_inode->i_flock) && (fl->fl_flags & FL_FLOCK))
-		return (-EBUSY);
-
 	if (caller->fl_type != F_UNLCK) {
-		while (fl != NULL) {
-			if (posix_locks_conflict(caller, fl)) {
-				if (!wait)
-					return (-EAGAIN);
-				if (current->signal & ~current->blocked)
-					return (-ERESTARTSYS);
-				if (posix_locks_deadlock(caller->fl_owner, fl->fl_owner))
-					return (-EDEADLK);
-				locks_insert_block(fl, caller);
-				interruptible_sleep_on(&caller->fl_wait);
-				locks_delete_block(fl, caller);
-				if (current->signal & ~current->blocked)
-					return (-ERESTARTSYS);
-				goto repeat;
-			}
-			fl = fl->fl_next;
+  repeat:
+		for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {
+			if (!(fl->fl_flags & FL_POSIX))
+				continue;
+			if (!posix_locks_conflict(caller, fl))
+				continue;
+			if (!wait)
+				return (-EAGAIN);
+			if (current->signal & ~current->blocked)
+				return (-ERESTARTSYS);
+			if (posix_locks_deadlock(caller->fl_owner, fl->fl_owner))
+				return (-EDEADLK);
+			locks_insert_block(fl, caller);
+			interruptible_sleep_on(&caller->fl_wait);
+			locks_delete_block(fl, caller);
+			if (current->signal & ~current->blocked)
+				return (-ERESTARTSYS);
+			goto repeat;
   		}
   	}
 
@@ -827,7 +762,8 @@
 
 	/* First skip locks owned by other processes.
 	 */
-	while ((fl = *before) && (caller->fl_owner != fl->fl_owner)) {
+	while ((fl = *before) && (!(fl->fl_flags & FL_POSIX) ||
+				  (caller->fl_owner != fl->fl_owner))) {
 		before = &fl->fl_next;
 	}
 
@@ -954,15 +890,11 @@
 					       GFP_ATOMIC)) == NULL)
 		return (tmp);
 
-	tmp->fl_nextlink = NULL;
-	tmp->fl_prevlink = NULL;
-	tmp->fl_next = NULL;
-	tmp->fl_nextblock = NULL;
-	tmp->fl_prevblock = NULL;
+	memset(tmp, 0, sizeof(*tmp));
+
 	tmp->fl_flags = fl->fl_flags;
 	tmp->fl_owner = fl->fl_owner;
 	tmp->fl_file = fl->fl_file;
-	tmp->fl_wait = NULL;
 	tmp->fl_type = fl->fl_type;
 	tmp->fl_start = fl->fl_start;
 	tmp->fl_end = fl->fl_end;
@@ -1027,8 +959,7 @@
 	p += sprintf(p, "%d:%s ", id, pfx);
 	if (fl->fl_flags & FL_POSIX) {
 		p += sprintf(p, "%s %s ",
-			     (fl->fl_flags & FL_ACCESS) ? "ACCESS" :
-			     ((fl->fl_flags & FL_BROKEN) ? "BROKEN" : "POSIX "),
+			     (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX",
 			     (IS_MANDLOCK(inode) &&
 			      (inode->i_mode & (S_IXGRP | S_ISGID)) == S_ISGID) ?
 			     "MANDATORY" : "ADVISORY ");
@@ -1063,6 +994,6 @@
 			p = lock_get_status(bfl, p, i, " ->");
 		} while ((bfl = bfl->fl_nextblock) != fl);
 	}
-	return  (p - buf);
+	return (p - buf);
 }
 
diff -u --recursive --new-file v2.1.15/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v2.1.15/linux/fs/ncpfs/inode.c	Tue Oct 29 19:58:43 1996
+++ linux/fs/ncpfs/inode.c	Mon Dec 16 14:36:16 1996
@@ -245,6 +245,12 @@
 	server->conn_status = 0;
 
         server->m = *data;
+	/* Althought anything producing this is buggy, it happens
+	   now because of PATH_MAX changes.. */
+	if (server->m.time_out < 10) {
+		server->m.time_out = 10;
+		printk("You need to recompile your ncpfs utils..\n");
+	}
 	server->m.file_mode = (server->m.file_mode &
 			       (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG;
 	server->m.dir_mode  = (server->m.dir_mode &
diff -u --recursive --new-file v2.1.15/linux/fs/nfs/bio.c linux/fs/nfs/bio.c
--- v2.1.15/linux/fs/nfs/bio.c	Tue Oct 29 19:58:43 1996
+++ linux/fs/nfs/bio.c	Sat Dec 14 13:33:17 1996
@@ -210,6 +210,9 @@
 	unsigned long	address;
 	int		error = -1;
 
+	/* In case we're called from a page fault we want to */
+	/* make sure we're runnable before we schedule.. */
+	current->state = TASK_RUNNING;
 	dprintk("NFS: nfs_readpage %08lx\n", page_address(page));
 	address = page_address(page);
 	page->count++;
diff -u --recursive --new-file v2.1.15/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c
--- v2.1.15/linux/fs/nfs/nfsroot.c	Fri Nov 22 18:28:20 1996
+++ linux/fs/nfs/nfsroot.c	Fri Dec 13 11:24:44 1996
@@ -85,10 +85,12 @@
 #include <linux/skbuff.h>
 #include <linux/socket.h>
 #include <linux/route.h>
+#include <linux/ip.h>
 #include <linux/nfs.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
 #include <linux/in.h>
+#include <linux/netlink.h>
 #include <net/route.h>
 #include <net/sock.h>
 
@@ -152,7 +154,10 @@
 /* Yes, we use sys_socket, but there's no include file for it */
 extern asmlinkage int sys_socket(int family, int type, int protocol);
 
-
+extern void fib_lock(void);
+extern void fib_unlock(void);
+extern int rtmsg_process(struct nlmsghdr *n, struct in_rtmsg *r);
+extern unsigned long ip_get_mask(unsigned long addr);
 
 /***************************************************************************
 
@@ -462,17 +467,21 @@
  */
 static int root_add_bootp_route(void)
 {
-	struct rtentry route;
-
-	memset(&route, 0, sizeof(route));
-	route.rt_dev = bootp_dev->name;
-	route.rt_mss = bootp_dev->mtu;
-	route.rt_flags = RTF_UP;
-	((struct sockaddr_in *) &(route.rt_dst)) -> sin_addr.s_addr = 0;
-	((struct sockaddr_in *) &(route.rt_dst)) -> sin_family = AF_INET;
-	((struct sockaddr_in *) &(route.rt_genmask)) -> sin_addr.s_addr = 0;
-	((struct sockaddr_in *) &(route.rt_genmask)) -> sin_family = AF_INET;
-	if (ip_rt_new(&route)) {
+	struct nlmsghdr dummy_nlh;
+	struct in_rtmsg rtm;
+	int err;
+
+	memset(&rtm, 0, sizeof(struct in_rtmsg));
+	dummy_nlh.nlmsg_seq = 0;
+	dummy_nlh.nlmsg_pid = current->pid;
+	dummy_nlh.nlmsg_type = RTMSG_NEWROUTE;
+	memcpy(&rtm.rtmsg_device, bootp_dev->name, 15);
+	rtm.rtmsg_mtu = bootp_dev->mtu;
+	rtm.rtmsg_flags = RTF_UP;
+	fib_lock();
+	err = rtmsg_process(&dummy_nlh, &rtm);
+	fib_unlock();
+	if (err) {
 		printk(KERN_ERR "BOOTP: Adding of route failed!\n");
 		return -1;
 	}
@@ -486,14 +495,20 @@
  */
 static int root_del_bootp_route(void)
 {
-	struct rtentry route;
+	struct nlmsghdr dummy_nlh;
+	struct in_rtmsg rtm;
+	int err;
 
 	if (!bootp_have_route)
 		return 0;
-	memset(&route, 0, sizeof(route));
-	((struct sockaddr_in *) &(route.rt_dst)) -> sin_addr.s_addr = 0;
-	((struct sockaddr_in *) &(route.rt_genmask)) -> sin_addr.s_addr = 0;
-	if (ip_rt_kill(&route)) {
+	memset(&rtm, 0, sizeof(struct in_rtmsg));
+	dummy_nlh.nlmsg_seq = 0;
+	dummy_nlh.nlmsg_pid = current->pid;
+	dummy_nlh.nlmsg_type = RTMSG_DELROUTE;
+	fib_lock();
+	err = rtmsg_process(&dummy_nlh, &rtm);
+	fib_unlock();
+	if (err) {
 		printk(KERN_ERR "BOOTP: Deleting of route failed!\n");
 		return -1;
 	}
@@ -581,7 +596,7 @@
 	msg.msg_iov = &iov;
 	msg.msg_iovlen = 1;
 	msg.msg_control = NULL;
-	result = sock->ops->sendmsg(sock, &msg, size, 0, 0);
+	result = sock_sendmsg(sock, &msg, size);
 	set_fs(oldfs);
 	return (result != size);
 }
@@ -606,7 +621,7 @@
 	msg.msg_iovlen = 1;
 	msg.msg_control = NULL;
 	msg.msg_namelen = 0;
-	result = sock->ops->recvmsg(sock, &msg, size, O_NONBLOCK, 0, &msg.msg_namelen);
+	result = sock_recvmsg(sock, &msg, size, MSG_DONTWAIT);
 	set_fs(oldfs);
 	return result;
 }
@@ -721,9 +736,9 @@
 		return -1;
 
 	/* Bind/connect the sockets */
-	((struct sock *) bootp_xmit_sock->data) -> broadcast = 1;
-	((struct sock *) bootp_xmit_sock->data) -> reuse = 1;
-	((struct sock *) bootp_recv_sock->data) -> reuse = 1;
+	bootp_xmit_sock->sk->broadcast = 1;
+	bootp_xmit_sock->sk->reuse = 1;
+	bootp_recv_sock->sk->reuse = 1;
 	if (root_bind_udp_sock(bootp_recv_sock, INADDR_ANY, 68) ||
 	    root_bind_udp_sock(bootp_xmit_sock, INADDR_ANY, 68) ||
 	    root_connect_udp_sock(bootp_xmit_sock, INADDR_BROADCAST, 67))
@@ -1277,7 +1292,9 @@
  */
 static int root_nfs_setup(void)
 {
-	struct rtentry route;
+	struct in_rtmsg rtm;
+	struct nlmsghdr dummy_nlh;
+	int err;
 
 	/* Set the default system name in case none was previously found */
 	if (!system_utsname.nodename[0]) {
@@ -1304,28 +1321,37 @@
 	 * gatewayed default route. Note that this gives sufficient network
 	 * setup even for full system operation in all common cases.
 	 */
-	memset(&route, 0, sizeof(route));	/* Local subnet route */
-	route.rt_dev = root_dev->name;
-	route.rt_mss = root_dev->mtu;
-	route.rt_flags = RTF_UP;
-	*((struct sockaddr_in *) &(route.rt_dst)) = myaddr;
-	(((struct sockaddr_in *) &(route.rt_dst)))->sin_addr.s_addr &= netmask.sin_addr.s_addr;
-	*((struct sockaddr_in *) &(route.rt_genmask)) = netmask;
-	if (ip_rt_new(&route)) {
+	dummy_nlh.nlmsg_seq = 0;
+	dummy_nlh.nlmsg_pid = current->pid;
+	dummy_nlh.nlmsg_type = RTMSG_NEWROUTE;
+
+	memset(&rtm, 0, sizeof(struct in_rtmsg));	/* Local subnet route */
+	memcpy(&rtm.rtmsg_device, root_dev->name, 15);
+	rtm.rtmsg_mtu = root_dev->mtu;
+	rtm.rtmsg_flags = RTF_UP;
+	rtm.rtmsg_prefixlen = (32 - ffz(~(netmask.sin_addr.s_addr)));
+	rtm.rtmsg_prefix = myaddr.sin_addr;
+	fib_lock();
+	err = rtmsg_process(&dummy_nlh, &rtm);
+	fib_unlock();
+	if (err) {
 		printk(KERN_ERR "Root-NFS: Adding of local route failed!\n");
 		return -1;
 	}
 
 	if (gateway.sin_addr.s_addr != INADDR_NONE) {	/* Default route */
-		(((struct sockaddr_in *) &(route.rt_dst)))->sin_addr.s_addr = INADDR_ANY;
-		(((struct sockaddr_in *) &(route.rt_genmask)))->sin_addr.s_addr = INADDR_ANY;
-		*((struct sockaddr_in *) &(route.rt_gateway)) = gateway;
-		route.rt_flags |= RTF_GATEWAY;
+		rtm.rtmsg_prefix.s_addr = INADDR_ANY;
+		rtm.rtmsg_prefixlen = 32;
+		rtm.rtmsg_gateway = gateway.sin_addr;
+		rtm.rtmsg_flags |= RTF_GATEWAY;
 		if ((gateway.sin_addr.s_addr ^ myaddr.sin_addr.s_addr) & netmask.sin_addr.s_addr) {
 			printk(KERN_ERR "Root-NFS: Gateway not on local network!\n");
 			return -1;
 		}
-		if (ip_rt_new(&route)) {
+		fib_lock();
+		err = rtmsg_process(&dummy_nlh, &rtm);
+		fib_unlock();
+		if (err) {
 			printk(KERN_ERR "Root-NFS: Adding of default route failed!\n");
 			return -1;
 		}
diff -u --recursive --new-file v2.1.15/linux/fs/proc/openpromfs.c linux/fs/proc/openpromfs.c
--- v2.1.15/linux/fs/proc/openpromfs.c	Thu Jan  1 02:00:00 1970
+++ linux/fs/proc/openpromfs.c	Fri Dec 13 16:00:11 1996
@@ -0,0 +1,1080 @@
+/* $Id: openpromfs.c,v 1.8 1996/12/02 16:04:42 ecd Exp $
+ * openpromfs.c: /proc/openprom handling routines
+ *
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/uaccess.h>
+
+#define ALIASES_NNODES 64
+
+typedef struct {
+	u16	parent;
+	u16	next;
+	u16	child;
+	u16	first_prop;
+	u32	node;
+} openpromfs_node;
+
+typedef struct {
+#define OPP_STRING	0x10
+#define OPP_BINARY	0x20
+#define OPP_DIRTY	0x01
+#define OPP_QUOTED	0x02
+#define OPP_NOTQUOTED	0x04
+#define OPP_ASCIIZ	0x08
+	u32	flag;
+	u32	alloclen;
+	u32	len;
+	char	*value;
+	char	name[8];
+} openprom_property;
+
+static openpromfs_node *nodes = NULL;
+static int alloced = 0;
+static u16 last_node = 0;
+static u16 first_prop = 0;
+static u16 options = 0xffff;
+static u16 aliases = 0xffff;
+static int aliases_nodes = 0;
+static char *alias_names [ALIASES_NNODES];
+static struct inode_operations *proc_openprom_iops = 0;
+static struct openpromfs_dev **devices;
+
+#define NODE(ino) nodes[ino - PROC_OPENPROM_FIRST]
+#define NODE2INO(node) (node + PROC_OPENPROM_FIRST)
+#define NODEP2INO(no) (no + PROC_OPENPROM_FIRST + last_node)
+
+static int openpromfs_create (struct inode *, const char *, int, int,
+			      struct inode **);
+static int openpromfs_readdir(struct inode *, struct file *, void *, filldir_t);
+static int openpromfs_lookup(struct inode *, const char *, int,
+			     struct inode **);
+static int openpromfs_unlink (struct inode *, const char *, int);
+
+static long nodenum_read(struct inode *inode, struct file *file,
+			 char *buf, unsigned long count)
+{
+	char buffer[10];
+	
+	if (count < 0 || !inode->u.generic_ip)
+		return -EINVAL;
+	sprintf (buffer, "%8.8x\n", (u32)(inode->u.generic_ip));
+	if (file->f_pos >= 9)
+		return 0;
+	if (count > 9 - file->f_pos)
+		count = 9 - file->f_pos;
+	copy_to_user(buf, buffer + file->f_pos, count);
+	file->f_pos += count;
+	return count;
+}
+
+static long property_read(struct inode *inode, struct file *filp,
+			  char *buf, unsigned long count)
+{
+	int i, j, k;
+	u32 node;
+	char *p;
+	u32 *q;
+	openprom_property *op;
+	
+	if (filp->f_pos >= 0xffffff)
+		return -EINVAL;
+	if (!filp->private_data) {
+		node = nodes[(u16)((uint)inode->u.generic_ip)].node;
+		i = ((u32)inode->u.generic_ip) >> 16;
+		if ((u16)((uint)inode->u.generic_ip) == aliases) {
+			if (i >= aliases_nodes)
+				p = 0;
+			else
+				p = alias_names [i];
+		} else
+			for (p = prom_firstprop (node);
+			     i && p && *p;
+			     p = prom_nextprop (node, p), i--)
+				/* nothing */ ;
+		if (!p || !*p)
+			return -EIO;
+		i = prom_getproplen (node, p);
+		if (i < 0) {
+			if ((u16)((uint)inode->u.generic_ip) == aliases)
+				i = 0;
+			else
+				return -EIO;
+		}
+		k = i;
+		if (i < 64) i = 64;
+		filp->private_data = kmalloc (sizeof (openprom_property)
+					      + (j = strlen (p)) + 2 * i,
+					      GFP_KERNEL);
+		if (!filp->private_data)
+			return -ENOMEM;
+		op = (openprom_property *)filp->private_data;
+		op->flag = 0;
+		op->alloclen = 2 * i;
+		strcpy (op->name, p);
+		op->value = (char *)(((unsigned long)(op->name + j + 4)) & ~3);
+		op->len = k;
+		if (k && prom_getproperty (node, p, op->value, i) < 0)
+			return -EIO;
+		op->value [k] = 0;
+		if (k) {
+			for (p = op->value; *p >= ' ' && *p <= '~'; p++);
+			if (p >= op->value + k - 1 && !*p) {
+				op->flag |= OPP_STRING;
+				if (p == op->value + k - 1) {
+					op->flag |= OPP_ASCIIZ;
+					op->len--;
+				}
+			} else if (!(k & 3))
+				op->flag |= OPP_BINARY;
+			else {
+				printk ("/proc/openprom: Strange property "
+					"size %d\n", i);
+				return -EIO;
+			}
+		}
+	} else
+		op = (openprom_property *)filp->private_data;
+	if (!count || !op->len) return 0;
+	if (op->flag & OPP_STRING)
+		i = op->len + 3;
+	else
+		i = (op->len * 9)>>2;
+	k = filp->f_pos;
+	if (k >= i) return 0;
+	if (count > i - k) count = i - k;
+	if (op->flag & OPP_STRING) {
+		if (!k) {
+			*buf = '\'';
+			k++;
+			count--;
+		}
+		if (k + count >= i - 2)
+			j = i - 2 - k;
+		else
+			j = count;
+		if (j >= 0) {
+			copy_to_user(buf + k - filp->f_pos,
+				     op->value + k - 1, j);
+			count -= j;
+			k += j;
+		}
+		if (count)
+			buf [k++ - filp->f_pos] = '\'';
+		if (count > 1)
+			buf [k++ - filp->f_pos] = '\n';
+	} else if (op->flag & OPP_BINARY) {
+		char buffer[10];
+		u32 *first, *last;
+		int first_off, last_cnt;
+
+		first = ((u32 *)op->value) + k / 9;
+		first_off = k % 9;
+		last = ((u32 *)op->value) + (k + count - 1) / 9;
+		last_cnt = (k + count) % 9;
+		if (!last_cnt) last_cnt = 9;
+
+		if (first == last) {
+			sprintf (buffer, "%08x.", *first);
+			memcpy (buf, buffer + first_off, last_cnt - first_off);
+			buf += last_cnt - first_off;
+		} else {		
+			for (q = first; q <= last; q++) {
+				sprintf (buffer, "%08x.", *q);
+				if (q == first) {
+					memcpy (buf, buffer + first_off,
+						9 - first_off);
+					buf += 9 - first_off;
+				} else if (q == last) {
+					memcpy (buf, buffer, last_cnt);
+					buf += last_cnt;
+				} else {
+					memcpy (buf, buffer, 9);
+					buf += 9;
+				}
+			}
+		}
+		if (last == (u32 *)(op->value + op->len - 4) && last_cnt == 9)
+			*(buf - 1) = '\n';
+		k += count;
+	}
+	count = k - filp->f_pos;
+	filp->f_pos = k;
+	return count;
+}
+
+static long property_write(struct inode *inode, struct file *filp,
+			   const char *buf, unsigned long count)
+{
+	int i, j, k;
+	char *p;
+	u32 *q;
+	void *b;
+	openprom_property *op;
+	
+	if (filp->f_pos >= 0xffffff)
+		return -EINVAL;
+	if (!filp->private_data) {
+		i = property_read (inode, filp, NULL, 0);
+		if (i)
+			return i;
+	}
+	k = filp->f_pos;
+	op = (openprom_property *)filp->private_data;
+	if (!(op->flag & OPP_STRING)) {
+		u32 *first, *last;
+		int first_off, last_cnt;
+		u32 mask, mask2;
+		char tmp [9];
+		int forcelen = 0;
+		
+		j = k % 9;
+		for (i = 0; i < count; i++, j++) {
+			if (j == 9) j = 0;
+			if (!j) {
+				if (buf [i] != '.') {
+					if (buf [i] != '\n') {
+						if (op->flag & OPP_BINARY)
+							return -EINVAL;
+						else
+							goto write_try_string;
+					} else {
+						count = i + 1;
+						forcelen = 1;
+						break;
+					}
+				}
+			} else {
+				if (buf [i] < '0' || 
+				    (buf [i] > '9' && buf [i] < 'A') ||
+				    (buf [i] > 'F' && buf [i] < 'a') ||
+				    buf [i] > 'f') {
+					if (op->flag & OPP_BINARY)
+						return -EINVAL;
+					else
+						goto write_try_string;
+				}
+			}
+		}
+		op->flag |= OPP_BINARY;
+		tmp [8] = 0;
+		i = ((count + k + 8) / 9) << 2;
+		if (op->alloclen <= i) {
+			b = kmalloc (sizeof (openprom_property) + 2 * i,
+				     GFP_KERNEL);
+			if (!b)
+				return -ENOMEM;
+			memcpy (b, filp->private_data,
+				sizeof (openprom_property)
+				+ strlen (op->name) + op->alloclen);
+			memset (((char *)b) + sizeof (openprom_property)
+				+ strlen (op->name) + op->alloclen, 
+				0, 2 * i - op->alloclen);
+			op = (openprom_property *)b;
+			op->alloclen = 2*i;
+			b = filp->private_data;
+			filp->private_data = (void *)op;
+			kfree (b);
+		}
+		first = ((u32 *)op->value) + (k / 9);
+		first_off = k % 9;
+		last = (u32 *)(op->value + i);
+		last_cnt = (k + count) % 9;
+		if (first + 1 == last) {
+			memset (tmp, '0', 8);
+			memcpy (tmp + first_off, buf, (count + first_off > 8) ?
+						      8 - first_off : count);
+			mask = 0xffffffff;
+			mask2 = 0xffffffff;
+			for (j = 0; j < first_off; j++)
+				mask >>= 1;
+			for (j = 8 - count - first_off; j > 0; j--)
+				mask2 <<= 1;
+			mask &= mask2;
+			if (mask) {
+				*first &= ~mask;
+				*first |= simple_strtoul (tmp, 0, 16);
+				op->flag |= OPP_DIRTY;
+			}
+		} else {
+			op->flag |= OPP_DIRTY;
+			for (q = first; q < last; q++) {
+				if (q == first) {
+					if (first_off < 8) {
+						memset (tmp, '0', 8);
+						memcpy (tmp + first_off, buf,
+							8 - first_off);
+						mask = 0xffffffff;
+						for (j = 0; j < first_off; j++)
+							mask >>= 1;
+						*q &= ~mask;
+						*q |= simple_strtoul (tmp,0,16);
+					}
+					buf += 9;
+				} else if ((q == last - 1) && last_cnt
+					   && (last_cnt < 8)) {
+					memset (tmp, '0', 8);
+					memcpy (tmp, buf, last_cnt);
+					mask = 0xffffffff;
+					for (j = 0; j < 8 - last_cnt; j++)
+						mask <<= 1;
+					*q &= ~mask;
+					*q |= simple_strtoul (tmp, 0, 16);
+					buf += last_cnt;
+				} else {
+					*q = simple_strtoul (buf, 0, 16);
+					buf += 9;
+				}
+			}
+		}
+		if (!forcelen) {
+			if (op->len < i)
+				op->len = i;
+		} else
+			op->len = i;
+		filp->f_pos += count;
+	}
+write_try_string:
+	if (!(op->flag & OPP_BINARY)) {
+		if (!(op->flag & (OPP_QUOTED | OPP_NOTQUOTED))) {
+			/* No way, if somebody starts writing from the middle, 
+			 * we don't know whether he uses quotes around or not 
+			 */
+			if (k > 0)
+				return -EINVAL;
+			if (*buf == '\'') {
+				op->flag |= OPP_QUOTED;
+				buf++;
+				count--;
+				filp->f_pos++;
+				if (!count) {
+					op->flag |= OPP_STRING;
+					return 1;
+				}
+			} else
+				op->flag |= OPP_NOTQUOTED;
+		}
+		op->flag |= OPP_STRING;
+		if (op->alloclen <= count + filp->f_pos) {
+			b = kmalloc (sizeof (openprom_property)
+				     + 2 * (count + filp->f_pos), GFP_KERNEL);
+			if (!b)
+				return -ENOMEM;
+			memcpy (b, filp->private_data,
+				sizeof (openprom_property)
+				+ strlen (op->name) + op->alloclen);
+			memset (((char *)b) + sizeof (openprom_property)
+				+ strlen (op->name) + op->alloclen, 
+				0, 2*(count - filp->f_pos) - op->alloclen);
+			op = (openprom_property *)b;
+			op->alloclen = 2*(count + filp->f_pos);
+			b = filp->private_data;
+			filp->private_data = (void *)op;
+			kfree (b);
+		}
+		p = op->value + filp->f_pos - ((op->flag & OPP_QUOTED) ? 1 : 0);
+		memcpy (p, buf, count);
+		op->flag |= OPP_DIRTY;
+		for (i = 0; i < count; i++, p++)
+			if (*p == '\n') {
+				*p = 0;
+				break;
+			}
+		if (i < count) {
+			op->len = p - op->value;
+			filp->f_pos += i + 1;
+			if ((p > op->value) && (op->flag & OPP_QUOTED)
+			    && (*(p - 1) == '\''))
+				op->len--;
+		} else {
+			if (p - op->value > op->len)
+				op->len = p - op->value;
+			filp->f_pos += count;
+		}
+	}
+	return filp->f_pos - k;
+}
+
+void property_release (struct inode *inode, struct file *filp)
+{
+	openprom_property *op = (openprom_property *)filp->private_data;
+	unsigned long flags;
+	int error;
+	u32 node;
+	
+	if (!op)
+		return;
+	node = nodes[(u16)((uint)inode->u.generic_ip)].node;
+	if ((u16)((uint)inode->u.generic_ip) == aliases) {
+		if ((op->flag & OPP_DIRTY) && (op->flag & OPP_STRING)) {
+			char *p = op->name;
+			int i = (op->value - op->name) - strlen (op->name) - 1;
+			op->value [op->len] = 0;
+			*(op->value - 1) = ' ';
+			if (i) {
+				for (p = op->value - i - 2; p >= op->name; p--)
+					p[i] = *p;
+				p = op->name + i;
+			}
+			memcpy (p - 8, "nvalias ", 8);
+			prom_feval (p - 8);
+		}
+	} else if (op->flag & OPP_DIRTY) {
+		if (op->flag & OPP_STRING) {
+			op->value [op->len] = 0;
+			save_and_cli (flags);
+			error = prom_setprop (node, op->name,
+					      op->value, op->len + 1);
+			restore_flags (flags);
+			if (error <= 0)
+				printk (KERN_WARNING "/proc/openprom: "
+					"Couldn't write property %s\n",
+					op->name);
+		} else if ((op->flag & OPP_BINARY) || !op->len) {
+			save_and_cli (flags);
+			error = prom_setprop (node, op->name,
+					      op->value, op->len);
+			restore_flags (flags);
+			if (error <= 0)
+				printk (KERN_WARNING "/proc/openprom: "
+					"Couldn't write property %s\n",
+					op->name);
+		} else {
+			printk (KERN_WARNING "/proc/openprom: "
+				"Unknown property type of %s\n",
+				op->name);
+		}
+	}
+	kfree (filp->private_data);
+}
+
+static struct file_operations openpromfs_prop_ops = {
+	NULL,			/* lseek - default */
+	property_read,		/* read */
+	property_write,		/* write - bad */
+	NULL,			/* readdir */
+	NULL,			/* select - default */
+	NULL,			/* ioctl - default */
+	NULL,			/* mmap */
+	NULL,			/* no special open code */
+	property_release,	/* no special release code */
+	NULL			/* can't fsync */
+};
+
+static struct inode_operations openpromfs_prop_inode_ops = {
+	&openpromfs_prop_ops,	/* default property file-ops */
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL			/* permission */
+};
+
+static struct file_operations openpromfs_nodenum_ops = {
+	NULL,			/* lseek - default */
+	nodenum_read,		/* read */
+	NULL,			/* write - bad */
+	NULL,			/* readdir */
+	NULL,			/* select - default */
+	NULL,			/* ioctl - default */
+	NULL,			/* mmap */
+	NULL,			/* no special open code */
+	NULL,			/* no special release code */
+	NULL			/* can't fsync */
+};
+
+static struct inode_operations openpromfs_nodenum_inode_ops = {
+	&openpromfs_nodenum_ops,/* default .node file-ops */
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL			/* permission */
+};
+
+static struct file_operations openprom_alias_operations = {
+	NULL,			/* lseek - default */
+	NULL,			/* read - bad */
+	NULL,			/* write - bad */
+	openpromfs_readdir,	/* readdir */
+	NULL,			/* select - default */
+	NULL,			/* ioctl - default */
+	NULL,			/* mmap */
+	NULL,			/* no special open code */
+	NULL,			/* no special release code */
+	NULL			/* can't fsync */
+};
+
+static struct inode_operations openprom_alias_inode_operations = {
+	&openprom_alias_operations,/* default aliases directory file-ops */
+	openpromfs_create,	/* create */
+	openpromfs_lookup,	/* lookup */
+	NULL,			/* link */
+	openpromfs_unlink,	/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL			/* permission */
+};
+
+static int lookup_children(u16 n, const char * name, int len)
+{
+	int ret;
+	u16 node;
+	for (; n != 0xffff; n = nodes[n].next) {
+		node = nodes[n].child;
+		if (node != 0xffff) {
+			char buffer[128];
+			int i;
+			char *p;
+			
+			while (node != 0xffff) {
+				if (prom_getname (nodes[node].node,
+						  buffer, 128) >= 0) {
+					i = strlen (buffer);
+					if ((len == i)
+					    && !strncmp (buffer, name, len))
+						return NODE2INO(node);
+					p = strchr (buffer, '@');
+					if (p && (len == p - buffer)
+					    && !strncmp (buffer, name, len))
+						return NODE2INO(node);
+				}
+				node = nodes[node].next;
+			}
+		} else
+			continue;
+		ret = lookup_children (nodes[n].child, name, len);
+		if (ret) return ret;
+	}
+	return 0;
+}
+
+static int openpromfs_lookup(struct inode * dir, const char * name, int len,
+	struct inode ** result)
+{
+	int ino = 0;
+#define OPFSL_DIR	0
+#define OPFSL_PROPERTY	1
+#define OPFSL_NODENUM	2
+#define OPFSL_DEVICE	3
+	int type = 0;
+	char buffer[128];
+	char *p;
+	u32 n;
+	u16 dirnode;
+	int i;
+	struct inode *inode;
+	struct openpromfs_dev *d = NULL;
+	
+	*result = NULL;
+	if (!dir || !S_ISDIR(dir->i_mode)) {
+		iput(dir);
+		return -ENOTDIR;
+	}
+	*result = dir;
+	if (!len) return 0;
+	if (name [0] == '.') {
+		if (len == 1)
+			return 0;
+		if (name [1] == '.' && len == 2) {
+			if (dir->i_ino == PROC_OPENPROM) {
+				inode = proc_get_inode (dir->i_sb,
+							PROC_ROOT_INO,
+							&proc_root);
+				iput(dir);
+				if (!inode)
+					return -EINVAL;
+				*result = inode;
+				return 0;
+			}
+			ino = NODE2INO(NODE(dir->i_ino).parent);
+			type = OPFSL_DIR;
+		} else if (len == 5 && !strncmp (name + 1, "node", 4)) {
+			ino = NODEP2INO(NODE(dir->i_ino).first_prop);
+			type = OPFSL_NODENUM;
+		}
+	}
+	if (!ino) {
+		u16 node = NODE(dir->i_ino).child;
+		while (node != 0xffff) {
+			if (prom_getname (nodes[node].node, buffer, 128) >= 0) {
+				i = strlen (buffer);
+				if (len == i && !strncmp (buffer, name, len)) {
+					ino = NODE2INO(node);
+					type = OPFSL_DIR;
+					break;
+				}
+				p = strchr (buffer, '@');
+				if (p && (len == p - buffer)
+				    && !strncmp (buffer, name, len)) {
+					ino = NODE2INO(node);
+					type = OPFSL_DIR;
+					break;
+				}
+			}
+			node = nodes[node].next;
+		}
+	}
+	n = NODE(dir->i_ino).node;
+	dirnode = dir->i_ino - PROC_OPENPROM_FIRST;
+	if (!ino) {
+		int j = NODEP2INO(NODE(dir->i_ino).first_prop);
+		if (dirnode != aliases) {
+			for (p = prom_firstprop (n);
+			     p && *p;
+			     p = prom_nextprop (n, p)) {
+				j++;
+				if ((len == strlen (p))
+				    && !strncmp (p, name, len)) {
+					ino = j;
+					type = OPFSL_PROPERTY;
+					break;
+				}
+			}
+		} else {
+			int k;
+			for (k = 0; k < aliases_nodes; k++) {
+				j++;
+				if (alias_names [k]
+				    && (len == strlen (alias_names [k]))
+				    && !strncmp (alias_names [k], name, len)) {
+					ino = j;
+					type = OPFSL_PROPERTY;
+					break;
+				}
+			}
+		}
+	}
+	if (!ino) {
+		for (d = *devices; d; d = d->next)
+			if ((d->node == n) && (strlen (d->name) == len)
+			    && !strncmp (d->name, name, len)) {
+				ino = d->inode;
+				type = OPFSL_DEVICE;
+				break;
+			}
+	}
+	if (!ino) {
+		ino = lookup_children (NODE(dir->i_ino).child, name, len);
+		if (ino)
+			type = OPFSL_DIR;
+		else {
+			iput(dir);
+			return -ENOENT;
+		}
+	}
+	inode = proc_get_inode (dir->i_sb, ino, 0);
+	iput(dir);
+	if (!inode)
+		return -EINVAL;
+	switch (type) {
+	case OPFSL_DIR:
+		inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+		if (ino == PROC_OPENPROM_FIRST + aliases) {
+			inode->i_mode |= S_IWUSR;
+			inode->i_op = &openprom_alias_inode_operations;
+		} else
+			inode->i_op = proc_openprom_iops;
+		inode->i_nlink = 2;
+		break;
+	case OPFSL_NODENUM:
+		inode->i_mode = S_IFREG | S_IRUGO;
+		inode->i_op = &openpromfs_nodenum_inode_ops;
+		inode->i_nlink = 1;
+		inode->u.generic_ip = (void *)(n);
+		break;
+	case OPFSL_PROPERTY:
+		if ((dirnode == options) && (len == 17)
+		    && !strncmp (name, "security-password", 17))
+			inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
+		else {
+			inode->i_mode = S_IFREG | S_IRUGO;
+			if (dirnode == options || dirnode == aliases) {
+				if (len != 4 || strncmp (name, "name", 4))
+					inode->i_mode |= S_IWUSR;
+			}
+		}
+		inode->i_op = &openpromfs_prop_inode_ops;
+		inode->i_nlink = 1;
+		if (inode->i_size < 0)
+			inode->i_size = 0;
+		inode->u.generic_ip = (void *)(((u16)dirnode) | 
+			(((u16)(ino - NODEP2INO(NODE(dir->i_ino).first_prop) - 1)) << 16));
+		break;
+	case OPFSL_DEVICE:
+		inode->i_mode = d->mode;
+		inode->i_op = &chrdev_inode_operations;
+		inode->i_nlink = 1;
+		inode->i_rdev = d->rdev;
+		break;
+	}		
+	*result = inode;
+	return 0;
+}
+
+static int openpromfs_readdir(struct inode * inode, struct file * filp,
+	void * dirent, filldir_t filldir)
+{
+	unsigned int ino;
+	u32 n;
+	int i, j;
+	char buffer[128];
+	u16 node;
+	char *p;
+	struct openpromfs_dev *d;
+	
+	if (!inode || !S_ISDIR (inode->i_mode)) return -ENOTDIR;
+	ino = inode->i_ino;
+	i = filp->f_pos;
+	switch (i) {
+	case 0:
+		if (filldir(dirent, ".", 1, i, ino) < 0) return 0;
+		i++;
+		filp->f_pos++;
+		/* fall thru */
+	case 1:
+		if (filldir(dirent, "..", 2, i, 
+			(NODE(ino).parent == 0xffff) ? 
+			PROC_ROOT_INO : NODE2INO(NODE(ino).parent)) < 0) 
+			return 0;
+		i++;
+		filp->f_pos++;
+		/* fall thru */
+	default:
+		i -= 2;
+		node = NODE(ino).child;
+		while (i && node != 0xffff) {
+			node = nodes[node].next;
+			i--;
+		}
+		while (node != 0xffff) {
+			if (prom_getname (nodes[node].node, buffer, 128) < 0)
+				return 0;
+			if (filldir(dirent, buffer, strlen(buffer),
+				    filp->f_pos, NODE2INO(node)) < 0)
+				return 0;
+			filp->f_pos++;
+			node = nodes[node].next;
+		}
+		j = NODEP2INO(NODE(ino).first_prop);
+		if (!i) {
+			if (filldir(dirent, ".node", 5, filp->f_pos, j) < 0)
+				return 0;
+			filp->f_pos++;
+		} else
+			i--;
+		n = NODE(ino).node;
+		if (ino == PROC_OPENPROM_FIRST + aliases) {
+			for (j++; i < aliases_nodes; i++, j++) {
+				if (alias_names [i]) {
+					if (filldir (dirent, alias_names [i], 
+						strlen (alias_names [i]), 
+						filp->f_pos, j) < 0) return 0;
+					filp->f_pos++;
+				}
+			}
+		} else {
+			for (p = prom_firstprop (n);
+			     p && *p;
+			     p = prom_nextprop (n, p)) {
+				j++;
+				if (i) i--;
+				else {
+					if (filldir(dirent, p, strlen(p),
+						    filp->f_pos, j) < 0)
+						return 0;
+					filp->f_pos++;
+				}
+			}
+		}
+		for (d = *devices; d; d = d->next) {
+			if (d->node == n) {
+				if (i) i--;
+				else {
+					if (filldir(dirent, d->name,
+						    strlen(d->name),
+						    filp->f_pos, d->inode) < 0)
+						return 0;
+					filp->f_pos++;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+static int openpromfs_create (struct inode *dir, const char *name, int len, 
+			      int mode, struct inode **result)
+{
+	char *p;
+	struct inode *inode;
+	
+	*result = NULL;
+	if (!dir)
+		return -ENOENT;
+	if (len > 256) {
+		iput (dir);
+		return -EINVAL;
+	}
+	if (aliases_nodes == ALIASES_NNODES) {
+		iput (dir);
+		return -EIO;
+	}
+	p = kmalloc (len + 1, GFP_KERNEL);
+	if (!p) {
+		iput (dir);
+		return -ENOMEM;
+	}
+	strncpy (p, name, len);
+	p [len] = 0;
+	alias_names [aliases_nodes++] = p;
+	inode = proc_get_inode (dir->i_sb,
+				NODEP2INO(NODE(dir->i_ino).first_prop)
+				+ aliases_nodes, 0);
+	iput (dir);
+	if (!inode)
+		return -EINVAL;
+	inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR;
+	inode->i_op = &openpromfs_prop_inode_ops;
+	inode->i_nlink = 1;
+	if (inode->i_size < 0) inode->i_size = 0;
+	inode->u.generic_ip = (void *)(((u16)aliases) | 
+			(((u16)(aliases_nodes - 1)) << 16));
+	*result = inode;
+	return 0;
+}
+
+static int openpromfs_unlink (struct inode *dir, const char *name, int len)
+{
+	char *p;
+	int i;
+	
+	if (!dir)
+		return -ENOENT;
+	for (i = 0; i < aliases_nodes; i++)
+		if ((strlen (alias_names [i]) == len)
+		    && !strncmp (name, alias_names[i], len)) {
+			char buffer[512];
+			
+			p = alias_names [i];
+			alias_names [i] = NULL;
+			kfree (p);
+			strcpy (buffer, "nvunalias ");
+			memcpy (buffer + 10, name, len);
+			buffer [10 + len] = 0;
+			prom_feval (buffer);
+		}
+	iput (dir);
+	return 0;
+}
+
+/* {{{ init section */
+static int check_space (u16 n)
+{
+	unsigned long pages;
+
+	if ((1 << alloced) * PAGE_SIZE < (n + 2) * sizeof(openpromfs_node)) {
+		pages = __get_free_pages (GFP_KERNEL, alloced + 1, 0);
+		if (!pages)
+			return -1;
+
+		if (nodes) {
+			memcpy ((char *)pages, (char *)nodes,
+				(1 << alloced) * PAGE_SIZE);
+			free_pages ((unsigned long)nodes, alloced);
+		}
+		alloced++;
+		nodes = (openpromfs_node *)pages;
+	}
+	return 0;
+}
+
+static u16 get_nodes (u16 parent, u32 node)
+{
+	char *p;
+	u16 n = last_node++, i;
+
+	if (check_space (n) < 0)
+		return 0xffff;
+	nodes[n].parent = parent;
+	nodes[n].node = node;
+	nodes[n].next = 0xffff;
+	nodes[n].child = 0xffff;
+	nodes[n].first_prop = first_prop++;
+	if (!parent) {
+		char buffer[8];
+		int j;
+		
+		if ((j = prom_getproperty (node, "name", buffer, 8)) >= 0) {
+		    buffer[j] = 0;
+		    if (!strcmp (buffer, "options"))
+			options = n;
+		    else if (!strcmp (buffer, "aliases"))
+		        aliases = n;
+		}
+	}
+	if (n != aliases)
+		for (p = prom_firstprop (node);
+		     p && p != (char *)-1 && *p;
+		     p = prom_nextprop (node, p))
+			first_prop++;
+	else {
+		char *q;
+		for (p = prom_firstprop (node);
+		     p && p != (char *)-1 && *p;
+		     p = prom_nextprop (node, p)) {
+			if (aliases_nodes == ALIASES_NNODES)
+				break;
+			for (i = 0; i < aliases_nodes; i++)
+				if (!strcmp (p, alias_names [i]))
+					break;
+			if (i < aliases_nodes)
+				continue;
+			q = kmalloc (strlen (p) + 1, GFP_KERNEL);
+			if (!q)
+				return 0xffff;
+			strcpy (q, p);
+			alias_names [aliases_nodes++] = q;
+		}
+		first_prop += ALIASES_NNODES;
+	}
+	node = prom_getchild (node);
+	if (node) {
+		parent = get_nodes (n, node);
+		if (parent == 0xffff)
+			return 0xffff;
+		nodes[n].child = parent;
+		while ((node = prom_getsibling (node)) != 0) {
+			i = get_nodes (n, node);
+			if (i == 0xffff)
+				return 0xffff;
+			nodes[parent].next = i;
+			parent = i;
+		}
+	}
+	return n;
+}
+
+
+#ifdef MODULE
+void openpromfs_use (struct inode *inode, int inc)
+{
+	static int root_fresh = 1;
+	static int dec_first = 1;
+#ifdef OPENPROM_DEBUGGING
+	static int usec = 0;
+
+	if (inc) {
+		if (inode->i_count == 1)
+			usec++;
+		else if (root_fresh && inode->i_ino == PROC_OPENPROM_FIRST) {
+			root_fresh = 0;
+			usec++;
+		}
+	} else {
+		if (inode->i_ino == PROC_OPENPROM_FIRST)
+			root_fresh = 0;
+		if (!dec_first)
+			usec--;
+	}
+	printk ("openpromfs_use: %d %d %d %d\n",
+		inode->i_ino, inc, usec, inode->i_count);
+#else
+	if (inc) {
+		if (inode->i_count == 1)
+			MOD_INC_USE_COUNT;
+		else if (root_fresh && inode->i_ino == PROC_OPENPROM_FIRST) {
+			root_fresh = 0;
+			MOD_INC_USE_COUNT;
+		}
+	} else {
+		if (inode->i_ino == PROC_OPENPROM_FIRST)
+			root_fresh = 0;
+		if (!dec_first)
+			MOD_DEC_USE_COUNT;
+	}
+#endif	
+	dec_first = 0;
+}
+
+#else
+#define openpromfs_use 0
+#endif
+
+#ifndef MODULE
+#define RET(x)
+void openpromfs_init (void)
+#else
+#define RET(x) -x
+int init_module (void)
+#endif
+{
+	if (!romvec->pv_romvers)
+		return RET(ENODEV);
+	nodes = (openpromfs_node *)__get_free_pages(GFP_KERNEL, 0, 0);
+	if (!nodes) {
+		printk (KERN_WARNING "/proc/openprom: can't get free page\n");
+		return RET(EIO);
+	}
+	if (get_nodes (0xffff, prom_root_node) == 0xffff) {
+		printk (KERN_WARNING "/proc/openprom: couldn't setup tree\n");
+		return RET(EIO);
+	}
+	nodes[last_node].first_prop = first_prop;
+	proc_openprom_iops = proc_openprom_register (openpromfs_readdir,
+				openpromfs_lookup, openpromfs_use, &devices);
+	return RET(0);
+}
+
+#ifdef MODULE
+void cleanup_module (void)
+{
+	int i;
+	proc_openprom_deregister ();
+	free_pages ((unsigned long)nodes, alloced);
+	for (i = 0; i < aliases_nodes; i++)
+		if (alias_names [i])
+			kfree (alias_names [i]);
+	nodes = NULL;
+}
+#endif
diff -u --recursive --new-file v2.1.15/linux/fs/smbfs/sock.c linux/fs/smbfs/sock.c
--- v2.1.15/linux/fs/smbfs/sock.c	Thu Dec 12 19:37:18 1996
+++ linux/fs/smbfs/sock.c	Mon Dec 16 13:10:33 1996
@@ -263,6 +263,10 @@
 				   (void *) (target + already_read),
 				   length - already_read, 0, 0, NULL);
 
+		if (result == 0)
+		{
+			return -EIO;
+		}
 		if (result < 0)
 		{
 			DPRINTK("smb_receive_raw: recvfrom error = %d\n",
diff -u --recursive --new-file v2.1.15/linux/fs/super.c linux/fs/super.c
--- v2.1.15/linux/fs/super.c	Fri Nov  1 17:13:19 1996
+++ linux/fs/super.c	Thu Dec 12 19:34:38 1996
@@ -278,6 +278,7 @@
 	{ MS_NODEV, ",nodev" },
 	{ MS_SYNCHRONOUS, ",sync" },
 	{ MS_MANDLOCK, ",mand" },
+	{ MS_NOATIME, ",noatime" },
 #ifdef MS_NOSUB			/* Can't find this except in mount.c */
 	{ MS_NOSUB, ",nosub" },
 #endif
diff -u --recursive --new-file v2.1.15/linux/fs/ufs/ufs_super.c linux/fs/ufs/ufs_super.c
--- v2.1.15/linux/fs/ufs/ufs_super.c	Tue Oct 29 19:58:45 1996
+++ linux/fs/ufs/ufs_super.c	Fri Dec 13 11:37:39 1996
@@ -6,7 +6,9 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_super.c,v 1.17 1996/09/03 07:15:53 ecd Exp $
+ * Copyright (C) 1996  Eddie C. Dost  (ecd@skynet.be)
+ *
+ * $Id: ufs_super.c,v 1.20 1996/11/02 18:10:12 ecd Exp $
  *
  */
 
@@ -158,7 +160,7 @@
 		ufs_need_swab = 1;
 		sb->s_magic = ufs_swab32(usb->fs_magic);
 		if (sb->s_magic != UFS_MAGIC) {
-	                printk ("ufs_read_super: bad magic number 0x%8.8x "
+	                printk ("ufs_read_super: bad magic number 0x%8.8lx "
 				"on dev %d/%d\n", sb->s_magic,
 				MAJOR(sb->s_dev), MINOR(sb->s_dev));
 
@@ -291,23 +293,36 @@
 void ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz)
 {
 	struct statfs tmp;
+	struct statfs *sp = &tmp;
+	struct ufs_superblock *fsb = sb->u.ufs_sb.s_raw_sb;
+	unsigned long used, avail;
 
         if (sb->u.ufs_sb.s_flags & UFS_DEBUG) {
 		printk("ufs_statfs\n"); /* XXX */
         }
 
-	tmp.f_type = sb->s_magic;
-	tmp.f_bsize = sb->s_blocksize;
-	tmp.f_blocks = ufs_swab32(sb->u.ufs_sb.s_raw_sb->fs_dsize);
-	tmp.f_bfree = ufs_swab32(sb->u.ufs_sb.s_raw_sb->fs_cstotal.cs_nbfree);
-	tmp.f_bavail =  ufs_swab32(sb->u.ufs_sb.s_raw_sb->fs_cstotal.cs_nbfree);
-	tmp.f_files = sb->u.ufs_sb.s_ncg * sb->u.ufs_sb.s_ipg;
-	tmp.f_ffree = ufs_swab32(sb->u.ufs_sb.s_raw_sb->fs_cstotal.cs_nifree);
-	tmp.f_fsid.val[0] = ufs_swab32(sb->u.ufs_sb.s_raw_sb->fs_id[0]);
-	tmp.f_fsid.val[1] = ufs_swab32(sb->u.ufs_sb.s_raw_sb->fs_id[1]);
-	tmp.f_namelen = UFS_MAXNAMLEN;
+	sp->f_type = sb->s_magic;
+	sp->f_bsize = sb->s_blocksize;
+	sp->f_blocks = ufs_swab32(fsb->fs_dsize);
+	sp->f_bfree = ufs_swab32(fsb->fs_cstotal.cs_nbfree) *
+			ufs_swab32(fsb->fs_frag) +
+			ufs_swab32(fsb->fs_cstotal.cs_nffree);
+
+	avail = sp->f_blocks - (sp->f_blocks / 100) *
+			ufs_swab32(fsb->fs_minfree);
+	used = sp->f_blocks - sp->f_bfree;
+	if (avail > used)
+		sp->f_bavail = avail - used;
+	else
+		sp->f_bavail = 0;
+
+	sp->f_files = sb->u.ufs_sb.s_ncg * sb->u.ufs_sb.s_ipg;
+	sp->f_ffree = ufs_swab32(fsb->fs_cstotal.cs_nifree);
+	sp->f_fsid.val[0] = ufs_swab32(fsb->fs_id[0]);
+	sp->f_fsid.val[1] = ufs_swab32(fsb->fs_id[1]);
+	sp->f_namelen = UFS_MAXNAMLEN;
 
-	copy_to_user(buf, &tmp, bufsiz);
+	copy_to_user(buf, sp, bufsiz);
 	return;
 }
 
diff -u --recursive --new-file v2.1.15/linux/fs/ufs/ufs_symlink.c linux/fs/ufs/ufs_symlink.c
--- v2.1.15/linux/fs/ufs/ufs_symlink.c	Tue Oct 29 19:58:46 1996
+++ linux/fs/ufs/ufs_symlink.c	Fri Dec 13 11:37:39 1996
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_symlink.c,v 1.5 1996/05/19 03:55:56 krioles Exp $
+ * $Id: ufs_symlink.c,v 1.6 1996/10/30 06:00:36 davem Exp $
  *
  */
 
diff -u --recursive --new-file v2.1.15/linux/include/asm-alpha/socket.h linux/include/asm-alpha/socket.h
--- v2.1.15/linux/include/asm-alpha/socket.h	Sat Nov 30 12:03:11 1996
+++ linux/include/asm-alpha/socket.h	Sun Dec 15 19:41:56 1996
@@ -37,4 +37,7 @@
 #define SO_PRIORITY	12
 #define SO_BSDCOMPAT	14
 
+#define SO_PASSCRED	17
+#define SO_PEERCRED	18
+
 #endif /* _ASM_SOCKET_H */
diff -u --recursive --new-file v2.1.15/linux/include/asm-i386/pgtable.h linux/include/asm-i386/pgtable.h
--- v2.1.15/linux/include/asm-i386/pgtable.h	Sat Oct 19 10:07:32 1996
+++ linux/include/asm-i386/pgtable.h	Wed Dec 18 12:45:23 1996
@@ -82,7 +82,7 @@
 	__flush_tlb()
 
 
-#undef CLEVER_SMP_INVALIDATE
+#define CLEVER_SMP_INVALIDATE
 #ifdef CLEVER_SMP_INVALIDATE
 
 /*
@@ -91,9 +91,6 @@
  *
  *	These mean you can really definitely utterly forget about
  *	writing to user space from interrupts. (Its not allowed anyway).
- *
- *	Doesn't currently work as Linus makes flush tlb calls before
- *	stuff like current/current->mm are setup properly
  */
  
 static inline void flush_tlb_current_task(void)
diff -u --recursive --new-file v2.1.15/linux/include/asm-i386/string.h linux/include/asm-i386/string.h
--- v2.1.15/linux/include/asm-i386/string.h	Sat Apr 20 13:12:23 1996
+++ linux/include/asm-i386/string.h	Wed Dec 18 10:02:49 1996
@@ -402,6 +402,10 @@
 		case 4:
 			*(unsigned long *)to = *(const unsigned long *)from;
 			return to;
+		case 6:	/* for ethernet addresses */
+			*(unsigned long *)to = *(const unsigned long *)from;
+			*(2+(unsigned short *)to) = *(2+(const unsigned short *)from);
+			return to;
 		case 8:
 			*(unsigned long *)to = *(const unsigned long *)from;
 			*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/atomic.h linux/include/asm-ppc/atomic.h
--- v2.1.15/linux/include/asm-ppc/atomic.h	Mon May 27 12:00:59 1996
+++ linux/include/asm-ppc/atomic.h	Wed Dec 18 10:54:09 1996
@@ -6,5 +6,17 @@
 #define _ASM_PPC_ATOMIC_H_
 
 typedef int atomic_t;
+/*
+ * Make sure gcc doesn't try to be clever and move things around
+ * on us. We need to use _exactly_ the address the user gave us,
+ * not some alias that contains the same information.
+ */
+#define __atomic_fool_gcc(x) (*(struct { int a[100]; } *)x)
+
+#define atomic_dec_return(v) ({atomic_sub(1,(v));(v);})
+#define atomic_inc_return(v) ({atomic_add(1,(v));(v);})
+
+#define atomic_inc(v) atomic_add(1,(v))
+#define atomic_dec(v) atomic_sub(1,(v))
 #endif
 
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/bitops.h linux/include/asm-ppc/bitops.h
--- v2.1.15/linux/include/asm-ppc/bitops.h	Mon May 27 12:00:59 1996
+++ linux/include/asm-ppc/bitops.h	Wed Dec 18 10:54:09 1996
@@ -1,39 +1,32 @@
 #ifndef _ASM_PPC_BITOPS_H_
 #define _ASM_PPC_BITOPS_H_
 
-/*
- * For the benefit of those who are trying to port Linux to another
- * architecture, here are some C-language equivalents.  You should
- * recode these in the native assembly language, if at all possible.
- * To guarantee atomicity, these routines call cli() and sti() to
- * disable interrupts while they operate.  (You have to provide inline
- * routines to cli() and sti().)
- *
- * Also note, these routines assume that you have 32 bit integers.
- * You will have to change this if you are trying to port Linux to the
- * Alpha architecture or to a Cray.  :-)
- * 
- * C language equivalents written by Theodore Ts'o, 9/26/92
- */
-
-#include "asm/system.h"  /* For cli/sti declaration */
+#include <asm/system.h>
+#include <asm/byteorder.h>
 
 #define BIT(n) 1<<(n&0x1F)
 typedef unsigned long BITFIELD;
 
+
+/* Set bit 'nr' in 32-bit quantity at address 'addr' where bit '0'
+ * is in the highest of the four bytes and bit '31' is the high bit
+ * within the first byte. powerpc is BIG-Endian. Unless noted otherwise
+ * all bit-ops return 0 if bit was previously clear and != 0 otherwise.
+ */
 extern __inline__ int set_bit(int nr, void * add)
 {
-       int	mask, oldbit;
   BITFIELD *addr = add;
-       
+	long	mask,oldbit;       
+#ifdef __KERNEL__
 	int s = _disable_interrupts();
+#endif
 	addr += nr >> 5;
 	mask = BIT(nr);
 	oldbit = (mask & *addr) != 0;
 	*addr |= mask;
+#ifdef __KERNEL__	
 	_enable_interrupts(s);
-
-	
+#endif
 	return oldbit;
 }
 
@@ -41,12 +34,16 @@
 {
   	BITFIELD *addr = add;
 	int	mask, retval;
+#ifdef __KERNEL__
 	int s = _disable_interrupts();
+#endif
 	addr += nr >> 5;
 	mask = BIT(nr);
 	retval = (mask & *addr) != 0;
 	*addr ^= mask;
+#ifdef __KERNEL__
 	_enable_interrupts(s);
+#endif
 	return retval;
 }
 
@@ -54,77 +51,115 @@
 {
         BITFIELD *addr = add;
 	int	mask, retval;
+#ifdef __KERNEL__
 	int s = _disable_interrupts();
+#endif
 	addr += nr >> 5;
 	mask = BIT(nr);
 	retval = (mask & *addr) != 0;
 	*addr &= ~mask;
+#ifdef __KERNEL__	
 	_enable_interrupts(s);
+#endif
 	return retval;
 }
 
-extern __inline__ int test_bit(int nr, void *add)
+#define _EXT2_HAVE_ASM_BITOPS_
+#define ext2_find_first_zero_bit(addr, size) \
+        ext2_find_next_zero_bit((addr), (size), 0)
+
+
+extern __inline__ int ext2_set_bit(int nr, void * addr)
 {
-	int	mask;
-	BITFIELD *addr = add;
+#ifdef __KERNEL__
+  int s = _disable_interrupts();
+#endif
+  int			mask;
+  unsigned char	*ADDR = (unsigned char *) addr;
+  int oldbit;
+  
+  ADDR += nr >> 3;
+  mask = 1 << (nr & 0x07);
+  oldbit = (*ADDR & mask) ? 1 : 0;
+  *ADDR |= mask;
+#ifdef __KERNEL__	
+  _enable_interrupts(s);
+#endif
+  return oldbit;
+}
 
-	addr += nr >> 5;
-	mask = BIT(nr);
-	return ((mask & *addr) != 0);
+extern __inline__ int ext2_clear_bit(int nr, void * addr)
+{
+#ifdef __KERNEL__
+  int s = _disable_interrupts();
+#endif
+  int		mask;
+  unsigned char	*ADDR = (unsigned char *) addr;
+  int oldbit;
+  
+  ADDR += nr >> 3;
+  mask = 1 << (nr & 0x07);
+  oldbit = (*ADDR & mask) ? 1 : 0;
+  *ADDR = *ADDR & ~mask;
+#ifdef __KERNEL__	
+  _enable_interrupts(s);
+#endif
+  return oldbit;
 }
-#if 0
-extern __inline__ int find_first_zero_bit(void *add, int len)
+
+
+/* The following routine need not be atomic. */
+extern __inline__ unsigned long test_bit(int nr, void *addr)
 {
-	int	mask, nr, i;
-	BITFIELD *addr = add;
-	nr = 0;
-	while (len)
-	{
-		if (~*addr != 0)
-		{ /* Contains at least one zero */
-			for (i = 0;  i < 32;  i++, nr++)
-			{
-				mask = BIT(nr);
-				if ((mask & *addr) == 0)
-				{
-					return (nr);
-				}
-			}
-		}
-		len -= 32;
-		addr++;
-		nr += 32;
-	}
-	return (0);  /* Shouldn't happen */
+	return 1UL & (((__const__ unsigned int *) addr)[nr >> 5] >> (nr & 31));
 }
 
-extern __inline__ int find_next_zero_bit(void *add, int len, int nr)
+extern __inline__ int ext2_test_bit(int nr, __const__ void * addr)
 {
-	int	mask, i;
-	BITFIELD *addr = add;
-	addr += nr >> 5;
-	len -= nr;
-	while (len)
-	{
-		if (*addr != 0xFFFFFFFF)
-		{ /* Contains at least one zero */
-			for (i = 0;  i < 32;  i++, nr++)
-			{
-				mask = BIT(nr);
-				if ((mask & *addr) == 0)
-				{
-printk("Bit: %d(%d), Pat: %x\n", nr, nr&0x1F, *addr);					
-					return (nr);
-				}
-			}
-		}
-		len -= 32;
-		addr++;
-		nr += 32;
+	int			mask;
+	__const__ unsigned char	*ADDR = (__const__ unsigned char *) addr;
+
+	ADDR += nr >> 3;
+	mask = 1 << (nr & 0x07);
+	return ((mask & *ADDR) != 0);
+}
+
+extern __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
+{
+	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
+	unsigned long result = offset & ~31UL;
+	unsigned long tmp;
+
+	if (offset >= size)
+		return size;
+	size -= result;
+	offset &= 31UL;
+	if(offset) {
+		tmp = *(p++);
+		tmp |= le32_to_cpu(~0UL >> (32-offset));
+		if(size < 32)
+			goto found_first;
+		if(~tmp)
+			goto found_middle;
+		size -= 32;
+		result += 32;
+	}
+	while(size & ~31UL) {
+		if(~(tmp = *(p++)))
+			goto found_middle;
+		result += 32;
+		size -= 32;
 	}
-	return (0);  /* Shouldn't happen */
+	if(!size)
+		return result;
+	tmp = *p;
+
+found_first:
+	return result + ffz(le32_to_cpu(tmp) | (~0UL << size));
+found_middle:
+	return result + ffz(le32_to_cpu(tmp));
 }
-#endif
+
 #endif /* _ASM_PPC_BITOPS_H */
 
 
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/byteorder.h linux/include/asm-ppc/byteorder.h
--- v2.1.15/linux/include/asm-ppc/byteorder.h	Sat Nov 25 19:49:06 1995
+++ linux/include/asm-ppc/byteorder.h	Wed Dec 18 10:54:09 1996
@@ -9,85 +9,48 @@
 #define __BIG_ENDIAN_BITFIELD
 #endif
 
-#if 0 /* Assume PowerPC is Big-Endian! */
-#undef ntohl
-#undef ntohs
-#undef htonl
-#undef htons
-
-extern unsigned long int	ntohl(unsigned long int);
-extern unsigned short int	ntohs(unsigned short int);
-extern unsigned long int	htonl(unsigned long int);
-extern unsigned short int	htons(unsigned short int);
-
-extern unsigned long int	__ntohl(unsigned long int);
-extern unsigned short int	__ntohs(unsigned short int);
-extern unsigned long int	__constant_ntohl(unsigned long int);
-extern unsigned short int	__constant_ntohs(unsigned short int);
+#define ntohl(x) (x)
+#define ntohs(x) (x)
+#define htonl(x) (x)
+#define htons(x) (x)
 
-extern __inline__ unsigned long int
-__ntohl(unsigned long int x)
-{
-	return (((x & 0x000000ffU) << 24) |
-		((x & 0x0000ff00U) <<  8) |
-		((x & 0x00ff0000U) >>  8) |
-		((x & 0xff000000U) >> 24));
-}
+#define __htonl(x) ntohl(x)
+#define __htons(x) ntohs(x)
+#define __constant_htonl(x) ntohl(x)
+#define __constant_htons(x) ntohs(x)
+
+/*
+ * In-kernel byte order macros to handle stuff like
+ * byte-order-dependent filesystems etc.
+ */
 
-extern __inline__ unsigned long int
-__constant_ntohl(unsigned long int x)
+#define cpu_to_le32(x) le32_to_cpu((x))
+extern __inline__ unsigned long le32_to_cpu(unsigned long x)
 {
-	return (((x & 0x000000ffU) << 24) |
+     	return (((x & 0x000000ffU) << 24) |
 		((x & 0x0000ff00U) <<  8) |
 		((x & 0x00ff0000U) >>  8) |
 		((x & 0xff000000U) >> 24));
 }
 
-extern __inline__ unsigned short int
-__ntohs(unsigned short int x)
-{
-	return (((x & 0x00ff) << 8) |
-		((x & 0xff00) >> 8));
-}
 
-extern __inline__ unsigned short int
-__constant_ntohs(unsigned short int x)
+#define cpu_to_le16(x) le16_to_cpu((x))
+extern __inline__ unsigned short le16_to_cpu(unsigned short x)
 {
 	return (((x & 0x00ff) << 8) |
 		((x & 0xff00) >> 8));
 }
 
-#define __htonl(x) __ntohl(x)
-#define __htons(x) __ntohs(x)
-#define __constant_htonl(x) __constant_ntohl(x)
-#define __constant_htons(x) __constant_ntohs(x)
-
-#ifdef  __OPTIMIZE__
-#  define ntohl(x) \
-(__builtin_constant_p((long)(x)) ? \
- __constant_ntohl((x)) : \
- __ntohl((x)))
-#  define ntohs(x) \
-(__builtin_constant_p((short)(x)) ? \
- __constant_ntohs((x)) : \
- __ntohs((x)))
-#  define htonl(x) \
-(__builtin_constant_p((long)(x)) ? \
- __constant_htonl((x)) : \
- __htonl((x)))
-#  define htons(x) \
-(__builtin_constant_p((short)(x)) ? \
- __constant_htons((x)) : \
- __htons((x)))
-#endif
+#define cpu_to_be32(x) (x)
+#define be32_to_cpu(x) (x)
+#define cpu_to_be16(x) (x)
+#define be16_to_cpu(x) (x)
+
+
+#endif /* !(_PPC_BYTEORDER_H) */
+
+
 
-#else
 
-#define ntohl(x) (x)
-#define ntohs(x) (x)
-#define htonl(x) (x)
-#define htons(x) (x)
 
-#endif
 
-#endif /* !(_PPC_BYTEORDER_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/checksum.h linux/include/asm-ppc/checksum.h
--- v2.1.15/linux/include/asm-ppc/checksum.h	Sat Nov 25 19:49:06 1995
+++ linux/include/asm-ppc/checksum.h	Wed Dec 18 10:54:09 1996
@@ -54,5 +54,5 @@
 A */
 
 extern unsigned short ip_compute_csum(unsigned char * buff, int len);
-
+extern unsigned int csum_fold(unsigned int sum);
 #endif
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/dma.h linux/include/asm-ppc/dma.h
--- v2.1.15/linux/include/asm-ppc/dma.h	Mon May 27 12:00:59 1996
+++ linux/include/asm-ppc/dma.h	Wed Dec 18 10:54:09 1996
@@ -7,6 +7,7 @@
 
 /*
  * Note: Adapted for PowerPC by Gary Thomas
+ * Modified by Cort Dougan <cort@cs.nmt.edu>
  *
  * There may be some comments or restrictions made here which are
  * not valid for the PowerPC (PreP) platform.  Take what you read
@@ -292,7 +293,6 @@
 
 
 /* These are in kernel/dma.c: */
-/*extern int request_dma(unsigned int dmanr, char * device_id);*/	/* reserve a DMA channel */
 extern void free_dma(unsigned int dmanr);	/* release it again */
 
 
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/elf.h linux/include/asm-ppc/elf.h
--- v2.1.15/linux/include/asm-ppc/elf.h	Sun Aug  4 14:12:40 1996
+++ linux/include/asm-ppc/elf.h	Wed Dec 18 10:54:09 1996
@@ -4,27 +4,30 @@
 /*
  * ELF register definitions..
  */
+#include <asm/ptrace.h>
 
 #define ELF_NGREG	32
 #define ELF_NFPREG	32
 
-typedef unsigned long elf_greg_t;
-typedef elf_greg_t elf_gregset_t[ELF_NGREG];
-
-typedef double elf_fpreg_t;
-typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
-
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
 #define elf_check_arch(x) ((x) == EM_PPC)
 
 /*
  * These are used to set parameters in the core dumps.
- * FIXME(eric) I don't know what the correct endianness to use is.
  */
-#define ELF_CLASS	ELFCLASS32
-#define ELF_DATA	ELFDATA2LSB;
 #define ELF_ARCH	EM_PPC
+#define ELF_CLASS	ELFCLASS32
+#define ELF_DATA	ELFDATA2MSB;
 
 #define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE	4096
+
+typedef unsigned long elf_greg_t;
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef double elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 
 #endif
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/fcntl.h linux/include/asm-ppc/fcntl.h
--- v2.1.15/linux/include/asm-ppc/fcntl.h	Sun Sep 22 09:41:32 1996
+++ linux/include/asm-ppc/fcntl.h	Wed Dec 18 10:54:09 1996
@@ -48,6 +48,12 @@
 				   blocking */
 #define LOCK_UN		8	/* remove lock */
 
+#ifdef __KERNEL__
+#define F_POSIX		1
+#define F_FLOCK		2
+#define F_BROKEN	4	/* broken flock() emulation */
+#endif /* __KERNEL__ */
+
 struct flock {
 	short l_type;
 	short l_whence;
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/floppy.h linux/include/asm-ppc/floppy.h
--- v2.1.15/linux/include/asm-ppc/floppy.h	Sat Sep 28 22:05:42 1996
+++ linux/include/asm-ppc/floppy.h	Wed Dec 18 10:54:09 1996
@@ -19,7 +19,7 @@
 #define fd_free_dma()           free_dma(FLOPPY_DMA)
 #define fd_clear_dma_ff()       clear_dma_ff(FLOPPY_DMA)
 #define fd_set_dma_mode(mode)   set_dma_mode(FLOPPY_DMA,mode)
-#define fd_set_dma_addr(addr)   set_dma_addr(FLOPPY_DMA,virt_to_bus(addr))
+#define fd_set_dma_addr(addr)   set_dma_addr(FLOPPY_DMA,(unsigned int)virt_to_bus(addr))
 #define fd_set_dma_count(count) set_dma_count(FLOPPY_DMA,count)
 #define fd_enable_irq()         enable_irq(FLOPPY_IRQ)
 #define fd_disable_irq()        disable_irq(FLOPPY_IRQ)
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/floppy.h.old linux/include/asm-ppc/floppy.h.old
--- v2.1.15/linux/include/asm-ppc/floppy.h.old	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-ppc/floppy.h.old	Wed Dec 18 10:54:09 1996
@@ -0,0 +1,54 @@
+/*
+ * Architecture specific parts of the Floppy driver
+ *
+ * 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) 1995
+ */
+#ifndef __ASM_PPC_FLOPPY_H
+#define __ASM_PPC_FLOPPY_H
+
+#define fd_inb(port)			inb_p(port)
+#define fd_outb(port,value)		outb_p(port,value)
+
+#define fd_enable_dma()         enable_dma(FLOPPY_DMA)
+#define fd_disable_dma()        disable_dma(FLOPPY_DMA)
+#define fd_request_dma()        request_dma(FLOPPY_DMA,"floppy")
+#define fd_free_dma()           free_dma(FLOPPY_DMA)
+#define fd_clear_dma_ff()       clear_dma_ff(FLOPPY_DMA)
+#define fd_set_dma_mode(mode)   set_dma_mode(FLOPPY_DMA,mode)
+#define fd_set_dma_addr(addr)   set_dma_addr(FLOPPY_DMA,addr)
+#define fd_set_dma_count(count) set_dma_count(FLOPPY_DMA,count)
+#define fd_enable_irq()         enable_irq(FLOPPY_IRQ)
+#define fd_disable_irq()        disable_irq(FLOPPY_IRQ)
+#define fd_cacheflush(addr,size) /* nothing */
+#define fd_request_irq()        request_irq(FLOPPY_IRQ, floppy_interrupt, \
+					    SA_INTERRUPT|SA_SAMPLE_RANDOM, \
+				            "floppy", NULL)
+#define fd_free_irq()           free_irq(FLOPPY_IRQ, NULL);
+
+__inline__ void virtual_dma_init(void)
+{
+	/* Nothing to do on PowerPC */
+}
+
+static int FDC1 = 0x3f0;
+static int FDC2 = -1;
+
+/*
+ * Again, the CMOS information not available
+ */
+#define FLOPPY0_TYPE 6
+#define FLOPPY1_TYPE 0
+
+#define N_FDC 2			/* Don't change this! */
+#define N_DRIVE 8
+
+/*
+ * The PowerPC has no problems with floppy DMA crossing 64k borders.
+ */
+#define CROSS_64KB(a,s)	(0)
+
+#endif /* __ASM_PPC_FLOPPY_H */
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/ide.h linux/include/asm-ppc/ide.h
--- v2.1.15/linux/include/asm-ppc/ide.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-ppc/ide.h	Wed Dec 18 10:54:09 1996
@@ -0,0 +1,119 @@
+/*
+ *  linux/include/asm-i386/ide.h
+ *
+ *  Copyright (C) 1994-1996  Linus Torvalds & authors
+ */
+
+/*
+ *  This file contains the ppc architecture specific IDE code.
+ */
+
+#ifndef __ASMPPC_IDE_H
+#define __ASMPPC_IDE_H
+
+#ifdef __KERNEL__
+
+typedef unsigned short ide_ioreg_t;
+
+#ifndef MAX_HWIFS
+#define MAX_HWIFS	4
+#endif
+
+#define ide_sti()	sti()
+
+static __inline__ int ide_default_irq(ide_ioreg_t base)
+{
+	switch (base) {
+		case 0x1f0: return 14;
+		case 0x170: return 15;
+		case 0x1e8: return 11;
+		case 0x168: return 10;
+		default:
+			return 0;
+	}
+}
+
+static __inline__ ide_ioreg_t ide_default_io_base(int index)
+{
+	switch (index) {
+		case 0:	return 0x1f0;
+		case 1:	return 0x170;
+		case 2: return 0x1e8;
+		case 3: return 0x168;
+		default:
+			return 0;
+	}
+}
+
+static __inline__ void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+	ide_ioreg_t port = base;
+	int i = 8;
+
+	while (i--)
+		*p++ = port++;
+	*p++ = base + 0x206;
+	if (irq != NULL)
+		*irq = 0;
+}
+
+typedef union {
+	unsigned all			: 8;	/* all of the bits together */
+	struct {
+		unsigned head		: 4;	/* always zeros here */
+		unsigned unit		: 1;	/* drive select number, 0 or 1 */
+		unsigned bit5		: 1;	/* always 1 */
+		unsigned lba		: 1;	/* using LBA instead of CHS */
+		unsigned bit7		: 1;	/* always 1 */
+	} b;
+	} select_t;
+
+static __inline__ int ide_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+			unsigned long flags, const char *device, void *dev_id)
+{
+	return request_irq(irq, handler, flags, device, dev_id);
+}			
+
+static __inline__ void ide_free_irq(unsigned int irq, void *dev_id)
+{
+	free_irq(irq, dev_id);
+}
+
+static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
+{
+	return check_region(from, extent);
+}
+
+static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
+{
+	request_region(from, extent, name);
+}
+
+static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
+{
+	release_region(from, extent);
+}
+
+/*
+ * The following are not needed for the non-m68k ports
+ */
+static __inline__ int ide_ack_intr (ide_ioreg_t base_port, ide_ioreg_t irq_port)
+{
+	return(1);
+}
+
+static __inline__ void ide_fix_driveid(struct hd_driveid *id)
+{
+}
+
+static __inline__ void ide_release_lock (int *ide_lock)
+{
+}
+
+static __inline__ void ide_get_lock (int *ide_lock, void (*handler)(int, void *, struct pt_regs *), void *data)
+{
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* __ASMPPC_IDE_H */
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/io.h linux/include/asm-ppc/io.h
--- v2.1.15/linux/include/asm-ppc/io.h	Sat Nov 25 19:49:06 1995
+++ linux/include/asm-ppc/io.h	Wed Dec 18 10:54:09 1996
@@ -1,16 +1,28 @@
 #ifndef _PPC_IO_H
 #define _PPC_IO_H
 
-/* Define the particulars of outb/outw/outl "instructions" */
+#include <asm/page.h>
+
+/* from the Carolina Technical Spec -- Cort */
+#define IBM_ACORN 0x82A
+#define SIO_CONFIG_RA	0x398
+#define SIO_CONFIG_RD	0x399
+
+#define IBM_HDD_LED       0x808
+#define IBM_EQUIP_PRESENT 0x80c	
+#define IBM_L2_STATUS     0x80d
+#define IBM_L2_INVALIDATE 0x814
+#define IBM_SYS_CTL       0x81c
+
 
+
+/* Define the particulars of outb/outw/outl "instructions" */
 #define SLOW_DOWN_IO
 
 #ifndef PCI_DRAM_OFFSET
 #define PCI_DRAM_OFFSET  0x80000000
 #endif
-#ifndef KERNELBASE
-#define KERNELBASE 0x90000000
-#endif
+
 
 /*
  * The PCI bus is inherently Little-Endian.  The PowerPC is being
@@ -39,10 +51,10 @@
 #define readb(addr) (*(volatile unsigned char *) (addr))
 #define readw(addr) (*(volatile unsigned short *) (addr))
 #define readl(addr) (*(volatile unsigned int *) (addr))
-
 #define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
 #define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
 #define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
+
 
 /*
  * Change virtual addresses to physical addresses and vv.
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/ipc.h linux/include/asm-ppc/ipc.h
--- v2.1.15/linux/include/asm-ppc/ipc.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-ppc/ipc.h	Wed Dec 18 10:54:09 1996
@@ -0,0 +1,28 @@
+#ifndef __i386_IPC_H__
+#define __i386_IPC_H__
+
+/* 
+ * These are used to wrap system calls on x86.
+ *
+ * See arch/i386/kernel/sys_i386.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
+
+#define IPCCALL(version,op)	((version)<<16 | (op))
+
+#endif
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/mman.h linux/include/asm-ppc/mman.h
--- v2.1.15/linux/include/asm-ppc/mman.h	Wed Oct  9 08:55:23 1996
+++ linux/include/asm-ppc/mman.h	Wed Dec 18 10:54:09 1996
@@ -12,10 +12,11 @@
 #define MAP_FIXED	0x10		/* Interpret addr exactly */
 #define MAP_ANONYMOUS	0x20		/* don't use a file */
 #define MAP_RENAME      MAP_ANONYMOUS   /* In SunOS terminology */
+#define MAP_NORESERVE   0x40            /* don't reserve swap pages */
 
 #define MAP_GROWSDOWN	0x0100		/* stack-like segment */
 #define MAP_DENYWRITE	0x0800		/* ETXTBSY */
-#define MAP_EXECUTABLE	0x1000		/* mark it as an executable */
+#define MAP_EXECUTABLE	0x1000		/* mark it as a executable */
 
 #define MS_ASYNC	1		/* sync memory asynchronously */
 #define MS_INVALIDATE	2		/* invalidate the caches */
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/mmu.h linux/include/asm-ppc/mmu.h
--- v2.1.15/linux/include/asm-ppc/mmu.h	Mon May 27 12:00:59 1996
+++ linux/include/asm-ppc/mmu.h	Wed Dec 18 10:54:09 1996
@@ -6,7 +6,6 @@
 #define _PPC_MMU_H_
 
 /* Hardware Page Table Entry */
- 
 typedef struct _PTE
    {
       unsigned long v:1;	/* Entry is valid */
@@ -32,7 +31,6 @@
 #define PP_RXRX 3	/* Supervisor read,       User read */
 
 /* Segment Register */
-
 typedef struct _SEGREG
    {
       unsigned long t:1;	/* Normal or I/O  type */
@@ -44,7 +42,6 @@
    } SEGREG;
 
 /* Block Address Translation (BAT) Registers */
-
 typedef struct _BATU		/* Upper part of BAT */
    {
       unsigned long bepi:15;	/* Effective page index (virtual address) */
@@ -146,8 +143,6 @@
 #define HASH_TABLE_MASK_2M	0x01F   
 #define HASH_TABLE_MASK_4M	0x03F   
 
-#define MMU_PAGE_SIZE	4096
-
-extern int MMU_hash_page(struct thread_struct *tss, unsigned long va, pte *pg);
+extern inline int MMU_hash_page(struct thread_struct *tss, unsigned long va, pte *pg);
 
 #endif
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/page.h linux/include/asm-ppc/page.h
--- v2.1.15/linux/include/asm-ppc/page.h	Mon May 27 12:00:59 1996
+++ linux/include/asm-ppc/page.h	Wed Dec 18 10:54:09 1996
@@ -6,8 +6,6 @@
 #define PAGE_SIZE	(1UL << PAGE_SHIFT)
 #define PAGE_MASK	(~(PAGE_SIZE-1))
 
-void invalidate(void);
-
 #ifdef __KERNEL__
 
 #define STRICT_MM_TYPECHECKS
@@ -59,30 +57,15 @@
 
 #define KERNELBASE	0x90000000
 #define PAGE_OFFSET	KERNELBASE
-#define MAP_NR(addr)	((((unsigned long)addr) - PAGE_OFFSET) >> PAGE_SHIFT)
-#define MAP_PAGE_RESERVED	(1<<15)
-
 
-#if 0  /* Now defined in "mm.h" */
-/*
- * This used to be an unsigned short...
- * 
- *                         -- Cort
- */
-/*typedef unsigned short mem_map_t;*/
+#define clear_page(page)        memset((void *)(page), 0, PAGE_SIZE)
+#define copy_page(to,from)	memcpy((void *)(to), (void *)(from), PAGE_SIZE)
+/* map phys->virtual and virtual->phys */
+#define __pa(x)			((unsigned long)(x)-PAGE_OFFSET)
+#define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
 
-typedef struct {
-	unsigned count:30,
-		 dirty:1,
-		 reserved:1;
-} mem_map_t;
-#endif
-
-/* Certain architectures need to do special things when pte's
- * within a page table are directly modified.  Thus, the following
- * hook is made available.
- */
-#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
+#define MAP_NR(addr)	(__pa(addr) >> PAGE_SHIFT)
+#define MAP_PAGE_RESERVED	(1<<15)
 
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/pgtable.h linux/include/asm-ppc/pgtable.h
--- v2.1.15/linux/include/asm-ppc/pgtable.h	Wed Oct  9 08:55:23 1996
+++ linux/include/asm-ppc/pgtable.h	Wed Dec 18 10:54:09 1996
@@ -5,75 +5,16 @@
 #include <asm/page.h>
 #include <asm/mmu.h>
 
-/*
- * Memory management on the PowerPC is a software emulation of the i386
- * MMU folded onto the PowerPC hardware MMU.  The emulated version looks
- * and behaves like the two-level i386 MMU.  Entries from these tables
- * are merged into the PowerPC hashed MMU tables, on demand, treating the
- * hashed tables like a special cache.
- *
- * Since the PowerPC does not have separate kernel and user address spaces,
- * the user virtual address space must be a [proper] subset of the kernel
- * space.  Thus, all tasks will have a specific virtual mapping for the
- * user virtual space and a common mapping for the kernel space.  The
- * simplest way to split this was literally in half.  Also, life is so
- * much simpler for the kernel if the machine hardware resources are
- * always mapped in.  Thus, some additional space is given up to the
- * kernel space to accommodate this.
- *
- * CAUTION! Some of the trade-offs make sense for the PreP platform on
- * which this code was originally developed.  When it migrates to other
- * PowerPC environments, some of the assumptions may fail and the whole
- * setup may need to be reevaluated.
- *
- * On the PowerPC, page translations are kept in a hashed table.  There
- * is exactly one of these tables [although the architecture supports
- * an arbitrary number].  Page table entries move in/out of this hashed
- * structure on demand, with the kernel filling in entries as they are
- * needed.  Just where a page table entry hits in the hashed table is a
- * function of the hashing which is in turn based on the upper 4 bits
- * of the logical address.  These 4 bits address a "virtual segment id"
- * which is unique per task/page combination for user addresses and
- * fixed for the kernel addresses.  Thus, the kernel space can be simply
- * shared [indeed at low overhead] among all tasks.
- *
- * The basic virtual address space is thus:
- *
- * 0x0XXXXXX  --+
- * 0x1XXXXXX    |
- * 0x2XXXXXX    |  User address space. 
- * 0x3XXXXXX    |
- * 0x4XXXXXX    |
- * 0x5XXXXXX    |
- * 0x6XXXXXX    |
- * 0x7XXXXXX  --+
- * 0x8XXXXXX       PCI/ISA I/O space
- * 0x9XXXXXX  --+
- * 0xAXXXXXX    |  Kernel virtual memory
- * 0xBXXXXXX  --+
- * 0xCXXXXXX       PCI/ISA Memory space
- * 0xDXXXXXX
- * 0xEXXXXXX
- * 0xFXXXXXX       Board I/O space
- *
- * CAUTION!  One of the real problems here is keeping the software
- * managed tables coherent with the hardware hashed tables.  When
- * the software decides to update the table, it's normally easy to
- * update the hardware table.  But when the hardware tables need
- * changed, e.g. as the result of a page fault, it's more difficult
- * to reflect those changes back into the software entries.  Currently,
- * this process is quite crude, with updates causing the entire set
- * of tables to become invalidated.  Some performance could certainly
- * be regained by improving this.
- *
- * The Linux memory management assumes a three-level page table setup. On
- * the i386, 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
- * i386 mmu expects.
- *
- * This file contains the functions and defines necessary to modify and use
- * the i386 page table tree.
- */
+inline void flush_tlb(void);
+inline void flush_tlb_all(void);
+inline void flush_tlb_mm(struct mm_struct *mm);
+inline void flush_tlb_page(struct vm_area_struct *vma, long vmaddr);
+inline void flush_tlb_range(struct mm_struct *mm, long start, long end);
+inline void flush_page_to_ram(unsigned long);
+inline void really_flush_cache_all(void);
+
+/* only called from asm in head.S, so why bother? */
+/*void MMU_init(void);*/
 
 /* PMD_SHIFT determines the size of the area a second-level page table can map */
 #define PMD_SHIFT	22
@@ -100,8 +41,17 @@
  * 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 ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+/* this must be a decent size since the ppc bat's can map only certain sizes
+   but these can be different from the physical ram size configured.
+   bat mapping must map at least physical ram size and vmalloc start addr
+   must beging AFTER the area mapped by the bat.
+   32 works for now, but may need to be changed with larger differences.
+   offset = next greatest bat mapping to ramsize - ramsize
+   (ie would be 0 if batmapping = ramsize)
+        -- Cort 10/6/96
+   */
+#define VMALLOC_OFFSET	(32*1024*1024)
+#define VMALLOC_START ((((long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
 
 #define _PAGE_PRESENT	0x001
@@ -146,36 +96,16 @@
 #define __S111	PAGE_SHARED
 
 /*
- * TLB invalidation:
- *
- *  - invalidate() invalidates the current mm struct TLBs
- *  - invalidate_all() invalidates all processes TLBs
- *  - invalidate_mm(mm) invalidates the specified mm context TLB's
- *  - invalidate_page(mm, vmaddr) invalidates one page
- *  - invalidate_range(mm, start, end) invalidates a range of pages
- *
- * FIXME: This could be done much better!
- */
-
-#define invalidate_all() printk("invalidate_all()\n");invalidate()
-#if 0
-#define invalidate_mm(mm_struct) \
-do { if ((mm_struct) == current->mm) invalidate(); else printk("Can't invalidate_mm(%x)\n", mm_struct);} while (0)
-#define invalidate_page(mm_struct,addr) \
-do { if ((mm_struct) == current->mm) invalidate(); else printk("Can't invalidate_page(%x,%x)\n", mm_struct, addr);} while (0)
-#define invalidate_range(mm_struct,start,end) \
-do { if ((mm_struct) == current->mm) invalidate(); else printk("Can't invalidate_range(%x,%x,%x)\n", mm_struct, start, end);} while (0)
-#endif
-
-/*
- * Define this if things work differently on an i386 and an i486:
- * it will (on an i486) warn about kernel memory accesses that are
+ * Define this if things work differently on a i386 and a i486:
+ * it will (on a i486) warn about kernel memory accesses that are
  * done without a 'verify_area(VERIFY_WRITE,..)'
  */
 #undef CONFIG_TEST_VERIFY_AREA
 
+#if 0
 /* page table for 0-4MB for everybody */
 extern unsigned long pg0[1024];
+#endif
 
 /*
  * BAD_PAGETABLE is used when we need a bogus page-table, while
@@ -187,11 +117,11 @@
 extern pte_t __bad_page(void);
 extern pte_t * __bad_pagetable(void);
 
-extern unsigned long __zero_page(void);
+extern unsigned long empty_zero_page[1024];
 
 #define BAD_PAGETABLE __bad_pagetable()
 #define BAD_PAGE __bad_page()
-#define ZERO_PAGE __zero_page()
+#define ZERO_PAGE ((unsigned long) empty_zero_page)
 
 /* number of bits that fit into a memory pointer */
 #define BITS_PER_PTR			(8*sizeof(unsigned long))
@@ -218,29 +148,13 @@
 	} \
 } while (0)
 
-extern unsigned long high_memory;
+/* comes from include/linux/mm.h now -- Cort */
+/*extern void *high_memory;*/
 
 extern inline int pte_none(pte_t pte)		{ return !pte_val(pte); }
 extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & _PAGE_PRESENT; }
-#if 0
-extern inline int pte_inuse(pte_t *ptep)	{ return mem_map[MAP_NR(ptep)].reserved; }
-/*extern inline int pte_inuse(pte_t *ptep)	{ return mem_map[MAP_NR(ptep)] != 1; }*/
-#endif
 extern inline void pte_clear(pte_t *ptep)	{ pte_val(*ptep) = 0; }
-#if 0
-extern inline void pte_reuse(pte_t * ptep)
-{
-	if (!mem_map[MAP_NR(ptep)].reserved)
-		mem_map[MAP_NR(ptep)].count++;
-}
-#endif
-/*
-   extern inline void pte_reuse(pte_t * ptep)
-{
-	if (!(mem_map[MAP_NR(ptep)] & MAP_PAGE_RESERVED))
-		mem_map[MAP_NR(ptep)]++;
-}
-*/
+
 extern inline int pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
 extern inline int pmd_bad(pmd_t pmd)		{ return (pmd_val(pmd) & ~PAGE_MASK) != _PAGE_TABLE; }
 extern inline int pmd_present(pmd_t pmd)	{ return pmd_val(pmd) & _PAGE_PRESENT; }
@@ -256,19 +170,8 @@
 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; }
-#if 0
-/*extern inline int pgd_inuse(pgd_t * pgdp)	{ return mem_map[MAP_NR(pgdp)] != 1; }*/
-extern inline int pgd_inuse(pgd_t *pgdp)	{ return mem_map[MAP_NR(pgdp)].reserved;  }
-#endif
 extern inline void pgd_clear(pgd_t * pgdp)	{ }
 
-/*
-extern inline void pgd_reuse(pgd_t * pgdp)
-{
-	if (!mem_map[MAP_NR(pgdp)].reserved)
-		mem_map[MAP_NR(pgdp)].count++;
-}
-*/
 
 /*
  * The following only work if pte_present() is true.
@@ -298,15 +201,24 @@
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
+
+/* Certain architectures need to do special things when pte's
+ * within a page table are directly modified.  Thus, the following
+ * hook is made available.
+ */
+#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
+
+static pte_t mk_pte_phys(unsigned long page, pgprot_t pgprot)
+{ pte_t pte; pte_val(pte) = (page) | pgprot_val(pgprot); return pte; }
+/*#define mk_pte_phys(physpage, pgprot) \
+({ pte_t __pte; pte_val(__pte) = physpage + pgprot_val(pgprot); __pte; })*/
+
 extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
 { pte_t pte; pte_val(pte) = page | pgprot_val(pgprot); return pte; }
 
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
 
-/*extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
-{ pmd_val(*pmdp) = _PAGE_TABLE | ((((unsigned long) ptep) - PAGE_OFFSET) << (32-PAGE_SHIFT)); }
-*/
 extern inline unsigned long pte_page(pte_t pte)
 { return pte_val(pte) & PAGE_MASK; }
 
@@ -342,75 +254,6 @@
 {
 	free_page((unsigned long) pte);
 }
-/*extern inline void pte_free_kernel(pte_t * pte)
-{
-	mem_map[MAP_NR(pte)] = 1;
-	free_page((unsigned long) pte);
-}
-*/
-
-/*
-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_free_page(GFP_KERNEL);
-		if (pmd_none(*pmd)) {
-			if (page) {
-				pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page;
-				mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
-				return page + address;
-			}
-			pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
-			return NULL;
-		}
-		free_page((unsigned long) page);
-	}
-	if (pmd_bad(*pmd)) {
-		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-		pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE;
-		return NULL;
-	}
-	return (pte_t *) pmd_page(*pmd) + address;
-}*/
-/*
-extern inline pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
-{
-printk("pte_alloc_kernel pmd = %08X, address = %08X\n", pmd, address);
-	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
-printk("address now = %08X\n", address);
-	if (pmd_none(*pmd)) {
-		pte_t *page;
-printk("pmd_none(*pmd) true\n");
-		page = (pte_t *) get_free_page(GFP_KERNEL);
-printk("page = %08X after get_free_page(%08X)\n",page,GFP_KERNEL);
-		if (pmd_none(*pmd)) {
-printk("pmd_none(*pmd=%08X) still\n",*pmd);		  
-			if (page) {
-printk("page true = %08X\n",page);			  
-				pmd_set(pmd, page);
-printk("pmd_set(%08X,%08X)\n",pmd,page);			  
-				mem_map[MAP_NR(page)].reserved = 1;
-printk("did mem_map\n",pmd,page);			  
-				return page + address;
-			}
-printk("did pmd_set(%08X, %08X\n",pmd,BAD_PAGETABLE);			  
-			pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
-			return NULL;
-		}
-printk("did free_page(%08X)\n",page);			  		
-		free_page((unsigned long) page);
-	}
-	if (pmd_bad(*pmd)) {
-		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-		pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
-		return NULL;
-	}
-printk("returning pmd_page(%08X) + %08X\n",pmd_page(*pmd) , address);	  
-
-	return (pte_t *) pmd_page(*pmd) + address;
-}
-*/
 extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address)
 {
 	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
@@ -501,30 +344,15 @@
 	return (pgd_t *) get_free_page(GFP_KERNEL);
 }
 
-extern pgd_t swapper_pg_dir[1024*8];
-/*extern pgd_t *swapper_pg_dir;*/
+extern pgd_t swapper_pg_dir[1024];
 
 /*
  * Software maintained MMU tables may have changed -- update the
  * hardware [aka cache]
  */
 extern inline void update_mmu_cache(struct vm_area_struct * vma,
-	unsigned long address, pte_t _pte)
-{
-#if 0
-	printk("Update MMU cache - VMA: %x, Addr: %x, PTE: %x\n", vma, address, *(long *)&_pte);
-	_printk("Update MMU cache - VMA: %x, Addr: %x, PTE: %x\n", vma, address, *(long *)&_pte);
-/*	MMU_hash_page(&(vma->vm_task)->tss, address & PAGE_MASK, (pte *)&_pte);*/
-#endif	
-	MMU_hash_page(&(current)->tss, address & PAGE_MASK, (pte *)&_pte);
-
-}
-
-
-#ifdef _SCHED_INIT_
-#define INIT_MMAP { &init_task, 0, 0x40000000, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }
+	unsigned long address, pte_t _pte);
 
-#endif	
 
 #define SWP_TYPE(entry) (((entry) >> 1) & 0x7f)
 #define SWP_OFFSET(entry) ((entry) >> 8)
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/pnp.h linux/include/asm-ppc/pnp.h
--- v2.1.15/linux/include/asm-ppc/pnp.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-ppc/pnp.h	Wed Dec 18 10:54:09 1996
@@ -0,0 +1,641 @@
+/* 11/02/95                                                                   */
+/*----------------------------------------------------------------------------*/
+/*      Plug and Play header definitions                                      */
+/*----------------------------------------------------------------------------*/
+
+/* Structure map for PnP on PowerPC Reference Platform                        */
+/* See Plug and Play ISA Specification, Version 1.0, May 28, 1993.  It        */
+/* (or later versions) is available on Compuserve in the PLUGPLAY area.       */
+/* This code has extensions to that specification, namely new short and       */
+/* long tag types for platform dependent information                          */
+
+/* Warning: LE notation used throughout this file                             */
+
+/* For enum's: if given in hex then they are bit significant, i.e.            */
+/* only one bit is on for each enum                                           */
+
+#ifndef _PNP_
+#define _PNP_
+
+#define MAX_MEM_REGISTERS 9
+#define MAX_IO_PORTS 20
+#define MAX_IRQS 7
+#define MAX_DMA_CHANNELS 7
+
+/* Interrupt controllers */
+
+#define PNPinterrupt0 "PNP0000"      /* AT Interrupt Controller               */
+#define PNPinterrupt1 "PNP0001"      /* EISA Interrupt Controller             */
+#define PNPinterrupt2 "PNP0002"      /* MCA Interrupt Controller              */
+#define PNPinterrupt3 "PNP0003"      /* APIC                                  */
+#define PNPExtInt     "IBM000D"      /* PowerPC Extended Interrupt Controller */
+
+/* Timers */
+
+#define PNPtimer0     "PNP0100"      /* AT Timer                              */
+#define PNPtimer1     "PNP0101"      /* EISA Timer                            */
+#define PNPtimer2     "PNP0102"      /* MCA Timer                             */
+
+/* DMA controllers */
+
+#define PNPdma0       "PNP0200"      /* AT DMA Controller                     */
+#define PNPdma1       "PNP0201"      /* EISA DMA Controller                   */
+#define PNPdma2       "PNP0202"      /* MCA DMA Controller                    */
+
+/* start of August 15, 1994 additions */
+/* CMOS */
+#define PNPCMOS       "IBM0009"      /* CMOS                                  */
+
+/* L2 Cache */
+#define PNPL2         "IBM0007"      /* L2 Cache                              */
+
+/* NVRAM */
+#define PNPNVRAM      "IBM0008"      /* NVRAM                                 */
+
+/* Power Management */
+#define PNPPM         "IBM0005"      /* Power Management                      */
+/* end of August 15, 1994 additions */
+
+/* Keyboards */
+
+#define PNPkeyboard0  "PNP0300"      /* IBM PC/XT KB Cntlr (83 key, no mouse) */
+#define PNPkeyboard1  "PNP0301"      /* Olivetti ICO (102 key)                */
+#define PNPkeyboard2  "PNP0302"      /* IBM PC/AT KB Cntlr (84 key)           */
+#define PNPkeyboard3  "PNP0303"      /* IBM Enhanced (101/2 key, PS/2 mouse)  */
+#define PNPkeyboard4  "PNP0304"      /* Nokia 1050 KB Cntlr                   */
+#define PNPkeyboard5  "PNP0305"      /* Nokia 9140 KB Cntlr                   */
+#define PNPkeyboard6  "PNP0306"      /* Standard Japanese KB Cntlr            */
+#define PNPkeyboard7  "PNP0307"      /* Microsoft Windows (R) KB Cntlr        */
+
+/* Parallel port controllers */
+
+#define PNPparallel0 "PNP0400"       /* Standard LPT Parallel Port            */
+#define PNPparallel1 "PNP0401"       /* ECP Parallel Port                     */
+#define PNPepp       "IBM001C"       /* EPP Parallel Port                     */
+
+/* Serial port controllers */
+
+#define PNPserial0   "PNP0500"       /* Standard PC Serial port               */
+#define PNPSerial1   "PNP0501"       /* 16550A Compatible Serial port         */
+
+/* Disk controllers */
+
+#define PNPdisk0     "PNP0600"       /* Generic ESDI/IDE/ATA Compat HD Cntlr  */
+#define PNPdisk1     "PNP0601"       /* Plus Hardcard II                      */
+#define PNPdisk2     "PNP0602"       /* Plus Hardcard IIXL/EZ                 */
+
+/* Diskette controllers */
+
+#define PNPdiskette0 "PNP0700"       /* PC Standard Floppy Disk Controller    */
+
+/* Display controllers */
+
+#define PNPdisplay0  "PNP0900"       /* VGA Compatible                        */
+#define PNPdisplay1  "PNP0901"       /* Video Seven VGA                       */
+#define PNPdisplay2  "PNP0902"       /* 8514/A Compatible                     */
+#define PNPdisplay3  "PNP0903"       /* Trident VGA                           */
+#define PNPdisplay4  "PNP0904"       /* Cirrus Logic Laptop VGA               */
+#define PNPdisplay5  "PNP0905"       /* Cirrus Logic VGA                      */
+#define PNPdisplay6  "PNP0906"       /* Tseng ET4000 or ET4000/W32            */
+#define PNPdisplay7  "PNP0907"       /* Western Digital VGA                   */
+#define PNPdisplay8  "PNP0908"       /* Western Digital Laptop VGA            */
+#define PNPdisplay9  "PNP0909"       /* S3                                    */
+#define PNPdisplayA  "PNP090A"       /* ATI Ultra Pro/Plus (Mach 32)          */
+#define PNPdisplayB  "PNP090B"       /* ATI Ultra (Mach 8)                    */
+#define PNPdisplayC  "PNP090C"       /* XGA Compatible                        */
+#define PNPdisplayD  "PNP090D"       /* ATI VGA Wonder                        */
+#define PNPdisplayE  "PNP090E"       /* Weitek P9000 Graphics Adapter         */
+#define PNPdisplayF  "PNP090F"       /* Oak Technology VGA                    */
+
+/* Peripheral busses */
+
+#define PNPbuses0    "PNP0A00"       /* ISA Bus                               */
+#define PNPbuses1    "PNP0A01"       /* EISA Bus                              */
+#define PNPbuses2    "PNP0A02"       /* MCA Bus                               */
+#define PNPbuses3    "PNP0A03"       /* PCI Bus                               */
+#define PNPbuses4    "PNP0A04"       /* VESA/VL Bus                           */
+
+/* RTC, BIOS, planar devices */
+
+#define PNPspeaker0  "PNP0800"       /* AT Style Speaker Sound                */
+#define PNPrtc0      "PNP0B00"       /* AT RTC                                */
+#define PNPpnpbios0  "PNP0C00"       /* PNP BIOS (only created by root enum)  */
+#define PNPpnpbios1  "PNP0C01"       /* System Board Memory Device            */
+#define PNPpnpbios2  "PNP0C02"       /* Math Coprocessor                      */
+#define PNPpnpbios3  "PNP0C03"       /* PNP BIOS Event Notification Interrupt */
+
+/* PCMCIA controller */
+
+#define PNPpcmcia0   "PNP0E00"       /* Intel 82365 Compatible PCMCIA Cntlr   */
+
+/* Mice */
+
+#define PNPmouse0    "PNP0F00"       /* Microsoft Bus Mouse                   */
+#define PNPmouse1    "PNP0F01"       /* Microsoft Serial Mouse                */
+#define PNPmouse2    "PNP0F02"       /* Microsoft Inport Mouse                */
+#define PNPmouse3    "PNP0F03"       /* Microsoft PS/2 Mouse                  */
+#define PNPmouse4    "PNP0F04"       /* Mousesystems Mouse                    */
+#define PNPmouse5    "PNP0F05"       /* Mousesystems 3 Button Mouse - COM2    */
+#define PNPmouse6    "PNP0F06"       /* Genius Mouse - COM1                   */
+#define PNPmouse7    "PNP0F07"       /* Genius Mouse - COM2                   */
+#define PNPmouse8    "PNP0F08"       /* Logitech Serial Mouse                 */
+#define PNPmouse9    "PNP0F09"       /* Microsoft Ballpoint Serial Mouse      */
+#define PNPmouseA    "PNP0F0A"       /* Microsoft PNP Mouse                   */
+#define PNPmouseB    "PNP0F0B"       /* Microsoft PNP Ballpoint Mouse         */
+
+/* Modems */
+
+#define PNPmodem0    "PNP9000"       /* Specific IDs TBD                      */
+
+/* Network controllers */
+
+#define PNPnetworkC9 "PNP80C9"       /* IBM Token Ring                        */
+#define PNPnetworkCA "PNP80CA"       /* IBM Token Ring II                     */
+#define PNPnetworkCB "PNP80CB"       /* IBM Token Ring II/Short               */
+#define PNPnetworkCC "PNP80CC"       /* IBM Token Ring 4/16Mbs                */
+#define PNPnetwork27 "PNP8327"       /* IBM Token Ring (All types)            */
+#define PNPnetworket "IBM0010"       /* IBM Ethernet used by Power PC         */
+#define PNPneteisaet "IBM2001"       /* IBM Ethernet EISA adapter             */
+#define PNPAMD79C970 "IBM0016"       /* AMD 79C970 (PCI Ethernet)             */
+
+/* SCSI controllers */
+
+#define PNPscsi0     "PNPA000"       /* Adaptec 154x Compatible SCSI Cntlr    */
+#define PNPscsi1     "PNPA001"       /* Adaptec 174x Compatible SCSI Cntlr    */
+#define PNPscsi2     "PNPA002"       /* Future Domain 16-700 Compat SCSI Cntlr*/
+#define PNPscsi3     "PNPA003"       /* Panasonic CDROM Adapter (SBPro/SB16)  */
+#define PNPscsiF     "IBM000F"       /* NCR 810 SCSI Controller               */
+#define PNPscsi825   "IBM001B"       /* NCR 825 SCSI Controller               */
+#define PNPscsi875   "IBM0018"       /* NCR 875 SCSI Controller               */
+
+/* Sound/Video, Multimedia */
+
+#define PNPmm0       "PNPB000"       /* Sound Blaster Compatible Sound Device */
+#define PNPmm1       "PNPB001"       /* MS Windows Sound System Compat Device */
+#define PNPmmF       "IBM000E"       /* Crystal CS4231 Audio Device           */
+#define PNPv7310     "IBM0015"       /* ASCII V7310 Video Capture Device      */
+#define PNPmm4232    "IBM0017"       /* Crystal CS4232 Audio Device           */
+#define PNPpmsyn     "IBM001D"       /* YMF 289B chip (Yamaha)                */
+#define PNPgp4232    "IBM0012"       /* Crystal CS4232 Game Port              */
+#define PNPmidi4232  "IBM0013"       /* Crystal CS4232 MIDI                   */
+
+/* Operator Panel */
+#define PNPopctl     "IBM000B"       /* Operator's panel                      */
+
+/* Service Processor */
+#define PNPsp        "IBM0011"       /* IBM Service Processor                 */
+#define PNPLTsp      "IBM001E"       /* Lightning/Terlingua Support Processor */
+#define PNPLTmsp     "IBM001F"       /* Lightning/Terlingua Mini-SP           */
+
+/* Memory Controller */
+#define PNPmemctl    "IBM000A"       /* Memory controller                     */
+
+/* Graphics Assist */
+#define PNPg_assist  "IBM0014"       /* Graphics Assist                       */
+
+/* Miscellaneous Device Controllers */
+#define PNPtablet    "IBM0019"       /* IBM Tablet Controller                 */
+
+/* PNP Packet Handles */
+
+#define S1_Packet                0x0A   /* Version resource                   */
+#define S2_Packet                0x15   /* Logical DEVID (without flags)      */
+#define S2_Packet_flags          0x16   /* Logical DEVID (with flags)         */
+#define S3_Packet                0x1C   /* Compatible device ID               */
+#define S4_Packet                0x22   /* IRQ resource (without flags)       */
+#define S4_Packet_flags          0x23   /* IRQ resource (with flags)          */
+#define S5_Packet                0x2A   /* DMA resource                       */
+#define S6_Packet                0x30   /* Depend funct start (w/o priority)  */
+#define S6_Packet_priority       0x31   /* Depend funct start (w/ priority)   */
+#define S7_Packet                0x38   /* Depend funct end                   */
+#define S8_Packet                0x47   /* I/O port resource (w/o fixed loc)  */
+#define S9_Packet_fixed          0x4B   /* I/O port resource (w/ fixed loc)   */
+#define S14_Packet               0x71   /* Vendor defined                     */
+#define S15_Packet               0x78   /* End of resource (w/o checksum)     */
+#define S15_Packet_checksum      0x79   /* End of resource (w/ checksum)      */
+#define L1_Packet                0x81   /* Memory range                       */
+#define L1_Shadow                0x20   /* Memory is shadowable               */
+#define L1_32bit_mem             0x18   /* 32-bit memory only                 */
+#define L1_8_16bit_mem           0x10   /* 8- and 16-bit supported            */
+#define L1_Decode_Hi             0x04   /* decode supports high address       */
+#define L1_Cache                 0x02   /* read cacheable, write-through      */
+#define L1_Writeable             0x01   /* Memory is writeable                */
+#define L2_Packet                0x82   /* ANSI ID string                     */
+#define L3_Packet                0x83   /* Unicode ID string                  */
+#define L4_Packet                0x84   /* Vendor defined                     */
+#define L5_Packet                0x85   /* Large I/O                          */
+#define L6_Packet                0x86   /* 32-bit Fixed Loc Mem Range Desc    */
+#define END_TAG                  0x78   /* End of resource                    */
+#define DF_START_TAG             0x30   /* Dependent function start           */
+#define DF_START_TAG_priority    0x31   /* Dependent function start           */
+#define DF_END_TAG               0x38   /* Dependent function end             */
+#define SUBOPTIMAL_CONFIGURATION 0x2    /* Priority byte sub optimal config   */
+
+/* Device Base Type Codes */
+
+typedef enum _PnP_BASE_TYPE {
+  Reserved = 0,
+  MassStorageDevice = 1,
+  NetworkInterfaceController = 2,
+  DisplayController = 3,
+  MultimediaController = 4,
+  MemoryController = 5,
+  BridgeController = 6,
+  CommunicationsDevice = 7,
+  SystemPeripheral = 8,
+  InputDevice = 9,
+  ServiceProcessor = 0x0A,              /* 11/2/95                            */
+  } PnP_BASE_TYPE;
+
+/* Device Sub Type Codes */
+
+typedef enum _PnP_SUB_TYPE {
+  SCSIController = 0,
+  IDEController = 1,
+  FloppyController = 2,
+  IPIController = 3,
+  OtherMassStorageController = 0x80,
+
+  EthernetController = 0,
+  TokenRingController = 1,
+  FDDIController = 2,
+  OtherNetworkController = 0x80,
+
+  VGAController= 0,
+  SVGAController= 1,
+  XGAController= 2,
+  OtherDisplayController = 0x80,
+
+  VideoController = 0,
+  AudioController = 1,
+  OtherMultimediaController = 0x80,
+
+  RAM = 0,
+  FLASH = 1,
+  OtherMemoryDevice = 0x80,
+
+  HostProcessorBridge = 0,
+  ISABridge = 1,
+  EISABridge = 2,
+  MicroChannelBridge = 3,
+  PCIBridge = 4,
+  PCMCIABridge = 5,
+  VMEBridge = 6,
+  OtherBridgeDevice = 0x80,
+
+  RS232Device = 0,
+  ATCompatibleParallelPort = 1,
+  OtherCommunicationsDevice = 0x80,
+
+  ProgrammableInterruptController = 0,
+  DMAController = 1,
+  SystemTimer = 2,
+  RealTimeClock = 3,
+  L2Cache = 4,
+  NVRAM = 5,
+  PowerManagement = 6,
+  CMOS = 7,
+  OperatorPanel = 8,
+  ServiceProcessorClass1 = 9,
+  ServiceProcessorClass2 = 0xA,
+  ServiceProcessorClass3 = 0xB,
+  GraphicAssist = 0xC,
+  SystemPlanar = 0xF,                   /* 10/5/95                            */
+  OtherSystemPeripheral = 0x80,
+
+  KeyboardController = 0,
+  Digitizer = 1,
+  MouseController = 2,
+  TabletController = 3,                 /* 10/27/95                           */
+  OtherInputController = 0x80,
+
+  GeneralMemoryController = 0,
+  } PnP_SUB_TYPE;
+
+/* Device Interface Type Codes */
+
+typedef enum _PnP_INTERFACE {
+  General = 0,
+  GeneralSCSI = 0,
+  GeneralIDE = 0,
+  ATACompatible = 1,
+
+  GeneralFloppy = 0,
+  Compatible765 = 1,
+  NS398_Floppy = 2,                     /* NS Super I/O wired to use index
+                                           register at port 398 and data
+                                           register at port 399               */
+  NS26E_Floppy = 3,                     /* Ports 26E and 26F                  */
+  NS15C_Floppy = 4,                     /* Ports 15C and 15D                  */
+  NS2E_Floppy = 5,                      /* Ports 2E and 2F                    */
+  CHRP_Floppy = 6,                      /* CHRP Floppy in PR*P system         */
+
+  GeneralIPI = 0,
+
+  GeneralEther = 0,
+  GeneralToken = 0,
+  GeneralFDDI = 0,
+
+  GeneralVGA = 0,
+  GeneralSVGA = 0,
+  GeneralXGA = 0,
+
+  GeneralVideo = 0,
+  GeneralAudio = 0,
+  CS4232Audio = 1,                      /* CS 4232 Plug 'n Play Configured    */
+
+  GeneralRAM = 0,
+  GeneralFLASH = 0,
+  PCIMemoryController = 0,              /* PCI Config Method                  */
+  RS6KMemoryController = 1,             /* RS6K Config Method                 */
+
+  GeneralHostBridge = 0,
+  GeneralISABridge = 0,
+  GeneralEISABridge = 0,
+  GeneralMCABridge = 0,
+  GeneralPCIBridge = 0,
+  PCIBridgeDirect = 0,
+  PCIBridgeIndirect = 1,
+  PCIBridgeRS6K = 2,
+  GeneralPCMCIABridge = 0,
+  GeneralVMEBridge = 0,
+
+  GeneralRS232 = 0,
+  COMx = 1,
+  Compatible16450 = 2,
+  Compatible16550 = 3,
+  NS398SerPort = 4,                     /* NS Super I/O wired to use index
+                                           register at port 398 and data
+                                           register at port 399               */
+  NS26ESerPort = 5,                     /* Ports 26E and 26F                  */
+  NS15CSerPort = 6,                     /* Ports 15C and 15D                  */
+  NS2ESerPort = 7,                      /* Ports 2E and 2F                    */
+
+  GeneralParPort = 0,
+  LPTx = 1,
+  NS398ParPort = 2,                     /* NS Super I/O wired to use index
+                                           register at port 398 and data
+                                           register at port 399               */
+  NS26EParPort = 3,                     /* Ports 26E and 26F                  */
+  NS15CParPort = 4,                     /* Ports 15C and 15D                  */
+  NS2EParPort = 5,                      /* Ports 2E and 2F                    */
+
+  GeneralPIC = 0,
+  ISA_PIC = 1,
+  EISA_PIC = 2,
+  MPIC = 3,
+  RS6K_PIC = 4,
+
+  GeneralDMA = 0,
+  ISA_DMA = 1,
+  EISA_DMA = 2,
+
+  GeneralTimer = 0,
+  ISA_Timer = 1,
+  EISA_Timer = 2,
+  GeneralRTC = 0,
+  ISA_RTC = 1,
+
+  StoreThruOnly = 1,
+  StoreInEnabled = 2,
+  RS6KL2Cache = 3,
+
+  IndirectNVRAM = 0,                    /* Indirectly addressed               */
+  DirectNVRAM = 1,                      /* Memory Mapped                      */
+  IndirectNVRAM24 = 2,                  /* Indirectly addressed - 24 bit      */
+
+  GeneralPowerManagement = 0,
+  EPOWPowerManagement = 1,
+  PowerControl = 2,                    // d1378
+
+  GeneralCMOS = 0,
+
+  GeneralOPPanel = 0,
+  HarddiskLight = 1,
+  CDROMLight = 2,
+  PowerLight = 3,
+  KeyLock = 4,
+  ANDisplay = 5,                        /* AlphaNumeric Display               */
+  SystemStatusLED = 6,                  /* 3 digit 7 segment LED              */
+  CHRP_SystemStatusLED = 7,             /* CHRP LEDs in PR*P system           */
+
+  GeneralServiceProcessor = 0,
+
+  TransferData = 1,
+  IGMC32 = 2,
+  IGMC64 = 3,
+
+  GeneralSystemPlanar = 0,              /* 10/5/95                            */
+
+  } PnP_INTERFACE;
+
+/* PnP resources */
+
+/* Compressed ASCII is 5 bits per char; 00001=A ... 11010=Z */
+
+typedef struct _SERIAL_ID {
+  unsigned char VendorID0;              /*    Bit(7)=0                        */
+                                        /*    Bits(6:2)=1st character in      */
+                                        /*       compressed ASCII             */
+                                        /*    Bits(1:0)=2nd character in      */
+                                        /*       compressed ASCII bits(4:3)   */
+  unsigned char VendorID1;              /*    Bits(7:5)=2nd character in      */
+                                        /*       compressed ASCII bits(2:0)   */
+                                        /*    Bits(4:0)=3rd character in      */
+                                        /*       compressed ASCII             */
+  unsigned char VendorID2;              /* Product number - vendor assigned   */
+  unsigned char VendorID3;              /* Product number - vendor assigned   */
+
+/* Serial number is to provide uniqueness if more than one board of same      */
+/* type is in system.  Must be "FFFFFFFF" if feature not supported.           */
+
+  unsigned char Serial0;                /* Unique serial number bits (7:0)    */
+  unsigned char Serial1;                /* Unique serial number bits (15:8)   */
+  unsigned char Serial2;                /* Unique serial number bits (23:16)  */
+  unsigned char Serial3;                /* Unique serial number bits (31:24)  */
+  unsigned char Checksum;
+  } SERIAL_ID;
+
+typedef enum _PnPItemName {
+  Unused = 0,
+  PnPVersion = 1,
+  LogicalDevice = 2,
+  CompatibleDevice = 3,
+  IRQFormat = 4,
+  DMAFormat = 5,
+  StartDepFunc = 6,
+  EndDepFunc = 7,
+  IOPort = 8,
+  FixedIOPort = 9,
+  Res1 = 10,
+  Res2 = 11,
+  Res3 = 12,
+  SmallVendorItem = 14,
+  EndTag = 15,
+  MemoryRange = 1,
+  ANSIIdentifier = 2,
+  UnicodeIdentifier = 3,
+  LargeVendorItem = 4,
+  MemoryRange32 = 5,
+  MemoryRangeFixed32 = 6,
+  } PnPItemName;
+
+/* Define a bunch of access functions for the bits in the tag field */
+
+/* Tag type - 0 = small; 1 = large */
+#define tag_type(t) (((t) & 0x80)>>7)
+#define set_tag_type(t,v) (t = (t & 0x7f) | ((v)<<7))
+
+/* Small item name is 4 bits - one of PnPItemName enum above */
+#define tag_small_item_name(t) (((t) & 0x78)>>3)
+#define set_tag_small_item_name(t,v) (t = (t & 0x07) | ((v)<<3))
+
+/* Small item count is 3 bits - count of further bytes in packet */
+#define tag_small_count(t) ((t) & 0x07)
+#define set_tag_count(t,v) (t = (t & 0x78) | (v))
+
+/* Large item name is 7 bits - one of PnPItemName enum above */
+#define tag_large_item_name(t) ((t) & 0x7f)
+#define set_tag_large_item_name(t,v) (t = (t | 0x80) | (v))
+
+/* a PnP resource is a bunch of contiguous TAG packets ending with an end tag */
+
+typedef union _PnP_TAG_PACKET {
+  struct _S1_Pack{                      /* VERSION PACKET                     */
+    unsigned char Tag;                  /* small tag = 0x0a                   */
+    unsigned char Version[2];           /* PnP version, Vendor version        */
+    } S1_Pack;
+
+  struct _S2_Pack{                      /* LOGICAL DEVICE ID PACKET           */
+    unsigned char Tag;                  /* small tag = 0x15 or 0x16           */
+    unsigned char DevId[4];             /* Logical device id                  */
+    unsigned char Flags[2];             /* bit(0) boot device;                */
+                                        /* bit(7:1) cmd in range x31-x37      */
+                                        /* bit(7:0) cmd in range x28-x3f (opt)*/
+    } S2_Pack;
+
+  struct _S3_Pack{                      /* COMPATIBLE DEVICE ID PACKET        */
+    unsigned char Tag;                  /* small tag = 0x1c                   */
+    unsigned char CompatId[4];          /* Compatible device id               */
+    } S3_Pack;
+
+  struct _S4_Pack{                      /* IRQ PACKET                         */
+    unsigned char Tag;                  /* small tag = 0x22 or 0x23           */
+    unsigned char IRQMask[2];           /* bit(0) is IRQ0, ...;               */
+                                        /* bit(0) is IRQ8 ...                 */
+    unsigned char IRQInfo;              /* optional; assume bit(0)=1; else    */
+                                        /*  bit(0) - high true edge sensitive */
+                                        /*  bit(1) - low true edge sensitive  */
+                                        /*  bit(2) - high true level sensitive*/
+                                        /*  bit(3) - low true level sensitive */
+                                        /*  bit(7:4) - must be 0              */
+    } S4_Pack;
+
+  struct _S5_Pack{                      /* DMA PACKET                         */
+    unsigned char Tag;                  /* small tag = 0x2a                   */
+    unsigned char DMAMask;              /* bit(0) is channel 0 ...            */
+    unsigned char DMAInfo;
+    } S5_Pack;
+
+  struct _S6_Pack{                      /* START DEPENDENT FUNCTION PACKET    */
+    unsigned char Tag;                  /* small tag = 0x30 or 0x31           */
+    unsigned char Priority;             /* Optional; if missing then x01; else*/
+                                        /*  x00 = best possible               */
+                                        /*  x01 = acceptible                  */
+                                        /*  x02 = sub-optimal but functional  */
+    } S6_Pack;
+
+  struct _S7_Pack{                      /* END DEPENDENT FUNCTION PACKET      */
+    unsigned char Tag;                  /* small tag = 0x38                   */
+    } S7_Pack;
+
+  struct _S8_Pack{                      /* VARIABLE I/O PORT PACKET           */
+    unsigned char Tag;                  /* small tag x47                      */
+    unsigned char IOInfo;               /* x0  = decode only bits(9:0);       */
+#define  ISAAddr16bit         0x01      /* x01 = decode bits(15:0)            */
+    unsigned char RangeMin[2];          /* Min base address                   */
+    unsigned char RangeMax[2];          /* Max base address                   */
+    unsigned char IOAlign;              /* base alignmt, incr in 1B blocks    */
+    unsigned char IONum;                /* number of contiguous I/O ports     */
+    } S8_Pack;
+
+  struct _S9_Pack{                      /* FIXED I/O PORT PACKET              */
+    unsigned char Tag;                  /* small tag = 0x4b                   */
+    unsigned char Range[2];             /* base address 10 bits               */
+    unsigned char IONum;                /* number of contiguous I/O ports     */
+    } S9_Pack;
+
+  struct _S14_Pack{                     /* VENDOR DEFINED PACKET              */
+    unsigned char Tag;                  /* small tag = 0x7m m = 1-7           */
+    union _S14_Data{
+      unsigned char Data[7];            /* Vendor defined                     */
+      struct _S14_PPCPack{              /* Pr*p s14 pack                      */
+         unsigned char Type;            /* 00=non-IBM                         */
+         unsigned char PPCData[6];      /* Vendor defined                     */
+        } S14_PPCPack;
+      } S14_Data;
+    } S14_Pack;
+
+  struct _S15_Pack{                     /* END PACKET                         */
+    unsigned char Tag;                  /* small tag = 0x78 or 0x79           */
+    unsigned char Check;                /* optional - checksum                */
+    } S15_Pack;
+
+  struct _L1_Pack{                      /* MEMORY RANGE PACKET                */
+    unsigned char Tag;                  /* large tag = 0x81                   */
+    unsigned char Count0;               /* x09                                */
+    unsigned char Count1;               /* x00                                */
+    unsigned char Data[9];              /* a variable array of bytes,         */
+                                        /* count in tag                       */
+    } L1_Pack;
+
+  struct _L2_Pack{                      /* ANSI ID STRING PACKET              */
+    unsigned char Tag;                  /* large tag = 0x82                   */
+    unsigned char Count0;               /* Length of string                   */
+    unsigned char Count1;
+    unsigned char Identifier[1];        /* a variable array of bytes,         */
+                                        /* count in tag                       */
+    } L2_Pack;
+
+  struct _L3_Pack{                      /* UNICODE ID STRING PACKET           */
+    unsigned char Tag;                  /* large tag = 0x83                   */
+    unsigned char Count0;               /* Length + 2 of string               */
+    unsigned char Count1;
+    unsigned char Country0;             /* TBD                                */
+    unsigned char Country1;             /* TBD                                */
+    unsigned char Identifier[1];        /* a variable array of bytes,         */
+                                        /* count in tag                       */
+    } L3_Pack;
+
+  struct _L4_Pack{                      /* VENDOR DEFINED PACKET              */
+    unsigned char Tag;                  /* large tag = 0x84                   */
+    unsigned char Count0;
+    unsigned char Count1;
+    union _L4_Data{
+      unsigned char Data[1];            /* a variable array of bytes,         */
+                                        /* count in tag                       */
+      struct _L4_PPCPack{               /* Pr*p L4 packet                     */
+         unsigned char Type;            /* 00=non-IBM                         */
+         unsigned char PPCData[1];      /* a variable array of bytes,         */
+                                        /* count in tag                       */
+        } L4_PPCPack;
+      } L4_Data;
+    } L4_Pack;
+
+  struct _L5_Pack{
+    unsigned char Tag;                  /* large tag = 0x85                   */
+    unsigned char Count0;               /* Count = 17                         */
+    unsigned char Count1;
+    unsigned char Data[17];
+    } L5_Pack;
+
+  struct _L6_Pack{
+    unsigned char Tag;                  /* large tag = 0x86                   */
+    unsigned char Count0;               /* Count = 9                          */
+    unsigned char Count1;
+    unsigned char Data[9];
+    } L6_Pack;
+
+  } PnP_TAG_PACKET;
+
+#endif  /* ndef _PNP_ */
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/posix_types.h linux/include/asm-ppc/posix_types.h
--- v2.1.15/linux/include/asm-ppc/posix_types.h	Mon Jul  8 14:19:04 1996
+++ linux/include/asm-ppc/posix_types.h	Wed Dec 18 10:54:09 1996
@@ -22,6 +22,7 @@
 typedef long		__kernel_clock_t;
 typedef int		__kernel_daddr_t;
 typedef char *		__kernel_caddr_t;
+typedef short             __kernel_ipc_pid_t;
 
 #ifdef __GNUC__
 typedef long long	__kernel_loff_t;
@@ -74,7 +75,7 @@
 #undef __FD_ZERO
 static __inline__ void __FD_ZERO(__kernel_fd_set *p)
 {
-	unsigned int *tmp = p->fds_bits;
+	unsigned int *tmp = (unsigned int *)p->fds_bits;
 	int i;
 
 	if (__builtin_constant_p(__FDSET_LONGS)) {
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/ppc_machine.h linux/include/asm-ppc/ppc_machine.h
--- v2.1.15/linux/include/asm-ppc/ppc_machine.h	Mon Jul  8 11:27:43 1996
+++ linux/include/asm-ppc/ppc_machine.h	Wed Dec 18 10:54:09 1996
@@ -5,6 +5,9 @@
 #ifndef _PPC_MACHINE_H_
 #define _PPC_MACHINE_H_ 
 
+#define KERNEL_STACK_SIZE (4096) /* usable stack -- not buffers at either end */
+#define KERNEL_STACK_MASK (~(KERNEL_STACK_SIZE-1))
+
 /* Bit encodings for Machine State Register (MSR) */
 #define MSR_POW		(1<<18)		/* Enable Power Management */
 #define MSR_TGPR	(1<<17)		/* TLB Update registers in use */
@@ -23,8 +26,8 @@
 #define MSR_RI		(1<<1)		/* Recoverable Exception */
 #define MSR_LE		(1<<0)		/* Little-Endian enable */
 
-#define MSR_		MSR_FP|MSR_FE0|MSR_FE1|MSR_ME
-#define MSR_USER	MSR_|MSR_PR|MSR_EE|MSR_IR|MSR_DR
+#define MSR_		MSR_FE0|MSR_FE1|MSR_ME|MSR_FP
+#define MSR_USER	MSR_FE0|MSR_FE1|MSR_ME|MSR_PR|MSR_EE|MSR_IR|MSR_DR
 
 /* Bit encodings for Hardware Implementation Register (HID0) */
 #define HID0_EMCP	(1<<31)		/* Enable Machine Check pin */
@@ -46,5 +49,8 @@
 #define HID0_DCI	(1<<10)		/* Data Cache Invalidate */
 #define HID0_SIED	(1<<7)		/* Serial Instruction Execution [Disable] */
 #define HID0_BHTE	(1<<2)		/* Branch History Table Enable */
- 
+
+/* fpscr settings */
+#define FPSCR_FX        (1<<31)
+#define FPSCR_FEX       (1<<30)
 #endif
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
--- v2.1.15/linux/include/asm-ppc/processor.h	Mon May 27 12:00:59 1996
+++ linux/include/asm-ppc/processor.h	Wed Dec 18 10:54:09 1996
@@ -5,8 +5,8 @@
  * PowerPC machine specifics
  */
 
-#ifndef _PPC_MACHINE_H_
-#define _PPC_MACHINE_H_ 
+#define KERNEL_STACK_SIZE (4096) /* usable stack -- not buffers at either end */
+#define KERNEL_STACK_MASK (~(KERNEL_STACK_SIZE-1))
 
 /* Bit encodings for Machine State Register (MSR) */
 #define MSR_POW		(1<<18)		/* Enable Power Management */
@@ -26,8 +26,8 @@
 #define MSR_RI		(1<<1)		/* Recoverable Exception */
 #define MSR_LE		(1<<0)		/* Little-Endian enable */
 
-#define MSR_		MSR_FP|MSR_FE0|MSR_FE1|MSR_ME
-#define MSR_USER	MSR_|MSR_PR|MSR_EE|MSR_IR|MSR_DR
+#define MSR_		MSR_FE0|MSR_FE1|MSR_ME|MSR_FP
+#define MSR_USER	MSR_FE0|MSR_FE1|MSR_ME|MSR_PR|MSR_EE|MSR_IR|MSR_DR
 
 /* Bit encodings for Hardware Implementation Register (HID0) */
 #define HID0_EMCP	(1<<31)		/* Enable Machine Check pin */
@@ -47,15 +47,20 @@
 #define HID0_DLOCK	(1<<12)		/* Data Cache Lock */
 #define HID0_ICFI	(1<<11)		/* Instruction Cache Flash Invalidate */
 #define HID0_DCI	(1<<10)		/* Data Cache Invalidate */
- 
-#endif
+#define HID0_SIED	(1<<7)		/* Serial Instruction Execution [Disable] */
+#define HID0_BHTE	(1<<2)		/* Branch History Table Enable */
 
-static inline void start_thread(struct pt_regs * regs, unsigned long eip, unsigned long esp)
-{
-  regs->nip = eip;
-  regs->gpr[1] = esp;
-  regs->msr = MSR_USER;
-}
+/* fpscr settings */
+#define FPSCR_FX        (1<<31)
+#define FPSCR_FEX       (1<<30)
+
+
+
+#ifndef __ASSEMBLY__
+/*
+ * PowerPC machine specifics
+ */
+extern inline void start_thread(struct pt_regs *, unsigned long, unsigned long );
 
 
 /*
@@ -69,7 +74,6 @@
 /*
  * Write Protection works right in supervisor mode on the PowerPC
  */
-
 #define wp_works_ok 1
 #define wp_works_ok__is_a_macro /* for versions in ksyms.c */
 
@@ -82,27 +86,42 @@
 #define TASK_SIZE	(0x80000000UL)
 
 struct thread_struct 
-   {
-   	unsigned long	ksp;		/* Kernel stack pointer */
-	unsigned long	*pg_tables;	/* MMU information */
-	unsigned long	segs[16];	/* MMU Segment registers */
-	unsigned long	last_pc;	/* PC when last entered system */
-	unsigned long	user_stack;	/* [User] Stack when entered kernel */
-	double		fpr[32];	/* Complete floating point set */
-	unsigned long	wchan;		/* Event task is sleeping on */
-	unsigned long	*regs;		/* Pointer to saved register state */
-   };
+{
+  unsigned long	ksp;		/* Kernel stack pointer */
+  unsigned long	*pg_tables;	/* MMU information */
+  unsigned long	segs[16];	/* MMU Segment registers */
+  unsigned long	last_pc;	/* PC when last entered system */
+  unsigned long	user_stack;	/* [User] Stack when entered kernel */
+  double       	fpr[32];	/* Complete floating point set */
+  unsigned long	wchan;		/* Event task is sleeping on */
+  unsigned long	*regs;		/* Pointer to saved register state */
+  unsigned long fp_used;	/* number of quantums fp was used */
+  unsigned long fs;		/* for get_fs() validation */
+  unsigned long expc;		/* exception handler addr (see fault.c) */
+  unsigned long excount;	/* exception handler count */
+};
+
 
 #define INIT_TSS  { \
+	sizeof(init_kernel_stack) + (long) &init_kernel_stack,\
+	(long *)swapper_pg_dir, {0}, \
 	0, 0, {0}, \
-	0, 0, {0}, \
+	0, 0, 0, \
+	KERNEL_DS, 0, 0 \
 }
 
 #define INIT_MMAP { &init_mm, 0, 0x40000000, \
 		      PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC }
 
+#ifdef KERNEL_STACK_BUFFER
+/* give a 1 page buffer below the stack - if change then change ppc_machine.h */
+#define alloc_kernel_stack()  \
+          (memset((void *)__get_free_pages(GFP_KERNEL,1,0),0,KERNEL_STACK_SIZE+PAGE_SIZE)+PAGE_SIZE)
+#define free_kernel_stack(page) free_pages((page)-PAGE_SIZE,1)
+#else
 #define alloc_kernel_stack()    get_free_page(GFP_KERNEL)
 #define free_kernel_stack(page) free_page((page))
+#endif
 
 /*
  * Return saved PC of a blocked thread. For now, this is the "user" PC
@@ -111,6 +130,14 @@
 {
 	return (t->last_pc);
 }
+
+#define _PROC_Motorola 0
+#define _PROC_IBM      1
+#define _PROC_Be       2
+
+int _Processor;
+
+#endif /* ASSEMBLY*/
 
 #endif
 
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/ptrace.h linux/include/asm-ppc/ptrace.h
--- v2.1.15/linux/include/asm-ppc/ptrace.h	Mon May 27 12:00:59 1996
+++ linux/include/asm-ppc/ptrace.h	Wed Dec 18 10:54:09 1996
@@ -1,7 +1,6 @@
 #ifndef _PPC_PTRACE_H
 #define _PPC_PTRACE_H
 
-
 /*
  * This struct defines the way the registers are stored on the
  * kernel stack during a system call or other kernel entry.
@@ -21,27 +20,28 @@
  */
 
 struct pt_regs {
-	unsigned long _overhead[14]; /* Callee's SP,LR,params */
-	unsigned long gpr[32];
-	unsigned long nip;
-	unsigned long msr;
-	unsigned long ctr;
-	unsigned long link;
-	unsigned long ccr;
-	unsigned long xer;
-	unsigned long dar;	/* Fault registers */
-	unsigned long dsisr;
-	unsigned long hash1, hash2;
-	unsigned long imiss, dmiss;
-	unsigned long icmp, dcmp;
-	unsigned long orig_gpr3; /* Used for restarting system calls */
-	unsigned long result;    /* Result of a system call */
-	double        fpr[4];    /* Caution! Only FP0-FP3 save on interrupts */
-	double        fpcsr;
-	unsigned long trap;	/* Reason for being here */
-	unsigned long marker;	/* Should have DEADDEAD */
-	unsigned long _underhead[20]; /* Callee's register save area */
-	unsigned long edx;	/* for binfmt_elf.c which wants edx */
+  unsigned long _overhead[14]; /* Callee's SP,LR,params */
+  unsigned long gpr[32];
+  unsigned long nip;
+  unsigned long msr;
+  unsigned long ctr;
+  unsigned long link;
+  unsigned long ccr;
+  unsigned long xer;
+  unsigned long dar;	/* Fault registers */
+  unsigned long dsisr;
+  unsigned long srr1;
+  unsigned long srr0;
+  unsigned long hash1, hash2;
+  unsigned long imiss, dmiss;
+  unsigned long icmp, dcmp;
+  unsigned long orig_gpr3; /* Used for restarting system calls */
+  unsigned long result;    /* Result of a system call */
+  double        fpcsr;
+  unsigned long trap;	/* Reason for being here */
+  unsigned long marker;	/* Should have DEADDEAD */
+  /*unsigned long _underhead[20]; *//* Callee's register save area */
+  unsigned long edx;	/* for binfmt_elf.c which wants edx */
 };
 
 #define instruction_pointer(regs) ((regs)->nip)
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/residual.h linux/include/asm-ppc/residual.h
--- v2.1.15/linux/include/asm-ppc/residual.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-ppc/residual.h	Wed Dec 18 10:54:10 1996
@@ -0,0 +1,315 @@
+/* 7/18/95                                                                    */
+/*----------------------------------------------------------------------------*/
+/*      Residual Data header definitions and prototypes                       */
+/*----------------------------------------------------------------------------*/
+
+/* Structure map for RESIDUAL on PowerPC Reference Platform                   */
+/* residual.h - Residual data structure passed in r3.                         */
+/*              Load point passed in r4 to boot image.                        */
+/* For enum's: if given in hex then they are bit significant,                 */
+/*             i.e. only one bit is on for each enum                          */
+/* Reserved fields must be filled with zeros.                                */
+
+#ifndef _RESIDUAL_
+#define _RESIDUAL_
+
+#define MAX_CPUS 32                     /* These should be set to the maximum */
+#define MAX_MEMS 64                     /* number possible for this system.   */
+#define MAX_DEVICES 256                 /* Changing these will change the     */
+#define AVE_PNP_SIZE 32                 /* structure, hence the version of    */
+#define MAX_MEM_SEGS 64                 /* this header file.                  */
+
+/*----------------------------------------------------------------------------*/
+/*               Public structures...                                         */
+/*----------------------------------------------------------------------------*/
+
+#include "pnp.h"
+
+typedef enum _L1CACHE_TYPE {
+  NoneCAC = 0,
+  SplitCAC = 1,
+  CombinedCAC = 2
+  } L1CACHE_TYPE;
+
+typedef enum _TLB_TYPE {
+  NoneTLB = 0,
+  SplitTLB = 1,
+  CombinedTLB = 2
+  } TLB_TYPE;
+
+typedef enum _FIRMWARE_SUPPORT {
+  Conventional = 0x01,
+  OpenFirmware = 0x02,
+  Diagnostics = 0x04,
+  LowDebug = 0x08,
+  Multiboot = 0x10,
+  LowClient = 0x20,
+  Hex41 = 0x40,
+  FAT = 0x80,
+  ISO9660 = 0x0100,
+  SCSI_InitiatorID_Override = 0x0200,
+  Tape_Boot = 0x0400,
+  FW_Boot_Path = 0x0800
+  } FIRMWARE_SUPPORT;
+
+typedef enum _FIRMWARE_SUPPLIERS {
+  IBMFirmware = 0x00,
+  MotoFirmware = 0x01,                  /* 7/18/95                            */
+  FirmWorks = 0x02,                     /* 10/5/95                            */
+  Bull = 0x03,                          /* 04/03/96                           */
+  } FIRMWARE_SUPPLIERS;
+
+typedef enum _ENDIAN_SWITCH_METHODS {
+  UsePort92 = 0x01,
+  UsePCIConfigA8 = 0x02,
+  UseFF001030 = 0x03,
+  } ENDIAN_SWITCH_METHODS;
+
+typedef enum _SPREAD_IO_METHODS {
+  UsePort850 = 0x00,
+/*UsePCIConfigA8 = 0x02,*/
+  } SPREAD_IO_METHODS;
+
+typedef struct _VPD {
+
+  /* Box dependent stuff */
+  unsigned char PrintableModel[32];     /* Null terminated string.
+                                           Must be of the form:
+                                           vvv,<20h>,<model designation>,<0x0>
+                                           where vvv is the vendor ID
+                                           e.g. IBM PPS MODEL 6015<0x0>       */
+  unsigned char Serial[16];             /* 12/94:
+                                           Serial Number; must be of the form:
+                                           vvv<serial number> where vvv is the
+                                           vendor ID.
+                                           e.g. IBM60151234567<20h><20h>      */
+  unsigned char Reserved[48];
+  unsigned long FirmwareSupplier;       /* See FirmwareSuppliers enum         */
+  unsigned long FirmwareSupports;       /* See FirmwareSupport enum           */
+  unsigned long NvramSize;              /* Size of nvram in bytes             */
+  unsigned long NumSIMMSlots;
+  unsigned short EndianSwitchMethod;    /* See EndianSwitchMethods enum       */
+  unsigned short SpreadIOMethod;        /* See SpreadIOMethods enum           */
+  unsigned long SmpIar;
+  unsigned long RAMErrLogOffset;        /* Heap offset to error log           */
+  unsigned long Reserved5;
+  unsigned long Reserved6;
+  unsigned long ProcessorHz;            /* Processor clock frequency in Hertz */
+  unsigned long ProcessorBusHz;         /* Processor bus clock frequency      */
+  unsigned long Reserved7;
+  unsigned long TimeBaseDivisor;        /* (Bus clocks per timebase tic)*1000 */
+  unsigned long WordWidth;              /* Word width in bits                 */
+  unsigned long PageSize;               /* Page size in bytes                 */
+  unsigned long CoherenceBlockSize;     /* Unit of transfer in/out of cache
+                                           for which coherency is maintained;
+                                           normally <= CacheLineSize.         */
+  unsigned long GranuleSize;            /* Unit of lock allocation to avoid   */
+                                        /*   false sharing of locks.          */
+
+  /* L1 Cache variables */
+  unsigned long CacheSize;              /* L1 Cache size in KB. This is the   */
+                                        /*   total size of the L1, whether    */
+                                        /*   combined or split                */
+  unsigned long CacheAttrib;            /* L1CACHE_TYPE                       */
+  unsigned long CacheAssoc;             /* L1 Cache associativity. Use this
+                                           for combined cache. If split, put
+                                           zeros here.                        */
+  unsigned long CacheLineSize;          /* L1 Cache line size in bytes. Use
+                                           for combined cache. If split, put
+                                           zeros here.                        */
+  /* For split L1 Cache: (= combined if combined cache) */
+  unsigned long I_CacheSize;
+  unsigned long I_CacheAssoc;
+  unsigned long I_CacheLineSize;
+  unsigned long D_CacheSize;
+  unsigned long D_CacheAssoc;
+  unsigned long D_CacheLineSize;
+
+  /* Translation Lookaside Buffer variables */
+  unsigned long TLBSize;                /* Total number of TLBs on the system */
+  unsigned long TLBAttrib;              /* Combined I+D or split TLB          */
+  unsigned long TLBAssoc;               /* TLB Associativity. Use this for
+                                           combined TLB. If split, put zeros
+                                           here.                              */
+  /* For split TLB: (= combined if combined TLB) */
+  unsigned long I_TLBSize;
+  unsigned long I_TLBAssoc;
+  unsigned long D_TLBSize;
+  unsigned long D_TLBAssoc;
+
+  unsigned long ExtendedVPD;            /* Offset to extended VPD area;
+                                           null if unused                     */
+  } VPD;
+
+typedef enum _DEVICE_FLAGS {
+  Enabled = 0x4000,                     /* 1 - PCI device is enabled          */
+  Integrated = 0x2000,
+  Failed = 0x1000,                      /* 1 - device failed POST code tests  */
+  Static = 0x0800,                      /* 0 - dynamically configurable
+                                           1 - static                         */
+  Dock = 0x0400,                        /* 0 - not a docking station device
+                                           1 - is a docking station device    */
+  Boot = 0x0200,                        /* 0 - device cannot be used for BOOT
+                                           1 - can be a BOOT device           */
+  Configurable = 0x0100,                /* 1 - device is configurable         */
+  Disableable = 0x80,                   /* 1 - device can be disabled         */
+  PowerManaged = 0x40,                  /* 0 - not managed; 1 - managed       */
+  ReadOnly = 0x20,                      /* 1 - device is read only            */
+  Removable = 0x10,                     /* 1 - device is removable            */
+  ConsoleIn = 0x08,
+  ConsoleOut = 0x04,
+  Input = 0x02,
+  Output = 0x01
+  } DEVICE_FLAGS;
+
+typedef enum _BUS_ID {
+  ISADEVICE = 0x01,
+  EISADEVICE = 0x02,
+  PCIDEVICE = 0x04,
+  PCMCIADEVICE = 0x08,
+  PNPISADEVICE = 0x10,
+  MCADEVICE = 0x20,
+  MXDEVICE = 0x40,                      /* Devices on mezzanine bus           */
+  PROCESSORDEVICE = 0x80,               /* Devices on processor bus           */
+  VMEDEVICE = 0x100,
+  } BUS_ID;
+
+typedef struct _DEVICE_ID {
+  unsigned long BusId;                  /* See BUS_ID enum above              */
+  unsigned long DevId;                  /* Big Endian format                  */
+  unsigned long SerialNum;              /* For multiple usage of a single
+                                           DevId                              */
+  unsigned long Flags;                  /* See DEVICE_FLAGS enum above        */
+  unsigned char BaseType;               /* See pnp.h for bit definitions      */
+  unsigned char SubType;                /* See pnp.h for bit definitions      */
+  unsigned char Interface;              /* See pnp.h for bit definitions      */
+  unsigned char Spare;
+  } DEVICE_ID;
+
+typedef union _BUS_ACCESS {
+  struct _PnPAccess{
+    unsigned char CSN;
+    unsigned char LogicalDevNumber;
+    unsigned short ReadDataPort;
+    } PnPAccess;
+  struct _ISAAccess{
+    unsigned char SlotNumber;           /* ISA Slot Number generally not
+                                           available; 0 if unknown            */
+    unsigned char LogicalDevNumber;
+    unsigned short ISAReserved;
+    } ISAAccess;
+  struct _MCAAccess{
+    unsigned char SlotNumber;
+    unsigned char LogicalDevNumber;
+    unsigned short MCAReserved;
+    } MCAAccess;
+  struct _PCMCIAAccess{
+    unsigned char SlotNumber;
+    unsigned char LogicalDevNumber;
+    unsigned short PCMCIAReserved;
+    } PCMCIAAccess;
+  struct _EISAAccess{
+    unsigned char SlotNumber;
+    unsigned char FunctionNumber;
+    unsigned short EISAReserved;
+    } EISAAccess;
+  struct _PCIAccess{
+    unsigned char BusNumber;
+    unsigned char DevFuncNumber;
+    unsigned short PCIReserved;
+    } PCIAccess;
+  struct _ProcBusAccess{
+    unsigned char BusNumber;
+    unsigned char BUID;
+    unsigned short ProcBusReserved;
+    } ProcBusAccess;
+  } BUS_ACCESS;
+
+/* Per logical device information */
+typedef struct _PPC_DEVICE {
+  DEVICE_ID DeviceId;
+  BUS_ACCESS BusAccess;
+
+  /* The following three are offsets into the DevicePnPHeap */
+  /* All are in PnP compressed format                       */
+  unsigned long AllocatedOffset;        /* Allocated resource description     */
+  unsigned long PossibleOffset;         /* Possible resource description      */
+  unsigned long CompatibleOffset;       /* Compatible device identifiers      */
+  } PPC_DEVICE;
+
+typedef enum _CPU_STATE {
+  CPU_GOOD = 0,                         /* CPU is present, and active         */
+  CPU_GOOD_FW = 1,                      /* CPU is present, and in firmware    */
+  CPU_OFF = 2,                          /* CPU is present, but inactive       */
+  CPU_FAILED = 3,                       /* CPU is present, but failed POST    */
+  CPU_NOT_PRESENT = 255                 /* CPU not present                    */
+  } CPU_STATE;
+
+typedef struct _PPC_CPU {
+  unsigned long CpuType;                /* Result of mfspr from Processor
+                                           Version Register (PVR).
+                                           PVR(0-15) = Version (e.g. 601)
+                                           PVR(16-31 = EC Level               */
+  unsigned char CpuNumber;              /* CPU Number for this processor      */
+  unsigned char CpuState;               /* CPU State, see CPU_STATE enum      */
+  unsigned short Reserved;
+  } PPC_CPU;
+
+typedef struct _PPC_MEM {
+  unsigned long SIMMSize;               /* 0 - absent or bad
+                                           8M, 32M (in MB)                    */
+  } PPC_MEM;
+
+typedef enum _MEM_USAGE {
+  Other = 0x8000,
+  ResumeBlock = 0x4000,                 /* for use by power management        */
+  SystemROM = 0x2000,                   /* Flash memory (populated)           */
+  UnPopSystemROM = 0x1000,              /* Unpopulated part of SystemROM area */
+  IOMemory = 0x0800,
+  SystemIO = 0x0400,
+  SystemRegs = 0x0200,
+  PCIAddr = 0x0100,
+  PCIConfig = 0x80,
+  ISAAddr = 0x40,
+  Unpopulated = 0x20,                   /* Unpopulated part of System Memory  */
+  Free = 0x10,                          /* Free part of System Memory         */
+  BootImage = 0x08,                     /* BootImage part of System Memory    */
+  FirmwareCode = 0x04,                  /* FirmwareCode part of System Memory */
+  FirmwareHeap = 0x02,                  /* FirmwareHeap part of System Memory */
+  FirmwareStack = 0x01                  /* FirmwareStack part of System Memory*/
+  } MEM_USAGE;
+
+typedef struct _MEM_MAP {
+  unsigned long Usage;                  /* See MEM_USAGE above                */
+  unsigned long BasePage;               /* Page number measured in 4KB pages  */
+  unsigned long PageCount;              /* Page count measured in 4KB pages   */
+  } MEM_MAP;
+
+typedef struct _RESIDUAL {
+  unsigned long ResidualLength;         /* Length of Residual                 */
+  unsigned char Version;                /* of this data structure             */
+  unsigned char Revision;               /* of this data structure             */
+  unsigned short EC;                    /* of this data structure             */
+  /* VPD */
+  VPD VitalProductData;
+  /* CPU */
+  unsigned short MaxNumCpus;            /* Max CPUs in this system            */
+  unsigned short ActualNumCpus;         /* ActualNumCpus < MaxNumCpus means   */
+                                        /* that there are unpopulated or      */
+                                        /* otherwise unusable cpu locations   */
+  PPC_CPU Cpus[MAX_CPUS];
+  /* Memory */
+  unsigned long TotalMemory;            /* Total amount of memory installed   */
+  unsigned long GoodMemory;             /* Total amount of good memory        */
+  unsigned long ActualNumMemSegs;
+  MEM_MAP Segs[MAX_MEM_SEGS];
+  unsigned long ActualNumMemories;
+  PPC_MEM Memories[MAX_MEMS];
+  /* Devices */
+  unsigned long ActualNumDevices;
+  PPC_DEVICE Devices[MAX_DEVICES];
+  unsigned char DevicePnPHeap[2*MAX_DEVICES*AVE_PNP_SIZE];
+  } RESIDUAL;
+
+#endif  /* ndef _RESIDUAL_ */
+
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/resource.h linux/include/asm-ppc/resource.h
--- v2.1.15/linux/include/asm-ppc/resource.h	Mon May 27 12:00:59 1996
+++ linux/include/asm-ppc/resource.h	Wed Dec 18 10:54:10 1996
@@ -1,35 +1,33 @@
 #ifndef _PPC_RESOURCE_H
 #define _PPC_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_NOFILE	6		/* max number of open files */
+#define RLIMIT_AS	7		/* address space limit(?) */
+#define RLIMIT_NPROC	8		/* max number of processes */
+#define RLIMIT_MEMLOCK	9		/* max locked-in-memory address space */
 
-#define RLIM_NLIMITS	9
+#define RLIM_NLIMITS	10
 
 #ifdef __KERNEL__
 
-#define INIT_RLIMITS					\
-{							\
-	{ LONG_MAX, LONG_MAX },				\
-	{ LONG_MAX, LONG_MAX },				\
-	{ LONG_MAX, LONG_MAX },				\
-	{ _STK_LIM, _STK_LIM },				\
-	{        0, LONG_MAX },				\
-	{ LONG_MAX, LONG_MAX },				\
-	{ MAX_TASKS_PER_USER, MAX_TASKS_PER_USER },	\
-	{ NR_OPEN, NR_OPEN },				\
-	{ LONG_MAX, LONG_MAX },				\
+#define INIT_RLIMITS							\
+{									\
+    {LONG_MAX, LONG_MAX},			/* RLIMIT_CPU */	\
+    {LONG_MAX, LONG_MAX},			/* RLIMIT_FSIZE */	\
+    {LONG_MAX, LONG_MAX},			/* RLIMIT_DATA */	\
+    {_STK_LIM, _STK_LIM},			/* RLIMIT_STACK */	\
+    {       0, LONG_MAX},			/* RLIMIT_CORE */	\
+    {LONG_MAX, LONG_MAX},			/* RLIMIT_RSS */	\
+    { NR_OPEN,  NR_OPEN},			/* RLIMIT_NOFILE */	\
+    {LONG_MAX, LONG_MAX},			/* RLIMIT_AS */		\
+    {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER},	/* RLIMIT_NPROC */	\
+    {LONG_MAX, LONG_MAX},			/* RLIMIT_MEMLOCK */	\
 }
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/segment.h linux/include/asm-ppc/segment.h
--- v2.1.15/linux/include/asm-ppc/segment.h	Sat Nov 25 19:49:06 1995
+++ linux/include/asm-ppc/segment.h	Wed Dec 18 10:54:10 1996
@@ -1,131 +1,7 @@
-#ifndef _ASM_PPC_SEGMENT_H
-#define _ASM_PPC_SEGMENT_H
+#ifndef __PPC_SEGMENT_H
+#define __PPC_SEGMENT_H
 
-#include <linux/string.h>
+/* Only here because we have some old header files that expect it.. */
 
-#define put_user(x,ptr) __put_user((unsigned long)(x),(ptr),sizeof(*(ptr)))
-#define get_user(ptr) ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr))))
-
-extern int bad_user_access_length(void);
-
-static inline void __put_user(unsigned long x, void * y, int size)
-{
-	switch (size) {
-		case 1:
-			*(char *) y = x;
-			break;
-		case 2:
-			*(short *) y = x;
-			break;
-		case 4:
-			*(int *) y = x;
-			break;
-		case 8:
-			*(long *) y = x;
-			break;
-		default:
-			bad_user_access_length();
-	}
-}
-
-static inline unsigned long __get_user(const void * y, int size)
-{
-	switch (size) {
-		case 1:
-			return *(unsigned char *) y;
-		case 2:
-			return *(unsigned short *) y;
-		case 4:
-			return *(unsigned int *) y;
-		case 8:
-			return *(unsigned long *) y;
-		default:
-			return bad_user_access_length();
-	}
-}
-
-static inline unsigned char get_user_byte(const char * addr)
-{
-	return *addr;
-}
-
-#define get_fs_byte(addr) get_user_byte((char *)(addr))
-
-static inline unsigned short get_user_word(const short *addr)
-{
-	return *addr;
-}
-
-#define get_fs_word(addr) get_user_word((short *)(addr))
-
-static inline unsigned long get_user_long(const int *addr)
-{
-	return *addr;
-}
-
-#define get_fs_long(addr) get_user_long((int *)(addr))
-
-static inline unsigned long get_user_quad(const long *addr)
-{
-	return *addr;
-}
-
-#define get_fs_quad(addr) get_user_quad((long *)(addr))
-
-static inline void put_user_byte(char val,char *addr)
-{
-	*addr = val;
-}
-
-#define put_fs_byte(x,addr) put_user_byte((x),(char *)(addr))
-
-static inline void put_user_word(short val,short * addr)
-{
-	*addr = val;
-}
-
-#define put_fs_word(x,addr) put_user_word((x),(short *)(addr))
-
-static inline void put_user_long(unsigned long val,int * addr)
-{
-	*addr = val;
-}
-
-#define put_fs_long(x,addr) put_user_long((x),(int *)(addr))
-
-static inline void put_user_quad(unsigned long val,long * addr)
-{
-	*addr = val;
-}
-
-#define put_fs_quad(x,addr) put_user_quad((x),(long *)(addr))
-
-#define memcpy_fromfs(to, from, n) memcpy((to),(from),(n))
-
-#define memcpy_tofs(to, from, n) memcpy((to),(from),(n))
-
-/*
- * For segmented architectures, these are used to specify which segment
- * to use for the above functions.
- *
- * The powerpc is not segmented, so these are just dummies.
- */
-
-#define KERNEL_DS 0
-#define USER_DS 1
-
-static inline unsigned long get_fs(void)
-{
-	return 0;
-}
-
-static inline unsigned long get_ds(void)
-{
-	return 0;
-}
-
-static inline void set_fs(unsigned long val)
-{
-}
-
-#endif /* _ASM_SEGMENT_H */
+#endif
+#include <asm/uaccess.h>
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/semaphore.h linux/include/asm-ppc/semaphore.h
--- v2.1.15/linux/include/asm-ppc/semaphore.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-ppc/semaphore.h	Wed Dec 18 10:54:10 1996
@@ -0,0 +1,39 @@
+#ifndef _PPC_SEMAPHORE_H
+#define _PPC_SEMAPHORE_H
+
+#include <asm/atomic.h>
+
+struct semaphore {
+	atomic_t count;
+	atomic_t waiting;
+	struct wait_queue * wait;
+};
+
+#define MUTEX ((struct semaphore) { 1, 0, NULL })
+#define MUTEX_LOCKED ((struct semaphore) { 0, 0, NULL })
+
+extern void __down(struct semaphore * sem);
+extern void __up(struct semaphore * sem);
+
+extern void atomic_add(int c, int *v);
+extern void atomic_sub(int c, int *v);
+
+extern inline void down(struct semaphore * sem)
+{
+  for (;;)
+  {
+    atomic_dec_return(&sem->count);
+    if ( sem->count >= 0)
+      break;
+    __down(sem);
+  }
+}
+
+extern inline void up(struct semaphore * sem)
+{
+  atomic_inc_return(&sem->count);
+  if ( sem->count <= 0)
+    __up(sem);
+}	
+
+#endif /* !(_PPC_SEMAPHORE_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/smp.h linux/include/asm-ppc/smp.h
--- v2.1.15/linux/include/asm-ppc/smp.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-ppc/smp.h	Wed Dec 18 10:54:10 1996
@@ -0,0 +1,26 @@
+/* smp.h: PPC specific SMP stuff.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _PPC_SMP_H
+#define _PPC_SMP_H
+
+#ifdef __SMP__
+
+#ifndef __ASSEMBLY__
+
+extern struct prom_cpuinfo linux_cpus[NCPUS];
+
+/* Per processor PPC parameters we need. */
+
+struct cpuinfo_PPC {
+	unsigned long udelay_val; /* that's it */
+};
+
+extern struct cpuinfo_PPC cpu_data[NR_CPUS];
+
+
+#endif /* !(__SMP__) */
+
+#endif /* !(_PPC_SMP_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/socket.h linux/include/asm-ppc/socket.h
--- v2.1.15/linux/include/asm-ppc/socket.h	Mon May 27 12:00:59 1996
+++ linux/include/asm-ppc/socket.h	Wed Dec 18 10:54:10 1996
@@ -27,5 +27,9 @@
 #define SO_LINGER	13
 #define SO_BSDCOMPAT	14
 /* To add :#define SO_REUSEPORT 14 */
+#define SO_RCVLOWAT	16
+#define SO_SNDLOWAT	17
+#define SO_RCVTIMEO	18
+#define SO_SNDTIMEO	19
 
 #endif /* _ASM_SOCKET_H */
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/stat.h linux/include/asm-ppc/stat.h
--- v2.1.15/linux/include/asm-ppc/stat.h	Mon May 27 12:00:59 1996
+++ linux/include/asm-ppc/stat.h	Wed Dec 18 10:54:10 1996
@@ -3,7 +3,7 @@
 
 #include <linux/types.h>
 
-struct old_stat {
+struct __old_kernel_stat {
 	unsigned short st_dev;
 	unsigned short st_ino;
 	unsigned short st_mode;
@@ -16,8 +16,7 @@
 	unsigned long  st_mtime;
 	unsigned long  st_ctime;
 };
-
-struct new_stat {
+struct stat {
 	dev_t		st_dev;
 	ino_t		st_ino;
 	mode_t		st_mode;
@@ -37,5 +36,4 @@
 	unsigned long  	__unused4;
 	unsigned long  	__unused5;
 };
-
 #endif
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/string.h linux/include/asm-ppc/string.h
--- v2.1.15/linux/include/asm-ppc/string.h	Fri Apr 12 09:49:45 1996
+++ linux/include/asm-ppc/string.h	Wed Dec 18 10:54:10 1996
@@ -5,12 +5,12 @@
 
 /*
  * keep things happy, the compile became unhappy since memset is
- * in include/string.h and lib/string.c with different args
+ * in include/linux/string.h and lib/string.c with different prototypes
  *                          -- Cort
  */
-
+#if 1
 #define  __HAVE_ARCH_MEMSET
-extern inline void * memset(void * s,int c,size_t count)
+extern __inline__ void * memset(void * s,int c,__kernel_size_t count)
 {
 	char *xs = (char *) s;
 
@@ -19,44 +19,8 @@
 
 	return s;
 }
-#define __HAVE_ARCH_STRSTR
-/* Return the first occurrence of NEEDLE in HAYSTACK.  */
-extern inline char *
-strstr(const char *haystack, const char *needle)
-{
-  const char *const needle_end = strchr(needle, '\0');
-  const char *const haystack_end = strchr(haystack, '\0');
-  const size_t needle_len = needle_end - needle;
-  const size_t needle_last = needle_len - 1;
-  const char *begin;
-
-  if (needle_len == 0)
-#ifdef __linux__
-    return (char *) haystack;
-#else
-    return (char *) haystack_end;
 #endif
-  if ((size_t) (haystack_end - haystack) < needle_len)
-    return NULL;
-
-  for (begin = &haystack[needle_last]; begin < haystack_end; ++begin)
-    {
-      register const char *n = &needle[needle_last];
-      register const char *h = begin;
-
-      do
-	if (*h != *n)
-	  goto loop;		/* continue for loop */
-      while (--n >= needle && --h >= haystack);
-
-      return (char *) h;
-
-    loop:;
-    }
-
-  return NULL;
-}
-
+#define bzero(addr,size) memset((addr),(int)(0),(size))
 
 
 #endif
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/system.h linux/include/asm-ppc/system.h
--- v2.1.15/linux/include/asm-ppc/system.h	Mon May 27 12:00:59 1996
+++ linux/include/asm-ppc/system.h	Wed Dec 18 10:54:10 1996
@@ -16,7 +16,6 @@
 extern void _enable_interrupts(int);
 
 /*extern void memcpy(void *, void *, int);*/
-extern void bzero(void *, int);
 
 struct task_struct;
 extern void switch_to(struct task_struct *prev, struct task_struct *next);
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/termios.h linux/include/asm-ppc/termios.h
--- v2.1.15/linux/include/asm-ppc/termios.h	Tue Nov 12 15:56:12 1996
+++ linux/include/asm-ppc/termios.h	Wed Dec 18 10:54:10 1996
@@ -343,7 +343,6 @@
 #define N_SLIP		1
 #define N_MOUSE		2
 #define N_PPP		3
-#define N_AX25		5
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/uaccess.h linux/include/asm-ppc/uaccess.h
--- v2.1.15/linux/include/asm-ppc/uaccess.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-ppc/uaccess.h	Wed Dec 18 10:54:10 1996
@@ -0,0 +1,150 @@
+#ifndef _ASM_UACCESS_H
+#define _ASM_UACCESS_H
+
+#ifndef __ASSEMBLY__
+#include <linux/sched.h>
+#include <linux/errno.h>
+
+#define KERNEL_DS   (0)
+#define USER_DS		(1)
+
+#define VERIFY_READ	0
+#define VERIFY_WRITE	1
+
+#define get_fs() (current->tss.fs)
+#define get_ds() (KERNEL_DS)
+#define set_fs(val) ( current->tss.fs = (val))
+
+#define __user_ok(addr,size) (((size) <= 0x80000000)&&((addr) <= 0x80000000-(size)))
+#define __kernel_ok (get_fs() == KERNEL_DS)
+#define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
+#define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
+
+extern inline int verify_area(int type, const void * addr, unsigned long size)
+{
+	return access_ok(type,addr,size) ? 0 : -EFAULT;
+}
+
+/*
+ * These are the main single-value transfer routines.  They automatically
+ * use the right size if we just have the right pointer type.
+ *
+ * As the powerpc uses the same address space for kernel and user
+ * data, we can just do these as direct assignments.  (Of course, the
+ * exception handling means that it's no longer "just"...)
+ *
+ * Careful to not
+ * (a) re-use the arguments for side effects (sizeof/typeof is ok)
+ * (b) require any knowledge of processes at this stage
+ */
+/*
+ * The "__xxx" versions do not do address space checking, useful when
+ * doing multiple accesses to the same area (the programmer has to do the
+ * checks by hand with "access_ok()")
+ */
+#define put_user(x,ptr) ({ \
+unsigned long __pu_addr = (unsigned long)(ptr); \
+__put_user_check((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr))); })
+
+#define get_user(x,ptr) ({ \
+unsigned long __gu_addr = (unsigned long)(ptr); \
+__get_user_check((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr))); })
+
+#define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr)))
+#define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr)),__typeof__(*(ptr)))
+struct __large_struct { unsigned long buf[100]; };
+#define __m(x) ((struct __large_struct *)(x))
+
+#define __put_user_check(x,addr,size) ({ \
+int __pu_ret; \
+__pu_ret = -EFAULT; \
+if (__access_ok(addr,size)) { \
+switch (size) { \
+case 1: __pu_ret =__put_user_8(x,addr); break; \
+case 2: __pu_ret =__put_user_16(x,addr); break; \
+case 4: __pu_ret =__put_user_32(x,addr); break; \
+default: __pu_ret = __put_user_bad(); break; \
+} } __pu_ret; })
+
+#define __put_user_nocheck(x,addr,size) ({ \
+int __pu_ret; \
+__pu_ret = -EFAULT; \
+switch (size) { \
+case 1: __pu_ret =__put_user_8(x,addr); break; \
+case 2: __pu_ret =__put_user_16(x,addr); break; \
+case 4: __pu_ret =__put_user_32(x,addr); break; \
+default: __pu_ret = __put_user_bad(); break; \
+} __pu_ret; })
+
+extern int __put_user_bad(void);
+
+#define __get_user_check(x,addr,size,type) ({ \
+register int __gu_ret asm("r4"); \
+unsigned long __gu_val = 0; \
+__gu_ret = -EFAULT; \
+if (__access_ok(addr,size)) { \
+switch (size) { \
+case 1: __gu_val = __get_user_8(__gu_val,addr); break; \
+case 2: __gu_val = __get_user_16(__gu_val,addr); break; \
+case 4: __gu_val = __get_user_32(__gu_val,addr); break; \
+default: __get_user_bad(); break; \
+} } (x) = (type) __gu_val; __gu_ret; })
+
+#define __get_user_nocheck(x,addr,size,type) ({ \
+register int __gu_ret asm("r4"); \
+unsigned long __gu_val = 0; \
+__gu_ret = -EFAULT; \
+switch (size) { \
+case 1: __gu_val =__get_user_8(__gu_val,addr); break; \
+case 2: __gu_val =__get_user_16(__gu_val,addr); break; \
+case 4: __gu_val =__get_user_32(__gu_val,addr); break; \
+default: __gu_val = __get_user_bad(); break; \
+} (x) = (type) __gu_val; __gu_ret;  })
+     
+
+/* more complex routines */
+
+extern int __copy_tofrom_user(unsigned long to, unsigned long from, int size);
+
+#define copy_to_user(to,from,n) ({ \
+unsigned long __copy_to = (unsigned long) (to); \
+unsigned long __copy_size = (unsigned long) (n); \
+unsigned long __copy_res = -EFAULT; \
+if(__copy_size && __access_ok(__copy_to, __copy_size)) { \
+__copy_res = __copy_tofrom_user(__copy_to, (unsigned long) (from), __copy_size); \
+}  \
+__copy_res; })
+
+#define copy_from_user(to,from,n) ({ \
+unsigned long __copy_from = (unsigned long) (from); \
+unsigned long __copy_size = (unsigned long) (n); \
+unsigned long __copy_res = -EFAULT; \
+if(__copy_size && __access_ok(__copy_from, __copy_size)) { \
+__copy_res = __copy_tofrom_user((unsigned long) (to), __copy_from, __copy_size); \
+} \
+__copy_res; })
+
+extern int __clear_user(unsigned long addr, int size);
+
+#define clear_user(addr,n) ({ \
+unsigned long __clear_addr = (unsigned long) (addr); \
+int __clear_size = (int) (n); \
+int __clear_res = -EFAULT; \
+if(__clear_size && __access_ok(__clear_addr, __clear_size)) { \
+__clear_res = __clear_user(__clear_addr, __clear_size); \
+} \
+__clear_res; })
+
+extern int __strncpy_from_user(unsigned long dest, unsigned long src, int count);
+
+#define strncpy_from_user(dest,src,count) ({ \
+unsigned long __sfu_src = (unsigned long) (src); \
+int __sfu_count = (int) (count); \
+long __sfu_res = -EFAULT; \
+if(__access_ok(__sfu_src, __sfu_count)) { \
+__sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \
+} __sfu_res; })
+
+#endif  /* __ASSEMBLY__ */
+
+#endif /* _ASM_UACCESS_H */
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/unistd.h linux/include/asm-ppc/unistd.h
--- v2.1.15/linux/include/asm-ppc/unistd.h	Mon Jul  8 11:27:43 1996
+++ linux/include/asm-ppc/unistd.h	Wed Dec 18 10:54:10 1996
@@ -1,3 +1,4 @@
+/* * Last edited: Nov 17 16:28 1995 (cort) */
 #ifndef _ASM_PPC_UNISTD_H_
 #define _ASM_PPC_UNISTD_H_
 
@@ -156,142 +157,113 @@
 #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
 
-
+/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
 #define _syscall0(type,name) \
 type name(void) \
 { \
-    long retval; \
-    __asm__  ( \
-	      "li 0, %0 \n\t" \
-	      "sc \n\t" \
-	      "mr 31,3 \n\t" \
-	      "bns 10f \n\t" \
-	      "mr 0,3 \n\t" \
-	      "lis 3,errno@ha \n\t" \
-	      "stw 0,errno@l(3) \n\t" \
-	      "li 3,-1 \n\t" \
-	      "10: \n\t" \
-	      : \
-	      : "i" (__NR_##name) \
-	      : "0", "31", "3", "cc", "memory" \
-	      );  \
-    return(retval);\
+ __asm__ (_lisc(__NR_##name)); \
+ __asm__ ("sc"); \
+ __asm__ ("mr 31,3"); \
+ __asm__ ("bns 10f"); \
+ __asm__ ("mr 0,3"); \
+ __asm__ ("lis 3,errno@ha"); \
+ __asm__ ("stw 0,errno@l(3)"); \
+ __asm__ ("li 3,-1"); \
+ __asm__ ("10:"); \
 }
 
 #define _syscall1(type,name,type1,arg1) \
 type name(type1 arg1) \
 { \
-    long retval; \
-    __asm__  ( \
-	      "li 0, %0 \n\t" \
-	      "sc \n\t" \
-	      "mr 31,3 \n\t" \
-	      "bns 10f \n\t" \
-	      "mr 0,3 \n\t" \
-	      "lis 3,errno@ha \n\t" \
-	      "stw 0,errno@l(3) \n\t" \
-	      "li 3,-1 \n\t" \
-	      "10: \n\t" \
-	      : \
-	      : "i" (__NR_##name) \
-	      : "0", "31", "3", "cc", "memory" \
-	      );  \
-    return(retval); \
+ __asm__ (_lisc(__NR_##name)); \
+ __asm__ ("sc"); \
+ __asm__ ("mr 31,3"); \
+ __asm__ ("bns 10f"); \
+ __asm__ ("mr 0,3"); \
+ __asm__ ("lis 3,errno@ha"); \
+ __asm__ ("stw 0,errno@l(3)"); \
+ __asm__ ("li 3,-1"); \
+ __asm__ ("10:"); \
 }
 
 #define _syscall2(type,name,type1,arg1,type2,arg2) \
 type name(type1 arg1,type2 arg2) \
 { \
-    long retval; \
-    __asm__  ( \
-	      "li 0, %0 \n\t" \
-	      "sc \n\t" \
-	      "mr 31,3 \n\t" \
-	      "bns 10f \n\t" \
-	      "mr 0,3 \n\t" \
-	      "lis 3,errno@ha \n\t" \
-	      "stw 0,errno@l(3) \n\t" \
-	      "li 3,-1 \n\t" \
-	      "10: \n\t" \
-	      : \
-	      : "i" (__NR_##name) \
-	      : "0", "31", "3", "cc", "memory" \
-	      );  \
-    return(retval); \
+ __asm__ (_lisc(__NR_##name)); \
+ __asm__ ("sc"); \
+ __asm__ ("mr 31,3"); \
+ __asm__ ("bns 10f"); \
+ __asm__ ("mr 0,3"); \
+ __asm__ ("lis 3,errno@ha"); \
+ __asm__ ("stw 0,errno@l(3)"); \
+ __asm__ ("li 3,-1"); \
+ __asm__ ("10:"); \
 }
 
-
 #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
-type name(type1 arg1,type2 arg2, type3 arg3) \
+type name(type1 arg1,type2 arg2,type3 arg3) \
 { \
-    long retval; \
-    __asm__  ( \
-	      "li 0, %0 \n\t" \
-	      "sc \n\t" \
-	      "mr 31,3 \n\t" \
-	      "bns 10f \n\t" \
-	      "mr 0,3 \n\t" \
-	      "lis 3,errno@ha \n\t" \
-	      "stw 0,errno@l(3) \n\t" \
-	      "li 3,-1 \n\t" \
-	      "10: \n\t" \
-	      : \
-	      : "i" (__NR_##name) \
-	      : "0", "31", "3", "cc", "memory" \
-	      );  \
-    return(retval); \
+ __asm__ (_lisc(__NR_##name)); \
+ __asm__ ("sc"); \
+ __asm__ ("mr 31,3"); \
+ __asm__ ("bns 10f"); \
+ __asm__ ("mr 0,3"); \
+ __asm__ ("lis 3,errno@ha"); \
+ __asm__ ("stw 0,errno@l(3)"); \
+ __asm__ ("li 3,-1"); \
+ __asm__ ("10:"); \
 }
 
 #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
 type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
 { \
-    long retval; \
-    __asm__  ( \
-	      "li 0, %0 \n\t" \
-	      "sc \n\t" \
-	      "mr 31,3 \n\t" \
-	      "bns 10f \n\t" \
-	      "mr 0,3 \n\t" \
-	      "lis 3,errno@ha \n\t" \
-	      "stw 0,errno@l(3) \n\t" \
-	      "li 3,-1 \n\t" \
-	      "10: \n\t" \
-	      : \
-	      : "i" (__NR_##name) \
-	      : "0", "31", "3", "cc", "memory" \
-	      );  \
-    return(retval); \
-}
+ __asm__ (_lisc(__NR_##name)); \
+ __asm__ ("sc"); \
+ __asm__ ("mr 31,3"); \
+ __asm__ ("bns 10f"); \
+ __asm__ ("mr 0,3"); \
+ __asm__ ("lis 3,errno@ha"); \
+ __asm__ ("stw 0,errno@l(3)"); \
+ __asm__ ("li 3,-1"); \
+ __asm__ ("10:"); \
+} 
 
 #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
 	  type5,arg5) \
 type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
 { \
-    long retval; \
-    __asm__  ( \
-	      "li 0, %0 \n\t" \
-	      "sc \n\t" \
-	      "mr 31,3 \n\t" \
-	      "bns 10f \n\t" \
-	      "mr 0,3 \n\t" \
-	      "lis 3,errno@ha \n\t" \
-	      "stw 0,errno@l(3) \n\t" \
-	      "li 3,-1 \n\t" \
-	      "10: \n\t" \
-	      : \
-	      : "i" (__NR_##name) \
-	      : "0", "31", "3", "cc", "memory" \
-	      );  \
-    return(retval); \
+ __asm__ (_lisc(__NR_##name)); \
+ __asm__ ("sc"); \
+ __asm__ ("mr 31,3"); \
+ __asm__ ("bns 10f"); \
+ __asm__ ("mr 0,3"); \
+ __asm__ ("lis 3,errno@ha"); \
+ __asm__ ("stw 0,errno@l(3)"); \
+ __asm__ ("li 3,-1"); \
+ __asm__ ("10:"); \
 }
 
 #ifdef __KERNEL_SYSCALLS__
+
 /*
  * we need this inline - forking from kernel space will result
  * in NO COPY ON WRITE (!!!), until an execve is executed. This
@@ -305,42 +277,16 @@
  * some others too.
  */
 
-/*
-   some of these had problems getting the right arguments (namely sys_clone())
-   when they were inline so I made them non-inline until we get problems with gcc
-   worked out.  I need to check with Linus to find out which he wants inline now
-   since the above comment was written a long time ago.
-
-   Once I understand the macro language better this should go away.
-             -- Cort
- */
-
-#define __NR__exit __NR_exit
-static /*__inline__*/ _syscall0(int,setup) 
-static __inline__ _syscall0(int,idle) 
-static /*__inline__*/ _syscall0(int,fork)
-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__*/ _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__ _syscall2(int,clone,unsigned long,flags,char *,esp)
-static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-
-static __inline__ pid_t wait(int * wait_stat) 
-{
-	return waitpid(-1,wait_stat,0);
-}
 
+#if 0
 /*
    This is the mechanism for creating a new kernel thread.
    For the time being it only behaves the same as clone().
    It should be changed very soon to work properly and cleanly.  This
    gets us going for now, though.
+
+   some versions of gcc hate this -- complains about constraints being
+   incorrect.  not sure why so it's in arch/ppc/kernel/misc.S now.
      -- Cort
  */
 static __inline__ long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
@@ -369,8 +315,39 @@
 	:"cc", "1", "0", "3", "7", "31", "memory" );
   return retval;
 }
+#else
+extern long __kernel_thread(unsigned long, int (*)(void *), void *);
+
+static inline long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+	return __kernel_thread(flags | CLONE_VM, fn, arg);
+}
+#endif
+
+#define __NR__exit __NR_exit
+static inline _syscall0(int,idle) /* made inline "just in case" -- Cort */
+static inline _syscall0(int,fork) /* needs to be inline */
+static inline _syscall0(int,pause) /* needs to be inline */
+static inline _syscall0(int,setup) /* called in init before execve */
+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*/ _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 _syscall2(int,clone,unsigned long,flags,char *,esp)
 
+/* called from init before execve -- need to be inline? -- Cort */
+static inline pid_t wait(int * wait_stat) 
+{
+	return waitpid(-1,wait_stat,0);
+}
 
-#endif /* __KERNEL_SYSCALLS__ */
+#endif
 
 #endif /* _ASM_PPC_UNISTD_H_ */
+
+
diff -u --recursive --new-file v2.1.15/linux/include/asm-ppc/unistd.h.cort linux/include/asm-ppc/unistd.h.cort
--- v2.1.15/linux/include/asm-ppc/unistd.h.cort	Mon Jul  8 11:27:43 1996
+++ linux/include/asm-ppc/unistd.h.cort	Thu Jan  1 02:00:00 1970
@@ -1,376 +0,0 @@
-#ifndef _ASM_PPC_UNISTD_H_
-#define _ASM_PPC_UNISTD_H_
-
-#define _NR(n) #n
-#define _lisc(n) "li 0," _NR(n)
-
-/*
- * This file contains the system call numbers.
- */
-
-#define __NR_setup		  0	/* used only by init, to get system going */
-#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_chown		 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_phys		 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_vm86		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_mlock		150
-#define __NR_munlock		151
-#define __NR_mlockall		152
-#define __NR_munlockall		153
-
-
-#define _syscall0(type,name) \
-type name(void) \
-{ \
-    long retval; \
-    __asm__  ( \
-	      "li 0, %0 \n\t" \
-	      "sc \n\t" \
-	      "mr 31,3 \n\t" \
-	      "bns 10f \n\t" \
-	      "mr 0,3 \n\t" \
-	      "lis 3,errno@ha \n\t" \
-	      "stw 0,errno@l(3) \n\t" \
-	      "li 3,-1 \n\t" \
-	      "10: \n\t" \
-	      : \
-	      : "i" (__NR_##name) \
-	      : "0", "31", "3", "cc", "memory" \
-	      );  \
-    return(retval);\
-}
-
-#define _syscall1(type,name,type1,arg1) \
-type name(type1 arg1) \
-{ \
-    long retval; \
-    __asm__  ( \
-	      "li 0, %0 \n\t" \
-	      "sc \n\t" \
-	      "mr 31,3 \n\t" \
-	      "bns 10f \n\t" \
-	      "mr 0,3 \n\t" \
-	      "lis 3,errno@ha \n\t" \
-	      "stw 0,errno@l(3) \n\t" \
-	      "li 3,-1 \n\t" \
-	      "10: \n\t" \
-	      : \
-	      : "i" (__NR_##name) \
-	      : "0", "31", "3", "cc", "memory" \
-	      );  \
-    return(retval); \
-}
-
-#define _syscall2(type,name,type1,arg1,type2,arg2) \
-type name(type1 arg1,type2 arg2) \
-{ \
-    long retval; \
-    __asm__  ( \
-	      "li 0, %0 \n\t" \
-	      "sc \n\t" \
-	      "mr 31,3 \n\t" \
-	      "bns 10f \n\t" \
-	      "mr 0,3 \n\t" \
-	      "lis 3,errno@ha \n\t" \
-	      "stw 0,errno@l(3) \n\t" \
-	      "li 3,-1 \n\t" \
-	      "10: \n\t" \
-	      : \
-	      : "i" (__NR_##name) \
-	      : "0", "31", "3", "cc", "memory" \
-	      );  \
-    return(retval); \
-}
-
-
-#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
-type name(type1 arg1,type2 arg2, type3 arg3) \
-{ \
-    long retval; \
-    __asm__  ( \
-	      "li 0, %0 \n\t" \
-	      "sc \n\t" \
-	      "mr 31,3 \n\t" \
-	      "bns 10f \n\t" \
-	      "mr 0,3 \n\t" \
-	      "lis 3,errno@ha \n\t" \
-	      "stw 0,errno@l(3) \n\t" \
-	      "li 3,-1 \n\t" \
-	      "10: \n\t" \
-	      : \
-	      : "i" (__NR_##name) \
-	      : "0", "31", "3", "cc", "memory" \
-	      );  \
-    return(retval); \
-}
-
-#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
-type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
-{ \
-    long retval; \
-    __asm__  ( \
-	      "li 0, %0 \n\t" \
-	      "sc \n\t" \
-	      "mr 31,3 \n\t" \
-	      "bns 10f \n\t" \
-	      "mr 0,3 \n\t" \
-	      "lis 3,errno@ha \n\t" \
-	      "stw 0,errno@l(3) \n\t" \
-	      "li 3,-1 \n\t" \
-	      "10: \n\t" \
-	      : \
-	      : "i" (__NR_##name) \
-	      : "0", "31", "3", "cc", "memory" \
-	      );  \
-    return(retval); \
-}
-
-#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
-	  type5,arg5) \
-type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
-{ \
-    long retval; \
-    __asm__  ( \
-	      "li 0, %0 \n\t" \
-	      "sc \n\t" \
-	      "mr 31,3 \n\t" \
-	      "bns 10f \n\t" \
-	      "mr 0,3 \n\t" \
-	      "lis 3,errno@ha \n\t" \
-	      "stw 0,errno@l(3) \n\t" \
-	      "li 3,-1 \n\t" \
-	      "10: \n\t" \
-	      : \
-	      : "i" (__NR_##name) \
-	      : "0", "31", "3", "cc", "memory" \
-	      );  \
-    return(retval); \
-}
-
-#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.
- */
-
-/*
-   some of these had problems getting the right arguments (namely sys_clone())
-   when they were inline so I made them non-inline until we get problems with gcc
-   worked out.  I need to check with Linus to find out which he wants inline now
-   since the above comment was written a long time ago.
-
-   Once I understand the macro language better this should go away.
-             -- Cort
- */
-
-#define __NR__exit __NR_exit
-static /*__inline__*/ _syscall0(int,setup) 
-static __inline__ _syscall0(int,idle) 
-static /*__inline__*/ _syscall0(int,fork)
-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__*/ _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__ _syscall2(int,clone,unsigned long,flags,char *,esp)
-static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-
-static __inline__ pid_t wait(int * wait_stat) 
-{
-	return waitpid(-1,wait_stat,0);
-}
-
-/*
-   This is the mechanism for creating a new kernel thread.
-   For the time being it only behaves the same as clone().
-   It should be changed very soon to work properly and cleanly.  This
-   gets us going for now, though.
-     -- Cort
- */
-static __inline__ long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-  long retval;
-  __asm__  (
-	"li 0, 120 \n\t"        /* __NR_clone */
-	"li 3, %5 \n\t"         /* load flags as arg to clone */
-	/*"mr 1,7 \n\t"*/		/* save kernel stack */
-	"sc \n\t"		/* syscall */
-	/*"cmp 0,1,7 \n\t"*/	/* if kernel stack changes -- child */
-	"cmpi	0,3,0 \n\t"
-	"bne 1f \n\t"		/* return if parent */
-	/* this is in child */
-	"li 3, %3 \n\t"		/* child -- load args and call fn */
-	"mtlr %4 \n\t"		
-	"blrl \n\t"
-	"li 0, %2 \n\t"		/* exit after child exits */
-        "li 3, 0 \n\t"
-	"sc \n\t"
-	/* parent */
-	"1: \n\t"
-	:"=3" (retval)
-	:"i" (__NR_clone), "i" (__NR_exit),
-	 "r" (arg), "r" (fn), "g" (CLONE_VM|flags) 
-	:"cc", "1", "0", "3", "7", "31", "memory" );
-  return retval;
-}
-
-
-#endif /* __KERNEL_SYSCALLS__ */
-
-#endif /* _ASM_PPC_UNISTD_H_ */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/a.out.h linux/include/asm-sparc/a.out.h
--- v2.1.15/linux/include/asm-sparc/a.out.h	Tue Nov 12 15:56:12 1996
+++ linux/include/asm-sparc/a.out.h	Fri Dec 13 11:37:39 1996
@@ -1,4 +1,4 @@
-/* $Id: a.out.h,v 1.9 1996/05/29 13:44:54 ecd Exp $ */
+/* $Id: a.out.h,v 1.11 1996/12/03 08:44:56 jj Exp $ */
 #ifndef __SPARC_A_OUT_H__
 #define __SPARC_A_OUT_H__
 
@@ -89,7 +89,9 @@
 
 #ifdef __KERNEL__
 
-#define STACK_TOP	TASK_SIZE
+extern unsigned long	stack_top;
+
+#define STACK_TOP	(stack_top)
 
 #endif
 
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/asmmacro.h linux/include/asm-sparc/asmmacro.h
--- v2.1.15/linux/include/asm-sparc/asmmacro.h	Tue Nov 12 15:56:12 1996
+++ linux/include/asm-sparc/asmmacro.h	Fri Dec 13 11:37:39 1996
@@ -34,12 +34,14 @@
  * c-code can be called.
  */
 #ifndef SMP_DEBUG
-#define SAVE_ALL \
+#define SAVE_ALL_HEAD \
 	sethi	%hi(trap_setup), %l4; \
-	jmpl	%l4 + %lo(trap_setup), %l6; \
+	jmpl	%l4 + %lo(trap_setup), %l6;
+#define SAVE_ALL \
+	SAVE_ALL_HEAD \
 	 nop;
 #else
-#define SAVE_ALL \
+#define SAVE_ALL_HEAD \
 	GET_PROCESSOR_ID(l4); \
 	set	C_LABEL(trap_log), %l5; \
 	sll	%l4, 11, %l6; \
@@ -59,7 +61,9 @@
 	and	%l6, 255, %l6; \
 	st	%l6, [%l5]; \
 	sethi	%hi(trap_setup), %l4; \
-	jmpl	%l4 + %lo(trap_setup), %l6; \
+	jmpl	%l4 + %lo(trap_setup), %l6;
+#define SAVE_ALL \
+	SAVE_ALL_HEAD \
 	 nop;
 #endif
 
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/atomic.h linux/include/asm-sparc/atomic.h
--- v2.1.15/linux/include/asm-sparc/atomic.h	Tue Nov 12 15:56:12 1996
+++ linux/include/asm-sparc/atomic.h	Fri Dec 13 11:37:39 1996
@@ -23,58 +23,93 @@
 {
 	__asm__ __volatile__("
 	rd	%%psr, %%g2
+	nop
+	nop
+	nop
 	andcc	%%g2, %2, %%g0
-	be,a	1f
-	 wr	%%g2, %2, %%psr
-1:	ld	[%0], %%g3
+	bne	1f
+	 nop
+	wr	%%g2, %2, %%psr
+	nop
+	nop
+	nop
+1:
+	ld	[%0], %%g3
 	add	%%g3, %1, %%g3
 	andcc	%%g2, %2, %%g0
 	st	%%g3, [%0]
-	be,a	1f
-	 wr	%%g2, 0x0, %%psr
-1:	nop; nop;
-        "
-        : : "r" (__atomic_fool_gcc(v)), "r" (i), "i" (PSR_PIL)
-        : "g2", "g3");
+	bne	1f
+	 nop
+	wr	%%g2, 0x0, %%psr
+	nop
+	nop
+	nop
+1:
+"	: /* no outputs */
+	: "r" (__atomic_fool_gcc(v)), "r" (i), "i" (PSR_PIL)
+	: "g2", "g3");
 }
 
 static __inline__ void atomic_sub(atomic_t i, atomic_t *v)
 {
 	__asm__ __volatile__("
 	rd	%%psr, %%g2
+	nop
+	nop
+	nop
 	andcc	%%g2, %2, %%g0
-	be,a	1f
-	 wr	%%g2, %2, %%psr
-1:	ld	[%0], %%g3
+	bne	1f
+	 nop
+	wr	%%g2, %2, %%psr
+	nop
+	nop
+	nop
+1:
+	ld	[%0], %%g3
 	sub	%%g3, %1, %%g3
 	andcc	%%g2, %2, %%g0
 	st	%%g3, [%0]
-	be,a	1f
-	 wr	%%g2, 0x0, %%psr
-1:       nop; nop;
-        "
-        : : "r" (__atomic_fool_gcc(v)), "r" (i), "i" (PSR_PIL)
-        : "g2", "g3");
+	bne	1f
+	 nop
+	wr	%%g2, 0x0, %%psr
+	nop
+	nop
+	nop
+1:
+"	: /* no outputs */
+	: "r" (__atomic_fool_gcc(v)), "r" (i), "i" (PSR_PIL)
+	: "g2", "g3");
 }
 
 static __inline__ int atomic_add_return(atomic_t i, atomic_t *v)
 {
 	__asm__ __volatile__("
 	rd	%%psr, %%g2
+	nop
+	nop
+	nop
 	andcc	%%g2, %3, %%g0
-	be,a	1f
-	 wr	%%g2, %3, %%psr
-1:	ld	[%1], %%g3
+	bne	1f
+	 nop
+	wr	%%g2, %3, %%psr
+	nop
+	nop
+	nop
+1:
+	ld	[%1], %%g3
 	add	%%g3, %2, %0
 	andcc	%%g2, %3, %%g0
 	st	%0, [%1]
-	be,a	1f
-	 wr	%%g2, 0x0, %%psr
-1:	nop; nop;
-        "
-        : "=&r" (i)
-        : "r" (__atomic_fool_gcc(v)), "0" (i), "i" (PSR_PIL)
-        : "g2", "g3");
+	bne	1f
+	 nop
+	wr	%%g2, 0x0, %%psr
+	nop
+	nop
+	nop
+1:
+"	: "=&r" (i)
+	: "r" (__atomic_fool_gcc(v)), "0" (i), "i" (PSR_PIL)
+	: "g2", "g3");
 
 	return i;
 }
@@ -83,20 +118,31 @@
 {
 	__asm__ __volatile__("
 	rd	%%psr, %%g2
+	nop
+	nop
+	nop
 	andcc	%%g2, %3, %%g0
-	be,a	1f
-	 wr	%%g2, %3, %%psr
-1:	ld	[%1], %%g3
+	bne	1f
+	 nop
+	wr	%%g2, %3, %%psr
+	nop
+	nop
+	nop
+1:
+	ld	[%1], %%g3
 	sub	%%g3, %2, %0
 	andcc	%%g2, %3, %%g0
 	st	%0, [%1]
-	be,a	1f
-	 wr	%%g2, 0x0, %%psr
-1:	nop; nop;
-        "
-        : "=&r" (i)
-        : "r" (__atomic_fool_gcc(v)), "0" (i), "i" (PSR_PIL)
-        : "g2", "g3");
+	bne	1f
+	 nop
+	wr	%%g2, 0x0, %%psr
+	nop
+	nop
+	nop
+1:
+"	: "=&r" (i)
+	: "r" (__atomic_fool_gcc(v)), "0" (i), "i" (PSR_PIL)
+	: "g2", "g3");
 
 	return i;
 }
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/auxio.h linux/include/asm-sparc/auxio.h
--- v2.1.15/linux/include/asm-sparc/auxio.h	Tue Nov 12 15:56:12 1996
+++ linux/include/asm-sparc/auxio.h	Fri Dec 13 11:37:39 1996
@@ -1,4 +1,4 @@
-/* $Id: auxio.h,v 1.14 1996/10/31 06:29:10 davem Exp $
+/* $Id: auxio.h,v 1.15 1996/12/06 00:37:11 davem Exp $
  * auxio.h:  Definitions and code for the Auxiliary I/O register.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -56,6 +56,8 @@
 		*AUXREG = ((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN;
 		break;
 	case sun4m:
+		if(!AUXREG)
+			break;     /* VME chassic sun4m, no auxio. */
 		regval = *AUXREG;
 		*AUXREG = ((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN4M;
 		break;
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/bitops.h linux/include/asm-sparc/bitops.h
--- v2.1.15/linux/include/asm-sparc/bitops.h	Tue Nov 12 15:56:12 1996
+++ linux/include/asm-sparc/bitops.h	Fri Dec 13 11:37:40 1996
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.36 1996/09/29 22:57:21 davem Exp $
+/* $Id: bitops.h,v 1.39 1996/12/10 06:06:35 davem Exp $
  * bitops.h: Bit string operations on the Sparc.
  *
  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -104,19 +104,30 @@
 	mask = 1 << (nr & 31);
 	__asm__ __volatile__("
 	rd	%%psr, %%g3
+	nop
+	nop
+	nop
 	andcc	%%g3, %3, %%g0
-	be,a	1f
-	 wr	%%g3, %3, %%psr
-1:	ld	[%0], %%g4
+	bne	1f
+	 nop
+	wr	%%g3, %3, %%psr
+	nop
+	nop
+	nop
+1:
+	ld	[%0], %%g4
 	or	%%g4, %2, %%g2
 	andcc	%%g3, %3, %%g0
 	st	%%g2, [%0]
-	be,a	1f
-	 wr	%%g3, 0x0, %%psr
-1:	nop
+	bne	1f
+	 nop
+	wr	%%g3, 0x0, %%psr
+	nop
+	nop
+	nop
+1:
 	and	%%g4, %2, %0
-	"
-	: "=&r" (ADDR)
+"	: "=&r" (ADDR)
 	: "0" (ADDR), "r" (mask), "i" (PSR_PIL)
 	: "g2", "g3", "g4");
 
@@ -132,19 +143,30 @@
 	mask = 1 << (nr & 31);
 	__asm__ __volatile__("
 	rd	%%psr, %%g3
+	nop
+	nop
+	nop
 	andcc	%%g3, %3, %%g0
-	be,a	1f
-	 wr	%%g3, %3, %%psr
-1:	ld	[%0], %%g4
+	bne	1f
+	 nop
+	wr	%%g3, %3, %%psr
+	nop
+	nop
+	nop
+1:
+	ld	[%0], %%g4
 	andn	%%g4, %2, %%g2
 	andcc	%%g3, %3, %%g0
 	st	%%g2, [%0]
-	be,a	1f
+	bne	1f
+	 nop
 	wr	%%g3, 0x0, %%psr
-1:	nop
+	nop
+	nop
+	nop
+1:
 	and	%%g4, %2, %0
-	"
-	: "=&r" (ADDR)
+"	: "=&r" (ADDR)
 	: "0" (ADDR), "r" (mask), "i" (PSR_PIL)
 	: "g2", "g3", "g4");
 
@@ -160,19 +182,30 @@
 	mask = 1 << (nr & 31);
 	__asm__ __volatile__("
 	rd	%%psr, %%g3
+	nop
+	nop
+	nop
 	andcc	%%g3, %3, %%g0
-	be,a	1f
-	 wr	%%g3, %3, %%psr
-1:	ld	[%0], %%g4
+	bne	1f
+	 nop
+	wr	%%g3, %3, %%psr
+	nop
+	nop
+	nop
+1:
+	ld	[%0], %%g4
 	xor	%%g4, %2, %%g2
 	andcc	%%g3, %3, %%g0
 	st	%%g2, [%0]
-	be,a	1f
-	 wr	%%g3, 0x0, %%psr
-1:	nop
+	bne	1f
+	 nop
+	wr	%%g3, 0x0, %%psr
+	nop
+	nop
+	nop
+1:
 	and	%%g4, %2, %0
-	"
-	: "=&r" (ADDR)
+"	: "=&r" (ADDR)
 	: "0" (ADDR), "r" (mask), "i" (PSR_PIL)
 	: "g2", "g3", "g4");
 
@@ -249,7 +282,7 @@
 
 #ifndef __KERNEL__
 
-extern __inline__ int __ext2_set_bit(int nr, void *addr)
+extern __inline__ int set_le_bit(int nr, void *addr)
 {
 	int		mask;
 	unsigned char	*ADDR = (unsigned char *) addr;
@@ -269,7 +302,7 @@
 	return (int) ADDR;
 }
 
-extern __inline__ int __ext2_clear_bit(int nr, void *addr)
+extern __inline__ int clear_le_bit(int nr, void *addr)
 {
 	int		mask;
 	unsigned char	*ADDR = (unsigned char *) addr;
@@ -293,7 +326,7 @@
 
 /* Now for the ext2 filesystem bit operations and helper routines. */
 
-extern __inline__ int __ext2_set_bit(int nr,void * addr)
+extern __inline__ int set_le_bit(int nr,void * addr)
 {
 	int		mask;
 	unsigned char	*ADDR = (unsigned char *) addr;
@@ -302,26 +335,37 @@
 	mask = 1 << (nr & 0x07);
 	__asm__ __volatile__("
 	rd	%%psr, %%g3
+	nop
+	nop
+	nop
 	andcc	%%g3, %3, %%g0
-	be,a	1f
-	 wr	%%g3, %3, %%psr
-1:	ldub	[%0], %%g4
+	bne	1f
+	 nop
+	wr	%%g3, %3, %%psr
+	nop
+	nop
+	nop
+1:
+	ldub	[%0], %%g4
 	or	%%g4, %2, %%g2
 	andcc	%%g3, %3, %%g0
 	stb	%%g2, [%0]
-	be,a	1f
-	 wr	%%g3, 0x0, %%psr
-1:	nop
+	bne	1f
+	 nop
+	wr	%%g3, 0x0, %%psr
+	nop
+	nop
+	nop
+1:
 	and	%%g4, %2, %0
-	"
-	: "=&r" (ADDR)
+"	: "=&r" (ADDR)
 	: "0" (ADDR), "r" (mask), "i" (PSR_PIL)
 	: "g2", "g3", "g4");
 
 	return (int) ADDR;
 }
 
-extern __inline__ int __ext2_clear_bit(int nr, void * addr)
+extern __inline__ int clear_le_bit(int nr, void * addr)
 {
 	int		mask;
 	unsigned char	*ADDR = (unsigned char *) addr;
@@ -330,19 +374,30 @@
 	mask = 1 << (nr & 0x07);
 	__asm__ __volatile__("
 	rd	%%psr, %%g3
+	nop
+	nop
+	nop
 	andcc	%%g3, %3, %%g0
-	be,a	1f
-	 wr	%%g3, %3, %%psr
-1:	ldub	[%0], %%g4
+	bne	1f
+	 nop
+	wr	%%g3, %3, %%psr
+	nop
+	nop
+	nop
+1:
+	ldub	[%0], %%g4
 	andn	%%g4, %2, %%g2
 	andcc	%%g3, %3, %%g0
 	stb	%%g2, [%0]
-	be,a	1f
+	bne	1f
+	 nop
 	wr	%%g3, 0x0, %%psr
-1:	nop
+	nop
+	nop
+	nop
+1:
 	and	%%g4, %2, %0
-	"
-	: "=&r" (ADDR)
+"	: "=&r" (ADDR)
 	: "0" (ADDR), "r" (mask), "i" (PSR_PIL)
 	: "g2", "g3", "g4");
 
@@ -351,7 +406,7 @@
 
 #endif /* __KERNEL__ */
 
-extern __inline__ int __ext2_test_bit(int nr, __const__ void * addr)
+extern __inline__ int test_le_bit(int nr, __const__ void * addr)
 {
 	int			mask;
 	__const__ unsigned char	*ADDR = (__const__ unsigned char *) addr;
@@ -361,21 +416,24 @@
 	return ((mask & *ADDR) != 0);
 }
 
-extern __inline__ unsigned short __swab16(unsigned short value)
-{
-        return ((value >> 8) | (value << 8));
-}     
+#ifdef __KERNEL__
+
+#define ext2_set_bit   set_le_bit
+#define ext2_clear_bit clear_le_bit
+#define ext2_test_bit  test_le_bit
+
+#endif /* __KERNEL__ */
+
+#define find_first_zero_le_bit(addr, size) \
+        find_next_zero_le_bit((addr), (size), 0)
 
 extern __inline__ unsigned long __swab32(unsigned long value)
 {
-        return ((value >> 24) | ((value >> 8) & 0xff00) |
-               ((value << 8) & 0xff0000) | (value << 24));
+	return((value>>24) | ((value>>8)&0xff00) |
+	       ((value<<8)&0xff0000) | (value<<24));
 }     
 
-#define __ext2_find_first_zero_bit(addr, size) \
-        __ext2_find_next_zero_bit((addr), (size), 0)
-
-extern __inline__ unsigned long __ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
+extern __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long size, unsigned long offset)
 {
 	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
 	unsigned long result = offset & ~31UL;
@@ -411,5 +469,11 @@
 	return result + ffz(__swab32(tmp));
 }
 
-#endif /* defined(_SPARC_BITOPS_H) */
+#ifdef __KERNEL__
+
+#define ext2_find_first_zero_bit     find_first_zero_le_bit
+#define ext2_find_next_zero_bit      find_next_zero_le_bit
 
+#endif /* __KERNEL__ */
+
+#endif /* defined(_SPARC_BITOPS_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/byteorder.h linux/include/asm-sparc/byteorder.h
--- v2.1.15/linux/include/asm-sparc/byteorder.h	Tue Nov 12 15:56:12 1996
+++ linux/include/asm-sparc/byteorder.h	Fri Dec 13 11:37:40 1996
@@ -1,4 +1,4 @@
-/* $Id: byteorder.h,v 1.9 1996/08/30 05:21:34 davem Exp $ */
+/* $Id: byteorder.h,v 1.11 1996/11/19 11:26:13 davem Exp $ */
 #ifndef _SPARC_BYTEORDER_H
 #define _SPARC_BYTEORDER_H
 
@@ -20,5 +20,37 @@
 #ifndef __BIG_ENDIAN_BITFIELD
 #define __BIG_ENDIAN_BITFIELD
 #endif
+
+#ifdef __KERNEL__
+
+/* Convert from CPU byte order, to specified byte order. */
+extern __inline__ __u16 cpu_to_le16(__u16 value)
+{
+	return (value >> 8) | (value << 8);
+}
+
+extern __inline__ __u32 cpu_to_le32(__u32 value)
+{
+	return((value>>24) | ((value>>8)&0xff00) |
+	       ((value<<8)&0xff0000) | (value<<24));
+}
+#define cpu_to_be16(x)  (x)
+#define cpu_to_be32(x)  (x)
+
+/* Convert from specified byte order, to CPU byte order. */
+extern __inline__ __u16 le16_to_cpu(__u16 value)
+{
+	return (value >> 8) | (value << 8);
+}
+
+extern __inline__ __u32 le32_to_cpu(__u32 value)
+{
+	return((value>>24) | ((value>>8)&0xff00) |
+	       ((value<<8)&0xff0000) | (value<<24));
+}
+#define be16_to_cpu(x)  (x)
+#define be32_to_cpu(x)  (x)
+
+#endif /* __KERNEL__ */
 
 #endif /* !(_SPARC_BYTEORDER_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/head.h linux/include/asm-sparc/head.h
--- v2.1.15/linux/include/asm-sparc/head.h	Tue Nov 12 15:56:12 1996
+++ linux/include/asm-sparc/head.h	Fri Dec 13 11:37:40 1996
@@ -1,4 +1,4 @@
-/* $Id: head.h,v 1.30 1996/07/29 21:00:28 miguel Exp $ */
+/* $Id: head.h,v 1.32 1996/12/04 00:12:48 ecd Exp $ */
 #ifndef __SPARC_HEAD_H
 #define __SPARC_HEAD_H
 
@@ -54,16 +54,16 @@
 
 /* Software trap for Slowaris system calls. */
 #define SOLARIS_SYSCALL_TRAP \
-        sethi %hi(C_LABEL(sys_call_table)), %l7; \
-        or %l7, %lo(C_LABEL(sys_call_table)), %l7; \
         b solaris_syscall; \
-        rd %psr, %l0;
+        rd %psr, %l0; \
+        nop; \
+        nop;
 
 #define INDIRECT_SOLARIS_SYSCALL(x) \
-        sethi %hi(C_LABEL(sys_call_table)), %l7; \
-	or %g0,%lo(x),%g1; \
-	b solaris_indirect_syscall; \
-        rd %psr, %l0; 
+	mov x, %g1; \
+	b solaris_syscall; \
+	rd %psr, %l0; \
+	nop;
 
 #define BREAKPOINT_TRAP \
 	b breakpoint_trap; \
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/io.h linux/include/asm-sparc/io.h
--- v2.1.15/linux/include/asm-sparc/io.h	Tue Nov 12 15:56:12 1996
+++ linux/include/asm-sparc/io.h	Fri Dec 13 11:37:40 1996
@@ -1,4 +1,4 @@
-/* $Id: io.h,v 1.10 1996/08/29 09:48:14 davem Exp $ */
+/* $Id: io.h,v 1.11 1996/11/19 11:26:14 davem Exp $ */
 #ifndef __SPARC_IO_H
 #define __SPARC_IO_H
 
@@ -138,5 +138,8 @@
 extern void *sparc_alloc_io (void *, void *, int, char *, int, int);
 extern void sparc_free_io (void *, int);
 extern void *sparc_dvma_malloc (int, char *);
+
+#define virt_to_phys(x) __pa((unsigned long)(x))
+#define phys_to_virt(x) __va((unsigned long)(x))
 
 #endif /* !(__SPARC_IO_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/page.h linux/include/asm-sparc/page.h
--- v2.1.15/linux/include/asm-sparc/page.h	Tue Nov 12 15:56:13 1996
+++ linux/include/asm-sparc/page.h	Fri Dec 13 11:37:40 1996
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.30 1996/10/27 08:55:30 davem Exp $
+/* $Id: page.h,v 1.33 1996/12/03 08:44:55 jj Exp $
  * page.h:  Various defines and such for MMU operations on the Sparc for
  *          the Linux kernel.
  *
@@ -129,6 +129,10 @@
  * place the page pool both above the kernel and below the kernel.
  */
 #define MAP_NR(addr) ((((unsigned long) (addr)) - PAGE_OFFSET) >> PAGE_SHIFT)
+
+#else /* !(__ASSEMBLY__) */
+
+#define __pgprot(x)	(x)
 
 #endif /* !(__ASSEMBLY__) */
 
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h
--- v2.1.15/linux/include/asm-sparc/pgtable.h	Tue Nov 12 15:56:13 1996
+++ linux/include/asm-sparc/pgtable.h	Fri Dec 13 11:37:40 1996
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.51 1996/10/27 08:55:32 davem Exp $ */
+/* $Id: pgtable.h,v 1.54 1996/12/03 02:38:31 davem Exp $ */
 #ifndef _SPARC_PGTABLE_H
 #define _SPARC_PGTABLE_H
 
@@ -255,6 +255,8 @@
 
 extern pgd_t * (*pgd_alloc)(void);
 
+extern void (*pgd_flush)(pgd_t *);
+
 /* Fine grained cache/tlb flushing. */
 
 #ifdef __SMP__
@@ -272,6 +274,8 @@
 
 extern void (*local_flush_page_to_ram)(unsigned long address);
 
+extern void (*local_flush_sig_insns)(struct mm_struct *mm, unsigned long insn_addr);
+
 extern void smp_flush_cache_all(void);
 extern void smp_flush_cache_mm(struct mm_struct *mm);
 extern void smp_flush_cache_range(struct mm_struct *mm,
@@ -286,6 +290,7 @@
 				  unsigned long end);
 extern void smp_flush_tlb_page(struct vm_area_struct *mm, unsigned long page);
 extern void smp_flush_page_to_ram(unsigned long page);
+extern void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
 #endif
 
 extern void (*flush_cache_all)(void);
@@ -301,6 +306,8 @@
 
 extern void (*flush_page_to_ram)(unsigned long page);
 
+extern void (*flush_sig_insns)(struct mm_struct *mm, unsigned long insn_addr);
+
 /* The permissions for pgprot_val to make a page mapped on the obio space */
 extern unsigned int pg_iobits;
 
@@ -329,9 +336,9 @@
 
 extern int invalid_segment;
 
-#define SWP_TYPE(entry) (((entry)>>2) & 0x7f)
-#define SWP_OFFSET(entry) (((entry) >> 9) & 0x7ffff)
-#define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << 9))
+#define SWP_TYPE(entry) (((entry) >> 2) & 0x7f)
+#define SWP_OFFSET(entry) (((entry) >> 9) & 0x3ffff)
+#define SWP_ENTRY(type,offset) ((((type) & 0x7f) << 2) | (((offset) & 0x3ffff) << 9))
 
 struct ctx_list {
 	struct ctx_list *next;
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/pgtsun4c.h linux/include/asm-sparc/pgtsun4c.h
--- v2.1.15/linux/include/asm-sparc/pgtsun4c.h	Tue Nov 12 15:56:13 1996
+++ linux/include/asm-sparc/pgtsun4c.h	Fri Dec 13 11:37:40 1996
@@ -1,4 +1,4 @@
-/* $Id: pgtsun4c.h,v 1.27 1996/10/30 06:01:32 davem Exp $
+/* $Id: pgtsun4c.h,v 1.32 1996/12/08 08:39:04 davem Exp $
  * pgtsun4c.h:  Sun4c specific pgtable.h defines and code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -44,29 +44,35 @@
 /*
  * Sparc SUN4C pte fields.
  */
-#define _SUN4C_PAGE_VALID     0x80000000   /* valid page */
-#define _SUN4C_PAGE_WRITE     0x40000000   /* can be written to */
-#define _SUN4C_PAGE_PRIV      0x20000000   /* bit to signify privileged page */
-#define _SUN4C_PAGE_USER      0x00000000   /* User page */
-#define _SUN4C_PAGE_NOCACHE   0x10000000   /* non-cacheable page */
-#define _SUN4C_PAGE_IO        0x04000000   /* I/O page */
-#define _SUN4C_PAGE_REF       0x02000000   /* Page has been accessed/referenced */
-#define _SUN4C_PAGE_DIRTY     0x01000000   /* Page has been modified, is dirty */
-#define _SUN4C_PAGE_PRESENT   0x00400000   /* present (known) page */
-
-#define _SUN4C_PAGE_CHG_MASK  (0xffff | _SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY)
-
-#define SUN4C_PAGE_NONE     __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_PRIV | \
-				     _SUN4C_PAGE_REF)
-#define SUN4C_PAGE_SHARED   __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | \
-				     _SUN4C_PAGE_USER | _SUN4C_PAGE_REF)
-#define SUN4C_PAGE_COPY     __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_USER | \
-				     _SUN4C_PAGE_REF)
-#define SUN4C_PAGE_READONLY __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_USER | \
-				     _SUN4C_PAGE_REF)
-#define SUN4C_PAGE_KERNEL   __pgprot(_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE | \
-				     _SUN4C_PAGE_PRIV | _SUN4C_PAGE_DIRTY | \
-				     _SUN4C_PAGE_REF | _SUN4C_PAGE_NOCACHE)
+#define _SUN4C_PAGE_VALID        0x80000000
+#define _SUN4C_PAGE_SILENT_READ  0x80000000   /* synonym */
+#define _SUN4C_PAGE_DIRTY        0x40000000
+#define _SUN4C_PAGE_SILENT_WRITE 0x40000000   /* synonym */
+#define _SUN4C_PAGE_PRIV         0x20000000   /* privileged page */
+#define _SUN4C_PAGE_NOCACHE      0x10000000   /* non-cacheable page */
+#define _SUN4C_PAGE_PRESENT      0x08000000   /* implemented in software */
+#define _SUN4C_PAGE_IO           0x04000000   /* I/O page */
+#define _SUN4C_PAGE_READ         0x00800000   /* implemented in software */
+#define _SUN4C_PAGE_WRITE        0x00400000   /* implemented in software */
+#define _SUN4C_PAGE_ACCESSED     0x00200000   /* implemented in software */
+#define _SUN4C_PAGE_MODIFIED     0x00100000   /* implemented in software */
+
+#define _SUN4C_READABLE		(_SUN4C_PAGE_READ|_SUN4C_PAGE_SILENT_READ|\
+				 _SUN4C_PAGE_ACCESSED)
+#define _SUN4C_WRITEABLE	(_SUN4C_PAGE_WRITE|_SUN4C_PAGE_SILENT_WRITE|\
+				 _SUN4C_PAGE_MODIFIED)
+
+#define _SUN4C_PAGE_CHG_MASK	(0xffff|_SUN4C_PAGE_ACCESSED|_SUN4C_PAGE_MODIFIED)
+
+#define SUN4C_PAGE_NONE		__pgprot(_SUN4C_PAGE_PRESENT)
+#define SUN4C_PAGE_SHARED	__pgprot(_SUN4C_PAGE_PRESENT|_SUN4C_READABLE|\
+					 _SUN4C_PAGE_WRITE)
+#define SUN4C_PAGE_COPY		__pgprot(_SUN4C_PAGE_PRESENT|_SUN4C_READABLE)
+#define SUN4C_PAGE_READONLY	__pgprot(_SUN4C_PAGE_PRESENT|_SUN4C_READABLE)
+#define SUN4C_PAGE_KERNEL	__pgprot(_SUN4C_READABLE|_SUN4C_WRITEABLE|\
+					 _SUN4C_PAGE_DIRTY|_SUN4C_PAGE_PRIV)
+
+#ifndef __ASSEMBLY__
 
 extern __inline__ unsigned long sun4c_get_synchronous_error(void)
 {
@@ -124,7 +130,7 @@
 {
   __asm__ __volatile__("\n\tsta %1, [%0] %2\n\t" : :
 		       "r" (addr), 
-		       "r" (entry), "i" (ASI_PTE));
+		       "r" ((entry & ~(_SUN4C_PAGE_PRESENT))), "i" (ASI_PTE));
 
   return;
 }
@@ -147,5 +153,7 @@
 
   return ctx;
 }
+
+#endif /* !(__ASSEMBLY__) */
 
 #endif /* !(_SPARC_PGTSUN4C_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/processor.h linux/include/asm-sparc/processor.h
--- v2.1.15/linux/include/asm-sparc/processor.h	Tue Nov 12 15:56:13 1996
+++ linux/include/asm-sparc/processor.h	Fri Dec 13 11:37:40 1996
@@ -1,4 +1,4 @@
-/* $Id: processor.h,v 1.48 1996/10/27 08:55:36 davem Exp $
+/* $Id: processor.h,v 1.52 1996/12/03 08:44:56 jj Exp $
  * include/asm-sparc/processor.h
  *
  * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
@@ -29,7 +29,10 @@
 #define wp_works_ok 1
 #define wp_works_ok__is_a_macro /* for versions in ksyms.c */
 
-/* Whee, this is STACK_TOP and the lowest kernel address too... */
+/* Whee, this is STACK_TOP + PAGE_SIZE and the lowest kernel address too... 
+ * That one page is used to protect kernel from intruders, so that
+ * we can make our access_ok test faster
+ */
 #define TASK_SIZE	(page_offset)
 
 /* Ok this is hot.  Sparc exception save area. */
@@ -80,6 +83,7 @@
 	struct exception_struct ex __attribute__ ((aligned (8)));
 	int current_ds;
 	struct exec core_exec;     /* just what it says. */
+	int new_signal;
 };
 
 #define SPARC_FLAG_KTHREAD      0x1    /* task is a kernel thread */
@@ -111,6 +115,8 @@
    SPARC_FLAG_KTHREAD, { 0, }, USER_DS, \
 /* core_exec */ \
 { 0, }, \
+/* new_signal */ \
+  0, \
 }
 
 /* Return saved PC of a blocked thread. */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/psr.h linux/include/asm-sparc/psr.h
--- v2.1.15/linux/include/asm-sparc/psr.h	Tue Nov 12 15:56:13 1996
+++ linux/include/asm-sparc/psr.h	Fri Dec 13 11:37:40 1996
@@ -1,4 +1,4 @@
-/* $Id: psr.h,v 1.12 1996/09/30 02:23:19 davem Exp $
+/* $Id: psr.h,v 1.13 1996/12/10 06:06:36 davem Exp $
  * psr.h: This file holds the macros for masking off various parts of
  *        the processor status register on the Sparc. This is valid
  *        for Version 8. On the V9 this is renamed to the PSTATE
@@ -41,16 +41,28 @@
 extern __inline__ unsigned int get_psr(void)
 {
 	unsigned int psr;
-	__asm__ __volatile__("rd\t%%psr, %0" :
-			     "=r" (psr));
+	__asm__ __volatile__("
+		rd	%%psr, %0
+		nop
+		nop
+		nop
+"	: "=r" (psr)
+	: /* no inputs */
+	: "memory");
+
 	return psr;
 }
 
 extern __inline__ void put_psr(unsigned int new_psr)
 {
-	__asm__ __volatile__("wr\t%0, 0x0, %%psr\n\t"
-			     "nop; nop; nop;" : :
-			     "r" (new_psr));
+	__asm__ __volatile__("
+		wr	%0, 0x0, %%psr
+		nop
+		nop
+		nop
+"	: /* no outputs */
+	: "r" (new_psr)
+	: "memory");
 }
 
 /* Get the %fsr register.  Be careful, make sure the floating point
@@ -64,10 +76,12 @@
 {
 	unsigned int fsr = 0;
 
-	__asm__ __volatile__("st\t%%fsr, %1\n\t"
-			     "ld\t%1, %0" :
-			     "=r" (fsr) :
-			     "m" (fsr_storage));
+	__asm__ __volatile__("
+		st	%%fsr, %1
+		ld	%1, %0
+"	: "=r" (fsr)
+	: "m" (fsr_storage));
+
 	return fsr;
 }
 
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/ptrace.h linux/include/asm-sparc/ptrace.h
--- v2.1.15/linux/include/asm-sparc/ptrace.h	Tue Nov 12 15:56:13 1996
+++ linux/include/asm-sparc/ptrace.h	Fri Dec 13 11:37:40 1996
@@ -1,4 +1,4 @@
-/* $Id: ptrace.h,v 1.22 1996/10/27 08:55:38 davem Exp $ */
+/* $Id: ptrace.h,v 1.23 1996/11/25 03:30:24 ecd Exp $ */
 #ifndef _SPARC_PTRACE_H
 #define _SPARC_PTRACE_H
 
@@ -73,7 +73,7 @@
 #define REGWIN_SZ         0x40
 #endif
 
-/* First generic task_struct offsets. sizeof(task_struct)=1616 */
+/* First generic task_struct offsets. sizeof(task_struct)=1552 */
 #define TASK_STATE        0x000
 #define TASK_PRIORITY     0x008
 #define TASK_SIGNAL       0x00c
@@ -83,28 +83,28 @@
 #define TASK_KSTACK_PG    0x058
 
 /* Thread stuff. */
-#define THREAD_UMASK      0x210
-#define THREAD_SADDR      0x218
-#define THREAD_SDESC      0x21c
-#define THREAD_KSP        0x220
-#define THREAD_KPC        0x224
-#define THREAD_KPSR       0x228
-#define THREAD_KWIM       0x22c
-#define THREAD_FORK_KPSR  0x230
-#define THREAD_FORK_KWIM  0x234
-#define THREAD_REG_WINDOW 0x238
-#define THREAD_STACK_PTRS 0x438
-#define THREAD_W_SAVED    0x458
-#define THREAD_FLOAT_REGS 0x460
-#define THREAD_FSR        0x560
-#define THREAD_SIGSTK     0x5e8
-#define THREAD_FLAGS      0x5f0
-#define THREAD_EX_COUNT   0x5f8
-#define THREAD_EX_PC      0x5fc
-#define THREAD_EX_EXPC    0x600
-#define THREAD_EX_ADDR    0x604
-#define THREAD_DS         0x608
-#define THREAD_MM         0x638
+#define THREAD_UMASK      0x1e0
+#define THREAD_SADDR      0x1e8
+#define THREAD_SDESC      0x1ec
+#define THREAD_KSP        0x1f0
+#define THREAD_KPC        0x1f4
+#define THREAD_KPSR       0x1f8
+#define THREAD_KWIM       0x1fc
+#define THREAD_FORK_KPSR  0x200
+#define THREAD_FORK_KWIM  0x204
+#define THREAD_REG_WINDOW 0x208
+#define THREAD_STACK_PTRS 0x408
+#define THREAD_W_SAVED    0x428
+#define THREAD_FLOAT_REGS 0x430
+#define THREAD_FSR        0x530
+#define THREAD_SIGSTK     0x5b8
+#define THREAD_FLAGS      0x5c0
+#define THREAD_EX_COUNT   0x5c8
+#define THREAD_EX_PC      0x5cc
+#define THREAD_EX_EXPC    0x5d0
+#define THREAD_EX_ADDR    0x5d4
+#define THREAD_DS         0x5d8
+#define THREAD_MM         0x608
 #define THREAD_MM_CTX     0x008
 
 /* These are for pt_regs. */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/resource.h linux/include/asm-sparc/resource.h
--- v2.1.15/linux/include/asm-sparc/resource.h	Fri Aug 23 15:30:15 1996
+++ linux/include/asm-sparc/resource.h	Fri Dec 13 11:37:40 1996
@@ -1,4 +1,4 @@
-/* $Id: resource.h,v 1.5 1995/11/25 02:32:35 davem Exp $
+/* $Id: resource.h,v 1.6 1996/11/25 03:30:25 ecd Exp $
  * resource.h: Resource definitions.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -20,7 +20,9 @@
 #define RLIMIT_NOFILE	6		/* max number of open files */
 #define RLIMIT_NPROC	7		/* max number of processes */
 #define RLIMIT_MEMLOCK  8               /* max locked-in-memory address space */
-#define RLIM_NLIMITS	9
+#define RLIMIT_AS       9               /* address space limit */
+
+#define RLIM_NLIMITS	10
 
 #ifdef __KERNEL__
 
@@ -29,8 +31,8 @@
     {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX},				\
     {LONG_MAX, LONG_MAX}, {_STK_LIM, _STK_LIM},				\
     {       0, LONG_MAX}, {LONG_MAX, LONG_MAX},				\
-    {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, {NR_OPEN, NR_OPEN},	\
-    {LONG_MAX, LONG_MAX},                                               \
+    {NR_OPEN, NR_OPEN}, {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER},	\
+    {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}                          \
 }
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/sigcontext.h linux/include/asm-sparc/sigcontext.h
--- v2.1.15/linux/include/asm-sparc/sigcontext.h	Tue Nov 12 15:56:13 1996
+++ linux/include/asm-sparc/sigcontext.h	Fri Dec 13 11:37:40 1996
@@ -1,4 +1,4 @@
-/* $Id: sigcontext.h,v 1.9 1996/10/27 08:55:42 davem Exp $ */
+/* $Id: sigcontext.h,v 1.10 1996/11/27 01:46:51 miguel Exp $ */
 #ifndef _ASMsparc_SIGCONTEXT_H
 #define _ASMsparc_SIGCONTEXT_H
 
@@ -36,7 +36,19 @@
 	/* Windows to restore after signal */
 	struct reg_window sigc_wbuf[SUNOS_MAXWIN];
 };
+
+typedef struct {
+	struct     pt_regs si_regs;
+	unsigned   long si_float_regs [64];
+	unsigned   long si_fsr;
+	unsigned   long si_fpqdepth;
+	struct {
+		unsigned long *insn_addr;
+		unsigned long insn;
+	} si_fpqueue [16];
+	int si_mask;
+} __siginfo_t;
+
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(_ASMsparc_SIGCONTEXT_H) */
-
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/socket.h linux/include/asm-sparc/socket.h
--- v2.1.15/linux/include/asm-sparc/socket.h	Sun Apr 21 12:30:34 1996
+++ linux/include/asm-sparc/socket.h	Fri Dec 13 11:37:40 1996
@@ -1,4 +1,4 @@
-/* $Id: socket.h,v 1.6 1996/04/04 12:51:26 davem Exp $ */
+/* $Id: socket.h,v 1.8 1996/12/12 19:21:43 davem Exp $ */
 #ifndef _ASM_SOCKET_H
 #define _ASM_SOCKET_H
 
@@ -8,14 +8,20 @@
 #define SOL_SOCKET	0xffff
 
 #define SO_DEBUG	0x0001
+#define SO_PASSCRED	0x0002
 #define SO_REUSEADDR	0x0004
 #define SO_KEEPALIVE	0x0008
 #define SO_DONTROUTE	0x0010
 #define SO_BROADCAST	0x0020
+#define SO_PEERCRED	0x0040
 #define SO_LINGER	0x0080
 #define SO_OOBINLINE	0x0100
 /* To add :#define SO_REUSEPORT 0x0200 */
 #define SO_BSDCOMPAT    0x0400
+#define SO_RCVLOWAT     0x0800
+#define SO_SNDLOWAT     0x1000
+#define SO_RCVTIMEO     0x2000
+#define SO_SNDTIMEO     0x4000
 
 /* wha!??? */
 #define SO_DONTLINGER   (~SO_LINGER)  /* Older SunOS compat. hack */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/system.h linux/include/asm-sparc/system.h
--- v2.1.15/linux/include/asm-sparc/system.h	Tue Nov 12 15:56:13 1996
+++ linux/include/asm-sparc/system.h	Fri Dec 13 11:37:40 1996
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.42 1996/09/30 02:23:21 davem Exp $ */
+/* $Id: system.h,v 1.43 1996/12/10 06:06:37 davem Exp $ */
 #ifndef __SPARC_SYSTEM_H
 #define __SPARC_SYSTEM_H
 
@@ -88,14 +88,23 @@
 	task_pc = ((unsigned long) &&here) - 0x8;					\
 	__asm__ __volatile__(								\
 	"rd\t%%psr, %%g4\n\t"								\
+	"nop\n\t"									\
+	"nop\n\t"									\
+	"nop\n\t"									\
 	"std\t%%sp, [%%g6 + %3]\n\t"							\
 	"rd\t%%wim, %%g5\n\t"								\
 	"wr\t%%g4, 0x20, %%psr\n\t"							\
+	"nop\n\t"									\
+	"nop\n\t"									\
+	"nop\n\t"									\
 	"std\t%%g4, [%%g6 + %2]\n\t"							\
 	"mov\t%1, %%g6\n\t"								\
 	"ldd\t[%%g6 + %2], %%g4\n\t"							\
 	"st\t%1, [%0]\n\t"								\
 	"wr\t%%g4, 0x20, %%psr\n\t"							\
+	"nop\n\t"									\
+	"nop\n\t"									\
+	"nop\n\t"									\
 	"ldd\t[%%g6 + %3], %%sp\n\t"							\
 	"wr\t%%g5, 0x0, %%wim\n\t"							\
 	"ldd\t[%%sp + 0x00], %%l0\n\t"							\
@@ -108,6 +117,8 @@
 	"ldd\t[%%sp + 0x38], %%i6\n\t"							\
 	"wr\t%%g4, 0x0, %%psr\n\t"							\
 	"nop\n\t"									\
+	"nop\n\t"									\
+	"nop\n\t"									\
 	"jmpl\t%%o7 + 0x8, %%g0\n\t"							\
 	" nop\n\t" : : "r" (&(current_set[smp_processor_id()])), "r" (next),		\
 	"i" ((const unsigned long)(&((struct task_struct *)0)->tss.kpsr)),		\
@@ -120,43 +131,70 @@
  */
 extern __inline__ void setipl(unsigned long __orig_psr)
 {
-	__asm__ __volatile__("wr\t%0, 0x0, %%psr\n\t"
-			     "nop; nop; nop;" : : "r" (__orig_psr) : "memory");
+	__asm__ __volatile__("
+		wr	%0, 0x0, %%psr
+		nop
+		nop
+		nop
+"		: /* no outputs */
+		: "r" (__orig_psr)
+		: "memory");
 }
 
 extern __inline__ void cli(void)
 {
 	unsigned long tmp;
 
-	__asm__ __volatile__("rd\t%%psr, %0\n\t"
-			     "andcc\t%0, %1, %%g0\n\t"
-			     "be,a\t1f\n\t"
-			     " wr\t%0, %1, %%psr\n"
-			     "1:\tnop; nop"
-			     : "=r" (tmp)
-			     : "i" (PSR_PIL)
-			     : "memory");
+	__asm__ __volatile__("
+		rd	%%psr, %0
+		nop
+		nop
+		nop
+		andcc	%0, %1, %%g0
+		bne	1f
+		 nop
+		wr	%0, %1, %%psr
+		nop
+		nop
+		nop
+1:
+"		: "=r" (tmp)
+		: "i" (PSR_PIL)
+		: "memory");
 }
 
 extern __inline__ void sti(void)
 {
 	unsigned long tmp;
 
-	__asm__ __volatile__("rd\t%%psr, %0\n\t"
-			     "andcc\t%0, %1, %%g0\n\t"
-			     "bne,a\t1f\n\t"
-			     " wr\t%0, %1, %%psr\n"
-			     "1:\tnop; nop"
-			     : "=r" (tmp)
-			     : "i" (PSR_PIL)
-			     : "memory");
+	__asm__ __volatile__("
+		rd	%%psr, %0
+		nop
+		nop
+		nop
+		andcc	%0, %1, %%g0
+		be	1f
+		 nop
+		wr	%0, %1, %%psr
+		nop
+		nop
+		nop
+1:
+"		: "=r" (tmp)
+		: "i" (PSR_PIL)
+		: "memory");
 }
 
 extern __inline__ unsigned long getipl(void)
 {
 	unsigned long retval;
 
-	__asm__ __volatile__("rd\t%%psr, %0" : "=r" (retval));
+	__asm__ __volatile__("
+		rd	%%psr, %0
+		nop
+		nop
+		nop
+"	: "=r" (retval));
 	return retval;
 }
 
@@ -164,16 +202,25 @@
 {
 	unsigned long retval, tmp1, tmp2;
 
-	__asm__ __volatile__("rd\t%%psr, %0\n\t"
-			     "and\t%0, %4, %1\n\t"
-			     "and\t%3, %4, %2\n\t"
-			     "xorcc\t%1, %2, %%g0\n\t"
-			     "bne,a\t1f\n\t"
-			     " wr %0, %4, %%psr\n"
-			     "1:\tnop; nop"
-			     : "=r" (retval), "=r" (tmp1), "=r" (tmp2)
-			     : "r" (__new_psr), "i" (PSR_PIL)
-			     : "memory");
+	__asm__ __volatile__("
+		rd	%%psr, %0
+		nop
+		nop
+		nop
+		and	%0, %4, %1
+		and	%3, %4, %2
+		xorcc	%1, %2, %%g0
+		be	1f
+		 nop
+		wr %0, %4, %%psr
+		nop
+		nop
+		nop
+1:
+"		: "=r" (retval), "=r" (tmp1), "=r" (tmp2)
+		: "r" (__new_psr), "i" (PSR_PIL)
+		: "memory");
+
 	return retval;
 }
 
@@ -181,14 +228,23 @@
 {
 	unsigned long retval;
 
-	__asm__ __volatile__("rd\t%%psr, %0\n\t"
-			     "andcc\t%0, %1, %%g0\n\t"
-			     "be,a\t1f\n\t"
-			     " wr\t%0, %1, %%psr\n"
-			     "1:\tnop; nop"
-			     : "=r" (retval)
-			     : "i" (PSR_PIL)
-			     : "memory");
+	__asm__ __volatile__("
+		rd	%%psr, %0
+		nop
+		nop
+		nop
+		andcc	%0, %1, %%g0
+		bne	1f
+		 nop
+		wr	%0, %1, %%psr
+		nop
+		nop
+		nop
+1:
+"		: "=r" (retval)
+		: "i" (PSR_PIL)
+		: "memory");
+
 	return retval;
 }
 
@@ -207,15 +263,27 @@
 {
 	__asm__ __volatile__("
 	rd	%%psr, %%g3
+	nop
+	nop
+	nop
 	andcc	%%g3, %3, %%g0
-	be,a	1f
-	 wr	%%g3, %3, %%psr
-1:	ld	[%1], %%g2
+	bne	1f
+	 nop
+	wr	%%g3, %3, %%psr
+	nop
+	nop
+	nop
+1:
+	ld	[%1], %%g2
 	andcc	%%g3, %3, %%g0
 	st	%2, [%1]
-	be,a	1f
-	 wr	%%g3, 0x0, %%psr
-1:	nop
+	bne	1f
+	 nop
+	wr	%%g3, 0x0, %%psr
+	nop
+	nop
+	nop
+1:
 	mov	%%g2, %0
 	"
         : "=&r" (val)
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/termios.h linux/include/asm-sparc/termios.h
--- v2.1.15/linux/include/asm-sparc/termios.h	Tue Nov 12 15:56:13 1996
+++ linux/include/asm-sparc/termios.h	Fri Dec 13 11:37:40 1996
@@ -1,4 +1,4 @@
-/* $Id: termios.h,v 1.20 1996/10/31 00:59:54 davem Exp $ */
+/* $Id: termios.h,v 1.21 1996/11/13 02:30:40 davem Exp $ */
 #ifndef _SPARC_TERMIOS_H
 #define _SPARC_TERMIOS_H
 
@@ -59,6 +59,8 @@
 #define N_SLIP		1
 #define N_MOUSE		2
 #define N_PPP		3
+#define N_STRIP		4
+#define N_AX25		5
 
 #ifdef __KERNEL__
 
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/uaccess.h linux/include/asm-sparc/uaccess.h
--- v2.1.15/linux/include/asm-sparc/uaccess.h	Tue Nov 12 15:56:13 1996
+++ linux/include/asm-sparc/uaccess.h	Fri Dec 13 11:37:40 1996
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.2 1996/10/31 00:59:56 davem Exp $ */
+/* $Id: uaccess.h,v 1.9 1996/12/03 08:44:54 jj Exp $ */
 #ifndef _ASM_UACCESS_H
 #define _ASM_UACCESS_H
 
@@ -10,6 +10,7 @@
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <asm/vac-ops.h>
+#include <asm/a.out.h>
 #endif
 
 #ifndef __ASSEMBLY__
@@ -20,7 +21,7 @@
  * "For historical reasons, these macros are grossly misnamed." -Linus
  */
 #define KERNEL_DS   0
-#define USER_DS     1
+#define USER_DS     -1
 
 #define VERIFY_READ	0
 #define VERIFY_WRITE	1
@@ -29,9 +30,14 @@
 #define get_ds() (KERNEL_DS)
 #define set_fs(val) ((current->tss.current_ds) = (val))
 
-#define __user_ok(addr,size) (((size) <= page_offset)&&((addr) <= page_offset-(size)))
+/* We have there a nice not-mapped page at page_offset - PAGE_SIZE, so that this test
+ * can be fairly lightweight.
+ * No one can read/write anything from userland in the kernel space by setting
+ * large size and address near to page_offset - a fault will break his intentions.
+ */
+#define __user_ok(addr,size) ((addr) < stack_top)
 #define __kernel_ok (get_fs() == KERNEL_DS)
-#define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
+#define __access_ok(addr,size) (__user_ok((addr) & get_fs(),(size)))
 #define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
 
 extern inline int verify_area(int type, const void * addr, unsigned long size)
@@ -39,6 +45,38 @@
 	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.
+ *
+ * There is a special way how to put a range of potentially faulting
+ * insns (like twenty ldd/std's with now intervening other instructions)
+ * You specify address of first in insn and 0 in fixup and in the next 
+ * exception_table_entry you specify last potentially faulting insn + 1
+ * and in fixup the routine which should handle the fault.
+ * That fixup code will get
+ * (faulting_insn_address - first_insn_in_the_range_address)/4
+ * in %g2 (ie. index of the faulting instruction in the range).
+ */
+
+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, unsigned long *);
+
+extern void __ret_efault(void);
+
 /* Uh, these should become the main single-value transfer routines..
  * They automatically use the right size if we just have the right
  * pointer type..
@@ -52,188 +90,248 @@
 unsigned long __pu_addr = (unsigned long)(ptr); \
 __put_user_check((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr))); })
 
+#define put_user_ret(x,ptr,retval) ({ \
+unsigned long __pu_addr = (unsigned long)(ptr); \
+__put_user_check_ret((__typeof__(*(ptr)))(x),__pu_addr,sizeof(*(ptr)),retval); })
+
 #define get_user(x,ptr) ({ \
 unsigned long __gu_addr = (unsigned long)(ptr); \
 __get_user_check((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr))); })
 
+#define get_user_ret(x,ptr,retval) ({ \
+unsigned long __gu_addr = (unsigned long)(ptr); \
+__get_user_check_ret((x),__gu_addr,sizeof(*(ptr)),__typeof__(*(ptr)),retval); })
+
 /*
  * The "__xxx" versions do not do address space checking, useful when
  * doing multiple accesses to the same area (the user has to do the
  * checks by hand with "access_ok()")
  */
 #define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr)))
+#define __put_user_ret(x,ptr,retval) __put_user_nocheck_ret((x),(ptr),sizeof(*(ptr)),retval)
 #define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr)),__typeof__(*(ptr)))
+#define __get_user_ret(x,ptr,retval) __get_user_nocheck_ret((x),(ptr),sizeof(*(ptr)),__typeof__(*(ptr)),retval)
 
 struct __large_struct { unsigned long buf[100]; };
 #define __m(x) ((struct __large_struct *)(x))
 
 #define __put_user_check(x,addr,size) ({ \
-register int __pu_ret asm("g1"); \
-__pu_ret = -EFAULT; \
+register int __pu_ret; \
 if (__access_ok(addr,size)) { \
 switch (size) { \
-case 1: __put_user_8(x,addr,__pu_ret); break; \
-case 2: __put_user_16(x,addr,__pu_ret); break; \
-case 4: __put_user_32(x,addr,__pu_ret); break; \
+case 1: __put_user_asm(x,b,addr,__pu_ret); break; \
+case 2: __put_user_asm(x,h,addr,__pu_ret); break; \
+case 4: __put_user_asm(x,,addr,__pu_ret); break; \
 default: __pu_ret = __put_user_bad(); break; \
-} } __pu_ret; })
+} } else { __pu_ret = -EFAULT; } __pu_ret; })
+
+#define __put_user_check_ret(x,addr,size,retval) ({ \
+register int __foo __asm__ ("l1"); \
+if (__access_ok(addr,size)) { \
+switch (size) { \
+case 1: __put_user_asm_ret(x,b,addr,retval,__foo); break; \
+case 2: __put_user_asm_ret(x,h,addr,retval,__foo); break; \
+case 4: __put_user_asm_ret(x,,addr,retval,__foo); break; \
+default: if (__put_user_bad()) return retval; break; \
+} } else return retval; })
 
 #define __put_user_nocheck(x,addr,size) ({ \
-register int __pu_ret asm("g1"); \
-__pu_ret = -EFAULT; \
+register int __pu_ret; \
 switch (size) { \
-case 1: __put_user_8(x,addr,__pu_ret); break; \
-case 2: __put_user_16(x,addr,__pu_ret); break; \
-case 4: __put_user_32(x,addr,__pu_ret); break; \
+case 1: __put_user_asm(x,b,addr,__pu_ret); break; \
+case 2: __put_user_asm(x,h,addr,__pu_ret); break; \
+case 4: __put_user_asm(x,,addr,__pu_ret); break; \
 default: __pu_ret = __put_user_bad(); break; \
 } __pu_ret; })
 
-#define __put_user_8(x,addr,ret)						\
-__asm__ __volatile(								\
-	"/* Put user 8, inline. */\n\t"						\
-	"ld	[%%g6 + %3], %%g2\n\t"						\
-	"set	1f, %0\n\t"							\
-	"add	%%g2, 1, %%g3\n\t"						\
-	"st	%0, [%%g6 + %4]\n\t"						\
-	"st	%%g3, [%%g6 + %3]\n\t"						\
-	"stb	%1, [%2]\n\t"							\
-	"mov	0, %0\n\t"							\
-	"st	%%g2, [%%g6 + %3]\n"						\
-"1:\n" : "=&r" (ret) : "r" (x), "r" (__m(addr)),				\
-	 "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ex.count)),	\
-	 "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ex.expc))	\
-       : "g2", "g3")
-
-#define __put_user_16(x,addr,ret)						\
-__asm__ __volatile(								\
-	"/* Put user 16, inline. */\n\t"					\
-	"ld	[%%g6 + %3], %%g2\n\t"						\
-	"set	1f, %0\n\t"							\
-	"add	%%g2, 1, %%g3\n\t"						\
-	"st	%0, [%%g6 + %4]\n\t"						\
-	"st	%%g3, [%%g6 + %3]\n\t"						\
-	"sth	%1, [%2]\n\t"							\
-	"mov	0, %0\n\t"							\
-	"st	%%g2, [%%g6 + %3]\n"						\
-"1:\n" : "=&r" (ret) : "r" (x), "r" (__m(addr)),				\
-	 "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ex.count)),	\
-	 "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ex.expc))	\
-       : "g2", "g3")
-
-#define __put_user_32(x,addr,ret)						\
-__asm__ __volatile(								\
-	"/* Put user 32, inline. */\n\t"					\
-	"ld	[%%g6 + %3], %%g2\n\t"						\
-	"set	1f, %0\n\t"							\
-	"add	%%g2, 1, %%g3\n\t"						\
-	"st	%0, [%%g6 + %4]\n\t"						\
-	"st	%%g3, [%%g6 + %3]\n\t"						\
-	"st	%1, [%2]\n\t"							\
-	"mov	0, %0\n\t"							\
-	"st	%%g2, [%%g6 + %3]\n"						\
-"1:\n" : "=&r" (ret) : "r" (x), "r" (__m(addr)),				\
-	 "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ex.count)),	\
-	 "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ex.expc))	\
-       : "g2", "g3")
+#define __put_user_nocheck_ret(x,addr,size,retval) ({ \
+register int __foo __asm__ ("l1"); \
+switch (size) { \
+case 1: __put_user_asm_ret(x,b,addr,retval,__foo); break; \
+case 2: __put_user_asm_ret(x,h,addr,retval,__foo); break; \
+case 4: __put_user_asm_ret(x,,addr,retval,__foo); break; \
+default: if (__put_user_bad()) return retval; break; \
+} })
+
+#define __put_user_asm(x,size,addr,ret)					\
+__asm__ __volatile__(							\
+	"/* Put user asm, inline. */\n"					\
+"1:\t"	"st"#size " %1, [%2]\n\t"					\
+	"clr	%0\n"							\
+"2:\n\n\t"								\
+	".section .fixup,#alloc,#execinstr\n\t"				\
+	".align	4\n"							\
+"3:\n\t"								\
+	"b	2b\n\t"							\
+	" mov	%3, %0\n\n\t"						\
+	".section __ex_table,#alloc\n\t"				\
+	".align	4\n\t"							\
+	".word	1b, 3b\n\t"						\
+	".text\n\n\t"							\
+       : "=&r" (ret) : "r" (x), "r" (__m(addr)),			\
+	 "i" (-EFAULT))
+
+#define __put_user_asm_ret(x,size,addr,ret,foo)				\
+if (__builtin_constant_p(ret) && ret == -EFAULT)			\
+__asm__ __volatile__(							\
+	"/* Put user asm ret, inline. */\n"				\
+"1:\t"	"st"#size " %1, [%2]\n\n\t"					\
+	".section __ex_table,#alloc\n\t"				\
+	".align	4\n\t"							\
+	".word	1b, __ret_efault\n\n\t"					\
+	".text\n\n\t"							\
+       : "=r" (foo) : "r" (x), "r" (__m(addr)));			\
+else									\
+__asm__ __volatile(							\
+	"/* Put user asm ret, inline. */\n"				\
+"1:\t"	"st"#size " %1, [%2]\n\n\t"					\
+	".section .fixup,#alloc,#execinstr\n\t"				\
+	".align	4\n"							\
+"3:\n\t"								\
+	"ret\n\t"							\
+	" restore %%g0, %3, %%o0\n\n\t"					\
+	".section __ex_table,#alloc\n\t"				\
+	".align	4\n\t"							\
+	".word	1b, 3b\n\n\t"						\
+	".text\n\n\t"							\
+       : "=r" (foo) : "r" (x), "r" (__m(addr)), "i" (ret))
 
 extern int __put_user_bad(void);
 
 #define __get_user_check(x,addr,size,type) ({ \
-register int __gu_ret asm("g1"); \
-register unsigned long __gu_val = 0; \
-__gu_ret = -EFAULT; \
+register int __gu_ret; \
+register unsigned long __gu_val; \
 if (__access_ok(addr,size)) { \
 switch (size) { \
-case 1: __get_user_8(__gu_val,addr,__gu_ret); break; \
-case 2: __get_user_16(__gu_val,addr,__gu_ret); break; \
-case 4: __get_user_32(__gu_val,addr,__gu_ret); break; \
-default: __gu_ret = __get_user_bad(); break; \
-} } x = (type) __gu_val; __gu_ret; })
+case 1: __get_user_asm(__gu_val,ub,addr,__gu_ret); break; \
+case 2: __get_user_asm(__gu_val,uh,addr,__gu_ret); break; \
+case 4: __get_user_asm(__gu_val,,addr,__gu_ret); break; \
+default: __gu_val = 0; __gu_ret = __get_user_bad(); break; \
+} } else { __gu_val = 0; __gu_ret = -EFAULT; } x = (type) __gu_val; __gu_ret; })
+
+#define __get_user_check_ret(x,addr,size,type,retval) ({ \
+register unsigned long __gu_val __asm__ ("l1"); \
+if (__access_ok(addr,size)) { \
+switch (size) { \
+case 1: __get_user_asm_ret(__gu_val,ub,addr,retval); break; \
+case 2: __get_user_asm_ret(__gu_val,uh,addr,retval); break; \
+case 4: __get_user_asm_ret(__gu_val,,addr,retval); break; \
+default: if (__get_user_bad()) return retval; \
+} x = (type) __gu_val; } else return retval; })
 
 #define __get_user_nocheck(x,addr,size,type) ({ \
-register int __gu_ret asm("g1"); \
-register unsigned long __gu_val = 0; \
-__gu_ret = -EFAULT; \
+register int __gu_ret; \
+register unsigned long __gu_val; \
 switch (size) { \
-case 1: __get_user_8(__gu_val,addr,__gu_ret); break; \
-case 2: __get_user_16(__gu_val,addr,__gu_ret); break; \
-case 4: __get_user_32(__gu_val,addr,__gu_ret); break; \
-default: __gu_ret = __get_user_bad(); break; \
+case 1: __get_user_asm(__gu_val,ub,addr,__gu_ret); break; \
+case 2: __get_user_asm(__gu_val,uh,addr,__gu_ret); break; \
+case 4: __get_user_asm(__gu_val,,addr,__gu_ret); break; \
+default: __gu_val = 0; __gu_ret = __get_user_bad(); break; \
 } x = (type) __gu_val; __gu_ret; })
 
-#define __get_user_8(x,addr,ret)						\
-__asm__ __volatile__(								\
-	"/* Get user 8, inline. */\n\t"						\
-	"ld	[%%g6 + %3], %%g2\n\t"						\
-	"set	1f, %0\n\t"							\
-	"add	%%g2, 1, %%g3\n\t"						\
-	"st	%0, [%%g6 + %4]\n\t"						\
-	"st	%%g3, [%%g6 + %3]\n\t"						\
-	"ldub	[%2], %1\n\t"							\
-	"mov	0, %0\n\t"							\
-	"st	%%g2, [%%g6 + %3]\n"						\
-"1:\n" : "=&r" (ret), "=&r" (x) : "r" (__m(addr)),				\
-	 "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ex.count)),	\
-	 "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ex.expc))	\
-       : "g2", "g3")
-
-#define __get_user_16(x,addr,ret)						\
-__asm__ __volatile__(								\
-	"/* Get user 16, inline. */\n\t"					\
-	"ld	[%%g6 + %3], %%g2\n\t"						\
-	"set	1f, %0\n\t"							\
-	"add	%%g2, 1, %%g3\n\t"						\
-	"st	%0, [%%g6 + %4]\n\t"						\
-	"st	%%g3, [%%g6 + %3]\n\t"						\
-	"lduh	[%2], %1\n\t"							\
-	"mov	0, %0\n\t"							\
-	"st	%%g2, [%%g6 + %3]\n"						\
-"1:\n" : "=&r" (ret), "=&r" (x) : "r" (__m(addr)),				\
-	 "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ex.count)),	\
-	 "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ex.expc))	\
-       : "g2", "g3")
-
-#define __get_user_32(x,addr,ret)						\
-__asm__ __volatile__(								\
-	"/* Get user 32, inline. */\n\t"					\
-	"ld	[%%g6 + %3], %%g2\n\t"						\
-	"set	1f, %0\n\t"							\
-	"add	%%g2, 1, %%g3\n\t"						\
-	"st	%0, [%%g6 + %4]\n\t"						\
-	"st	%%g3, [%%g6 + %3]\n\t"						\
-	"ld	[%2], %1\n\t"							\
-	"mov	0, %0\n\t"							\
-	"st	%%g2, [%%g6 + %3]\n"						\
-"1:\n" : "=&r" (ret), "=&r" (x) : "r" (__m(addr)),				\
-	 "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ex.count)),	\
-	 "i" ((const unsigned long)(&((struct task_struct *)0)->tss.ex.expc))	\
-       : "g2", "g3")
+#define __get_user_nocheck_ret(x,addr,size,type,retval) ({ \
+register unsigned long __gu_val __asm__ ("l1"); \
+switch (size) { \
+case 1: __get_user_asm_ret(__gu_val,ub,addr,retval); break; \
+case 2: __get_user_asm_ret(__gu_val,uh,addr,retval); break; \
+case 4: __get_user_asm_ret(__gu_val,,addr,retval); break; \
+default: if (__get_user_bad()) return retval; \
+} x = (type) __gu_val; })
+
+#define __get_user_asm(x,size,addr,ret)					\
+__asm__ __volatile__(							\
+	"/* Get user asm, inline. */\n"					\
+"1:\t"	"ld"#size " [%2], %1\n\t"					\
+	"clr	%0\n"							\
+"2:\n\n\t"								\
+	".section .fixup,#alloc,#execinstr\n\t"				\
+	".align	4\n"							\
+"3:\n\t"								\
+	"clr	%1\n\t"							\
+	"b	2b\n\t"							\
+	" mov	%3, %0\n\n\t"						\
+	".section __ex_table,#alloc\n\t"				\
+	".align	4\n\t"							\
+	".word	1b, 3b\n\n\t"						\
+	".text\n\t"							\
+       : "=&r" (ret), "=&r" (x) : "r" (__m(addr)),			\
+	 "i" (-EFAULT))
+
+#define __get_user_asm_ret(x,size,addr,retval)				\
+if (__builtin_constant_p(retval) && retval == -EFAULT)			\
+__asm__ __volatile__(							\
+	"/* Get user asm ret, inline. */\n"				\
+"1:\t"	"ld"#size " [%1], %0\n\n\t"					\
+	".section __ex_table,#alloc\n\t"				\
+	".align	4\n\t"							\
+	".word	1b,__ret_efault\n\n\t"					\
+	".text\n\t"							\
+       : "=&r" (x) : "r" (__m(addr)));					\
+else									\
+__asm__ __volatile__(							\
+	"/* Get user asm ret, inline. */\n"				\
+"1:\t"	"ld"#size " [%1], %0\n\n\t"					\
+	".section .fixup,#alloc,#execinstr\n\t"				\
+	".align	4\n"							\
+"3:\n\t"								\
+	"ret\n\t"							\
+	" restore %%g0, %2, %%o0\n\n\t"					\
+	".section __ex_table,#alloc\n\t"				\
+	".align	4\n\t"							\
+	".word	1b, 3b\n\n\t"						\
+	".text\n\t"							\
+       : "=&r" (x) : "r" (__m(addr)), "i" (retval))
 
 extern int __get_user_bad(void);
 
-extern int __copy_to_user(unsigned long to, unsigned long from, int size);
-extern int __copy_from_user(unsigned long to, unsigned long from, int size);
+extern int __copy_user(unsigned long to, unsigned long from, int size);
 
 #define copy_to_user(to,from,n) ({ \
 unsigned long __copy_to = (unsigned long) (to); \
 unsigned long __copy_size = (unsigned long) (n); \
 unsigned long __copy_res; \
 if(__copy_size && __access_ok(__copy_to, __copy_size)) { \
-__copy_res = __copy_to_user(__copy_to, (unsigned long) (from), __copy_size); \
-if(__copy_res) __copy_res = __copy_size - __copy_res; \
+__copy_res = __copy_user(__copy_to, (unsigned long) (from), __copy_size); \
 } else __copy_res = __copy_size; \
 __copy_res; })
 
+#define copy_to_user_ret(to,from,n,retval) ({ \
+if (copy_to_user(to,from,n)) \
+	return retval; \
+})
+
+#define __copy_to_user(to,from,n)		\
+	__copy_user((unsigned long)(to),	\
+		    (unsigned long)(from), n)
+
+#define __copy_to_user_ret(to,from,n,retval) ({ \
+if (__copy_to_user(to,from,n)) \
+	return retval; \
+})
+
 #define copy_from_user(to,from,n) ({ \
 unsigned long __copy_from = (unsigned long) (from); \
 unsigned long __copy_size = (unsigned long) (n); \
 unsigned long __copy_res; \
 if(__copy_size && __access_ok(__copy_from, __copy_size)) { \
-__copy_res = __copy_from_user((unsigned long) (to), __copy_from, __copy_size); \
-if(__copy_res) __copy_res = __copy_size - __copy_res; \
+__copy_res = __copy_user((unsigned long) (to), __copy_from, __copy_size); \
 } else __copy_res = __copy_size; \
 __copy_res; })
 
+#define copy_from_user_ret(to,from,n,retval) ({ \
+if (copy_from_user(to,from,n)) \
+	return retval; \
+})
+
+#define __copy_from_user(to,from,n)		\
+	__copy_user((unsigned long)(to),	\
+		    (unsigned long)(from), n)
+
+#define __copy_from_user_ret(to,from,n,retval) ({ \
+if (__copy_from_user(to,from,n)) \
+	return retval; \
+})
+
 extern int __clear_user(unsigned long addr, int size);
 
 #define clear_user(addr,n) ({ \
@@ -242,10 +340,14 @@
 int __clear_res; \
 if(__clear_size && __access_ok(__clear_addr, __clear_size)) { \
 __clear_res = __clear_user(__clear_addr, __clear_size); \
-if(__clear_res) __clear_res = __clear_size - __clear_res; \
 } else __clear_res = __clear_size; \
 __clear_res; })
 
+#define clear_user_ret(addr,size,retval) ({ \
+if (clear_user(addr,size)) \
+	return retval; \
+})
+
 extern int __strncpy_from_user(unsigned long dest, unsigned long src, int count);
 
 #define strncpy_from_user(dest,src,count) ({ \
@@ -255,6 +357,16 @@
 if(__access_ok(__sfu_src, __sfu_count)) { \
 __sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \
 } __sfu_res; })
+
+extern int __strlen_user(const char *);
+
+extern __inline__ int strlen_user(const char *str)
+{
+	if(!access_ok(VERIFY_READ, str, 0))
+		return 0;
+	else
+		return __strlen_user(str);
+}
 
 #endif  /* __ASSEMBLY__ */
 
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc/viking.h linux/include/asm-sparc/viking.h
--- v2.1.15/linux/include/asm-sparc/viking.h	Tue Nov 12 15:56:13 1996
+++ linux/include/asm-sparc/viking.h	Fri Dec 13 11:37:40 1996
@@ -1,4 +1,4 @@
-/* $Id: viking.h,v 1.16 1996/08/29 09:49:10 davem Exp $
+/* $Id: viking.h,v 1.17 1996/11/24 17:11:51 ecd Exp $
  * viking.h:  Defines specific to the GNU/Viking MBUS module.
  *            This is SRMMU stuff.
  *
@@ -9,6 +9,7 @@
 
 #include <asm/asi.h>
 #include <asm/mxcc.h>
+#include <asm/pgtsrmmu.h>
 
 /* Bits in the SRMMU control register for GNU/Viking modules.
  *
@@ -193,6 +194,45 @@
 			      "i" (ASI_M_MXCC) : "g2");
 	*mregp = mreg;
 	*mxcc_cregp = mxcc_creg;
+}
+
+extern __inline__ unsigned long viking_hwprobe(unsigned long vaddr)
+{
+	unsigned long val;
+
+	vaddr &= PAGE_MASK;
+	/* Probe all MMU entries. */
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (val) :
+			     "r" (vaddr | 0x400), "i" (ASI_M_FLUSH_PROBE));
+	if (!val)
+		return 0;
+
+	/* Probe region. */
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (val) :
+			     "r" (vaddr | 0x200), "i" (ASI_M_FLUSH_PROBE));
+	if ((val & SRMMU_ET_MASK) == SRMMU_ET_PTE) {
+		vaddr &= ~SRMMU_PGDIR_MASK;
+		vaddr >>= PAGE_SHIFT;
+		return val | (vaddr << 8);
+	}
+
+	/* Probe segment. */
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (val) :
+			     "r" (vaddr | 0x100), "i" (ASI_M_FLUSH_PROBE));
+	if ((val & SRMMU_ET_MASK) == SRMMU_ET_PTE) {
+		vaddr &= ~SRMMU_PMD_MASK;
+		vaddr >>= PAGE_SHIFT;
+		return val | (vaddr << 8);
+	}
+
+	/* Probe page. */
+	__asm__ __volatile__("lda [%1] %2, %0\n\t" :
+			     "=r" (val) :
+			     "r" (vaddr), "i" (ASI_M_FLUSH_PROBE));
+	return val;
 }
 
 #endif /* !(_SPARC_VIKING_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/a.out.h linux/include/asm-sparc64/a.out.h
--- v2.1.15/linux/include/asm-sparc64/a.out.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/a.out.h	Fri Dec 13 11:37:41 1996
@@ -0,0 +1,96 @@
+/* $Id: a.out.h,v 1.1 1996/11/20 12:05:19 davem Exp $ */
+#ifndef __SPARC64_A_OUT_H__
+#define __SPARC64_A_OUT_H__
+
+#define SPARC_PGSIZE    0x2000        /* Thanks to the sun4 architecture... */
+#define SEGMENT_SIZE    SPARC_PGSIZE  /* whee... */
+
+struct exec {
+	unsigned char a_dynamic:1;      /* A __DYNAMIC is in this image */
+	unsigned char a_toolversion:7;
+	unsigned char a_machtype;
+	unsigned short a_info;
+	unsigned int a_text;		/* length of text, in bytes */
+	unsigned int a_data;		/* length of data, in bytes */
+	unsigned int a_bss;		/* length of bss, in bytes */
+	unsigned int a_syms;		/* length of symbol table, in bytes */
+	unsigned int a_entry;		/* where program begins */
+	unsigned int a_trsize;
+	unsigned int a_drsize;
+};
+
+/* Where in the file does the text information begin? */
+#define N_TXTOFF(x)     (N_MAGIC(x) == ZMAGIC ? 0 : sizeof (struct exec))
+
+/* Where do the Symbols start? */
+#define N_SYMOFF(x)     (N_TXTOFF(x) + (x).a_text +   \
+                         (x).a_data + (x).a_trsize +  \
+                         (x).a_drsize)
+
+/* Where does text segment go in memory after being loaded? */
+#define N_TXTADDR(x)    (((N_MAGIC(x) == ZMAGIC) &&        \
+	                 ((x).a_entry < SPARC_PGSIZE)) ?   \
+                          0 : SPARC_PGSIZE)
+
+/* And same for the data segment.. */
+#define N_DATADDR(x) (N_MAGIC(x)==OMAGIC ?         \
+                      (N_TXTADDR(x) + (x).a_text)  \
+                       : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
+
+#define N_TRSIZE(a)	((a).a_trsize)
+#define N_DRSIZE(a)	((a).a_drsize)
+#define N_SYMSIZE(a)	((a).a_syms)
+
+/*
+ * Sparc relocation types
+ */
+enum reloc_type
+{
+	RELOC_8,
+	RELOC_16,
+	RELOC_32,	/* simplest relocs */
+	RELOC_DISP8,
+	RELOC_DISP16,
+	RELOC_DISP32,	/* Disp's (pc-rel) */
+	RELOC_WDISP30,
+	RELOC_WDISP22,  /* SR word disp's */
+	RELOC_HI22,
+	RELOC_22,	/* SR 22-bit relocs */
+	RELOC_13,
+	RELOC_LO10,	/* SR 13&10-bit relocs */
+	RELOC_SFA_BASE,
+	RELOC_SFA_OFF13, /* SR S.F.A. relocs */
+	RELOC_BASE10,
+	RELOC_BASE13,
+	RELOC_BASE22,	/* base_relative pic */
+	RELOC_PC10,
+	RELOC_PC22,	/* special pc-rel pic */
+	RELOC_JMP_TBL,	/* jmp_tbl_rel in pic */
+	RELOC_SEGOFF16,	/* ShLib offset-in-seg */
+	RELOC_GLOB_DAT,
+	RELOC_JMP_SLOT,
+	RELOC_RELATIVE 	/* rtld relocs */
+};
+
+/*
+ * Format of a relocation datum.
+ */
+struct relocation_info /* used when header.a_machtype == M_SPARC */
+{
+        unsigned int    r_address;  /* relocation addr */
+        unsigned int    r_index:24; /* segment index or symbol index */
+        unsigned int    r_extern:1; /* if F, r_index==SEG#; if T, SYM idx */
+        int             r_pad:2;    /* <unused> */
+        enum reloc_type r_type:5;   /* type of relocation to perform */
+        int             r_addend;   /* addend for relocation value */
+};
+
+#define N_RELOCATION_INFO_DECLARED 1
+
+#ifdef __KERNEL__
+
+#define STACK_TOP	TASK_SIZE
+
+#endif
+
+#endif /* __SPARC64_A_OUT_H__ */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/asi.h linux/include/asm-sparc64/asi.h
--- v2.1.15/linux/include/asm-sparc64/asi.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/asi.h	Fri Dec 13 11:37:41 1996
@@ -0,0 +1,103 @@
+/* $Id: asi.h,v 1.1 1996/11/20 12:59:45 davem Exp $ */
+#ifndef _SPARC64_ASI_H
+#define _SPARC64_ASI_H
+
+/* asi.h:  Address Space Identifier values for the V9.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/* V9 Architecture mandary ASIs. */
+#define ASI_N			0x04 /* Nucleus					*/
+#define ASI_NL			0x0c /* Nucleus, little endian			*/
+#define ASI_AIUP		0x10 /* Primary, user				*/
+#define ASI_AIUS		0x11 /* Secondary, user				*/
+#define ASI_AIUPL		0x18 /* Primary, user, little endian		*/
+#define ASI_AIUSL		0x19 /* Secondary, user, little endian		*/
+#define ASI_P			0x80 /* Primary, implicit			*/
+#define ASI_S			0x81 /* Secondary, implicit			*/
+#define ASI_PNF			0x82 /* Primary, no fault			*/
+#define ASI_SNF			0x83 /* Secondary, no fault			*/
+#define ASI_PL			0x88 /* Primary, implicit, little endian	*/
+#define ASI_SL			0x89 /* Secondary, implicit, little endian	*/
+#define ASI_PNFL		0x8a /* Primary, no fault, little endian	*/
+#define ASI_SNFL		0x8b /* Secondary, no fault, little endian	*/
+
+/* SpitFire extended ASIs. */
+#define ASI_PHYS_USE_EC		0x14 /* PADDR, E-cachable			*/
+#define ASI_PHYS_BYPASS_EC_E	0x15 /* PADDR, E-cachable, E-bit		*/
+#define ASI_PHYS_USE_EC_L	0x1c /* PADDR, E-cachable, little endian	*/
+#define ASI_PHYS_BYPASS_EC_E_L	0x1d /* PADDR, E-cachable, E-bit, little endian	*/
+#define ASI_NUCLEUS_QUAD_LDD	0x24 /* Cachable, qword load			*/
+#define ASI_NUCLEUS_QUAD_LDD_L	0x2c /* Cachable, qword load, little endian 	*/
+#define ASI_LSU_CONTROL		0x45 /* Load-store control unit			*/
+#define ASI_DCACHE_DATA		0x46 /* Data cache data-ram diag access		*/
+#define ASI_DCACHE_TAG		0x47 /* Data cache tag/valid ram diag access	*/
+#define ASI_INTR_DISPATCH_STAT	0x48 /* IRQ vector dispatch status		*/
+#define ASI_INTR_RECEIVE	0x49 /* IRQ vector receive status		*/
+#define ASI_UPA_CONFIG		0x4a /* UPA config space			*/
+#define ASI_ESTATE_ERROR_EN	0x4b /* E-cache error enable space		*/
+#define ASI_AFSR		0x4c /* Async fault status register		*/
+#define ASI_AFAR		0x4d /* Async fault address register		*/
+#define ASI_EC_TAG_DATA		0x4e /* E-cache tag/valid ram diag access	*/
+#define ASI_IMMU		0x50 /* Insn-MMU main register space		*/
+#define ASI_IMMU_TSB_8KB_PTR	0x51 /* Insn-MMU 8KB TSB pointer register	*/
+#define ASI_IMMU_TSB_64KB_PTR	0x52 /* Insn-MMU 64KB TSB pointer register	*/
+#define ASI_ITLB_DATA_IN	0x54 /* Insn-MMU TLB data in register		*/
+#define ASI_ITLB_DATA_ACCESS	0x55 /* Insn-MMU TLB data access register	*/
+#define ASI_ITLB_TAG_READ	0x56 /* Insn-MMU TLB tag read register		*/
+#define ASI_IMMU_DEMAP		0x57 /* Insn-MMU TLB demap			*/
+#define ASI_DMMU		0x58 /* Data-MMU main register space		*/
+#define ASI_DMMU_TSB_8KB_PTR	0x59 /* Data-MMU 8KB TSB pointer register	*/
+#define ASI_DMMU_TSB_64KB_PTR	0x5a /* Data-MMU 16KB TSB pointer register	*/
+#define ASI_DMMU_TSB_DIRECT_PTR	0x5b /* Data-MMU TSB direct pointer register	*/
+#define ASI_DTLB_DATA_IN	0x5c /* Data-MMU TLB data in register		*/
+#define ASI_DTLB_DATA_ACCESS	0x5d /* Data-MMU TLB data access register	*/
+#define ASI_DTLB_TAG_READ	0x5e /* Data-MMU TLB tag read register		*/
+#define ASI_DMMU_DEMAP		0x5f /* Data-MMU TLB demap			*/
+#define ASI_IC_INSTR		0x66 /* Insn cache instrucion ram diag access	*/
+#define ASI_IC_TAG		0x67 /* Insn cache tag/valid ram diag access	*/
+#define ASI_IC_PRE_DECODE	0x6e /* Insn cache pre-decode ram diag access	*/
+#define ASI_IC_NEXT_FIELD	0x6f /* Insn cache next-field ram diag access	*/
+#define ASI_BLK_AIUP		0x70 /* Primary, user, block load/store		*/
+#define ASI_BLK_AIUS		0x71 /* Secondary, user, block load/store	*/
+#define ASI_EC_W		0x76 /* E-cache diag write access		*/
+#define ASI_UDB_ERROR_W		0x77 /* External UDB error registers write	*/
+#define ASI_UDB_CONTROL_W	0x77 /* External UDB control registers write	*/
+#define ASI_UDB_INTR_W		0x77 /* External UDB IRQ vector dispatch write	*/
+#define ASI_BLK_AIUPL		0x78 /* Primary, user, little, blk ld/st	*/
+#define ASI_BLK_AIUSL		0x79 /* Secondary, user, little, blk ld/st	*/
+#define ASI_EC_R		0x7e /* E-cache diag read access		*/
+#define ASI_UDBH_ERROR_R	0x7f /* External UDB error registers read hi	*/
+#define ASI_UDBL_ERROR_R	0x7f /* External UDB error registers read low	*/
+#define ASI_UDBH_CONTROL_R	0x7f /* External UDB control registers read hi	*/
+#define ASI_UDBL_CONTROL_R	0x7f /* External UDB control registers read low	*/
+#define ASI_UDB_INTR_R		0x7f /* External UDB IRQ vector dispatch read	*/
+#define ASI_PST8_P		0xc0 /* Primary, 8 8-bit, partial		*/
+#define ASI_PST8_S		0xc1 /* Secondary, 8 8-bit, partial		*/
+#define ASI_PST16_P		0xc2 /* Primary, 4 16-bit, partial		*/
+#define ASI_PST16_S		0xc3 /* Seconary, 4 16-bit, partial		*/
+#define ASI_PST32_P		0xc4 /* Primary, 2 32-bit, partial		*/
+#define ASI_PST32_S		0xc5 /* Secondary, 2 32-bit, partial		*/
+#define ASI_PST8_PL		0xc8 /* Primary, 8 8-bit, partial, little	*/
+#define ASI_PST8_SL		0xc9 /* Secondary, 8 8-bit, partial, little	*/
+#define ASI_PST16_PL		0xca /* Primary, 4 16-bit, partial, little	*/
+#define ASI_PST16_SL		0xcb /* Seconary, 4 16-bit, partial, little	*/
+#define ASI_PST32_PL		0xcc /* Primary, 2 32-bit, partial, little	*/
+#define ASI_PST32_SL		0xcd /* Secondary, 2 32-bit, partial, little	*/
+#define ASI_FL8_P		0xd0 /* Primary, 1 8-bit, fpu ld/st		*/
+#define ASI_FL8_S		0xd1 /* Secondary, 1 8-bit, fpu ld/st		*/
+#define ASI_FL16_P		0xd2 /* Primary, 1 16-bit, fpu ld/st		*/
+#define ASI_FL16_S		0xd3 /* Secondary, 1 16-bit, fpu ld/st		*/
+#define ASI_FL8_PL		0xd8 /* Primary, 1 8-bit, fpu ld/st, little	*/
+#define ASI_FL8_SL		0xd9 /* Secondary, 1 8-bit, fpu ld/st, little	*/
+#define ASI_FL16_PL		0xda /* Primary, 1 16-bit, fpu ld/st, little	*/
+#define ASI_FL16_SL		0xdb /* Secondary, 1 16-bit, fpu ld/st, little	*/
+#define ASI_BLK_COMMIT_P	0xe0 /* Primary, blk store commit		*/
+#define ASI_BLK_COMMIT_S	0xe1 /* Secondary, blk store commit		*/
+#define ASI_BLK_P		0xf0 /* Primary, blk ld/st			*/
+#define ASI_BLK_S		0xf1 /* Secondary, blk ld/st			*/
+#define ASI_BLK_PL		0xf8 /* Primary, blk ld/st, little		*/
+#define ASI_BLK_SL		0xf9 /* Secondary, blk ld/st, little		*/
+
+#endif /* _SPARC64_ASI_H */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/atomic.h linux/include/asm-sparc64/atomic.h
--- v2.1.15/linux/include/asm-sparc64/atomic.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/atomic.h	Fri Dec 13 11:37:41 1996
@@ -0,0 +1,95 @@
+/* $Id: atomic.h,v 1.6 1996/12/12 15:40:22 davem Exp $
+ * atomic.h: Thankfully the V9 is at least reasonable for this
+ *           stuff.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __ARCH_SPARC64_ATOMIC__
+#define __ARCH_SPARC64_ATOMIC__
+
+/* Make sure gcc doesn't try to be clever and move things around
+ * on us. We need to use _exactly_ the address the user gave us,
+ * not some alias that contains the same information.
+ */
+#define __atomic_fool_gcc(x) ((struct { int a[100]; } *)x)
+
+typedef int atomic_t;
+
+extern __inline__ void atomic_add(atomic_t i, atomic_t *v)
+{
+	unsigned long temp0, temp1;
+	__asm__ __volatile__("
+	lduw		[%2], %0
+1:
+	add		%0, %3, %1
+	cas		[%2], %0, %1
+	cmp		%0, %1
+	bne,a,pn	%%icc, 1b
+	 lduw		[%2], %0
+2:
+" 	: "=&r" (temp0), "=&r" (temp1), "=r" (__atomic_fool_gcc(v))
+	: "ir" (i), "r" (__atomic_fool_gcc(v)));
+}
+
+extern __inline__ void atomic_sub(atomic_t i, atomic_t *v)
+{
+	unsigned long temp0, temp1;
+	__asm__ __volatile__("
+	lduw		[%2], %0
+1:
+	sub		%0, %3, %1
+	cas		[%2], %0, %1
+	cmp		%0, %1
+	bne,a,pn	%%icc, 1b
+	 lduw		[%2], %0
+2:
+"	: "=&r" (temp0), "=&r" (temp1), "=r" (__atomic_fool_gcc(v))
+	: "ir" (i), "r" (__atomic_fool_gcc(v)));
+}
+
+/* Same as above, but return the result value. */
+extern __inline__ long atomic_add_return(atomic_t i, atomic_t *v)
+{
+	long temp0, result;
+	__asm__ __volatile__("
+	lduw		[%2], %0
+1:
+	add		%0, %3, %1
+	cas		[%2], %0, %1
+	cmp		%0, %1
+	bne,a,pn	%%icc, 1b
+	 lduw		[%2], %0
+2:
+"	: "=&r" (temp0), "=&r" (result), "=r" (__atomic_fool_gcc(v))
+	: "ir" (i), "r" (__atomic_fool_gcc(v)));
+	return result;
+}
+
+extern __inline__ long atomic_sub_return(atomic_t i, atomic_t *v)
+{
+	long temp0, result;
+	__asm__ __volatile__("
+	lduw		[%2], %0
+1:
+	sub		%0, %3, %1
+	cas		[%2], %0, %1
+	cmp		%0, %1
+	bne,a,pn	%%icc, 1b
+	 lduw		[%2], %0
+2:
+"	: "=&r" (temp0), "=&r" (result), "=r" (__atomic_fool_gcc(v))
+	: "ir" (i), "r" (__atomic_fool_gcc(v)));
+	return result;
+}
+
+#define atomic_dec_return(v) atomic_sub_return(1,(v))
+#define atomic_inc_return(v) atomic_add_return(1,(v))
+
+#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
+#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
+
+#define atomic_inc(v) atomic_add(1,(v))
+#define atomic_dec(v) atomic_sub(1,(v))
+
+#endif /* !(__ARCH_SPARC64_ATOMIC__) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/bitops.h linux/include/asm-sparc64/bitops.h
--- v2.1.15/linux/include/asm-sparc64/bitops.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/bitops.h	Fri Dec 13 11:37:41 1996
@@ -0,0 +1,269 @@
+/* $Id: bitops.h,v 1.4 1996/12/12 15:50:14 davem Exp $
+ * bitops.h: Bit string operations on the V9.
+ *
+ * Copyright 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC64_BITOPS_H
+#define _SPARC64_BITOPS_H
+
+#include <asm/asi.h>         /* For the little endian spaces. */
+
+/* These can all be exported to userland, because the atomic
+ * primitives used are not privileged.
+ */
+
+/* Set bit 'nr' in 32-bit quantity at address 'addr' where bit '0'
+ * is in the highest of the four bytes and bit '31' is the high bit
+ * within the first byte. Sparc is BIG-Endian. Unless noted otherwise
+ * all bit-ops return 0 if bit was previously clear and != 0 otherwise.
+ */
+
+extern __inline__ unsigned long set_bit(unsigned long nr, void *addr)
+{
+	unsigned long oldbit;
+	unsigned long temp0, temp1;
+	unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
+
+	__asm__ __volatile__("
+	lduw		[%2], %0
+1:
+	andcc		%0, %4, %3
+	bne,pn		%%icc, 2f
+	 xor		%0, %4, %1
+	cas 		[%2], %0, %1
+	cmp		%0, %1
+	bne,a,pn	%%icc, 1b
+	 lduw		[%2], %0
+2:
+"	: "=&r" (temp0), "=&r" (temp1), "=r" (m), "=&r" (oldbit)
+	: "ir" (1UL << (nr & 31)), "r" (m));
+	return oldbit != 0;
+}
+
+extern __inline__ unsigned long clear_bit(unsigned long nr, void *addr)
+{
+	unsigned long oldbit;
+	unsigned long temp0, temp1;
+	unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
+
+	__asm__ __volatile__("
+	lduw		[%2], %0
+1:
+	andcc		%0, %4, %3
+	be,pn		%%icc, 2f
+	 xor		%0, %4, %1
+	cas 		[%2], %0, %1
+	cmp		%0, %1
+	bne,a,pn	%%icc, 1b
+	 lduw		[%2], %0
+2:
+"	: "=&r" (temp0), "=&r" (temp1), "=r" (m), "=&r" (oldbit)
+	: "ir" (1UL << (nr & 31)), "r" (m));
+	return oldbit != 0;
+}
+
+extern __inline__ unsigned long change_bit(unsigned long nr, void *addr)
+{
+	unsigned long oldbit;
+	unsigned long temp0, temp1;
+	unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
+
+	__asm__ __volatile__("
+	lduw		[%2], %0
+1:
+	andcc		%0, %4, %3
+	xor		%0, %4, %1
+	cas 		[%2], %0, %1
+	cmp		%0, %1
+	bne,a,pn	%%icc, 1b
+	 lduw		[%2], %0
+"	: "=&r" (temp0), "=&r" (temp1), "=r" (m), "=&r" (oldbit)
+	: "ir" (1UL << (nr & 31)), "r" (m));
+	return oldbit != 0;
+}
+
+extern __inline__ unsigned long test_bit(int nr, __const__ void *addr)
+{
+	return 1UL & (((__const__ int *) addr)[nr >> 5] >> (nr & 31));
+}
+
+/* The easy/cheese version for now. */
+extern __inline__ unsigned long ffz(unsigned long word)
+{
+	unsigned long result = 0;
+
+	while(word & 1) {
+		result++;
+		word >>= 1;
+	}
+	return result;
+}
+
+/* find_next_zero_bit() finds the first zero bit in a bit string of length
+ * 'size' bits, starting the search at bit 'offset'. This is largely based
+ * on Linus's ALPHA routines, which are pretty portable BTW.
+ */
+
+extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
+{
+	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
+	unsigned long result = offset & ~31UL;
+	unsigned long tmp;
+
+	if (offset >= size)
+		return size;
+	size -= result;
+	offset &= 31UL;
+	if (offset) {
+		tmp = *(p++);
+		tmp |= ~0UL >> (32-offset);
+		if (size < 32)
+			goto found_first;
+		if (~tmp)
+			goto found_middle;
+		size -= 32;
+		result += 32;
+	}
+	while (size & ~31UL) {
+		if (~(tmp = *(p++)))
+			goto found_middle;
+		result += 32;
+		size -= 32;
+	}
+	if (!size)
+		return result;
+	tmp = *p;
+
+found_first:
+	tmp |= ~0UL << size;
+found_middle:
+	return result + ffz(tmp);
+}
+
+#define find_first_zero_bit(addr, size) \
+        find_next_zero_bit((addr), (size), 0)
+
+/* Now for the ext2 filesystem bit operations and helper routines.
+ * Note the usage of the little endian ASI's, werd, V9 is supreme.
+ */
+extern __inline__ int set_le_bit(int nr,void * addr)
+{
+	unsigned long oldbit;
+	unsigned long temp0, temp1;
+	unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
+
+	__asm__ __volatile__("
+	lduwa		[%2] %5, %0
+1:
+	andcc		%0, %4, %3
+	bne,pn		%%icc, 2f
+	 xor		%0, %4, %1
+	casa 		[%2] %5, %0, %1
+	cmp		%0, %1
+	bne,a,pn	%%icc, 1b
+	 lduwa		[%2] %5, %0
+2:
+"	: "=&r" (temp0), "=&r" (temp1), "=r" (m), "=&r" (oldbit)
+	: "ir" (1UL << (nr & 31)), "r" (m), "i" (ASI_PL));
+	return oldbit != 0;
+}
+
+extern __inline__ int clear_le_bit(int nr, void * addr)
+{
+	unsigned long oldbit;
+	unsigned long temp0, temp1;
+	unsigned int * m = ((unsigned int *) addr) + (nr >> 5);
+
+	__asm__ __volatile__("
+	lduwa		[%2] %5, %0
+1:
+	andcc		%0, %4, %3
+	be,pn		%%icc, 2f
+	 xor		%0, %4, %1
+	casa 		[%2] %5, %0, %1
+	cmp		%0, %1
+	bne,a,pn	%%icc, 1b
+	 lduwa		[%2] %5, %0
+2:
+"	: "=&r" (temp0), "=&r" (temp1), "=r" (m), "=&r" (oldbit)
+	: "ir" (1UL << (nr & 31)), "r" (m), "i" (ASI_PL));
+	return oldbit != 0;
+}
+
+extern __inline__ int test_le_bit(int nr, __const__ void * addr)
+{
+	int			mask;
+	__const__ unsigned char	*ADDR = (__const__ unsigned char *) addr;
+
+	ADDR += nr >> 3;
+	mask = 1 << (nr & 0x07);
+	return ((mask & *ADDR) != 0);
+}
+
+#define find_first_zero_le_bit(addr, size) \
+        find_next_zero_le_bit((addr), (size), 0)
+
+---------------------------------------------------------
+| byte | byte | byte | byte | byte | byte | byte | byte |
+---------------------------------------------------------
+ 63  56 55  48 47  40 39  32 31  24 23  16 15   8 7    0
+extern __inline__ unsigned long __swab64(unsigned long value)
+{
+	return (((value>>56) & 0x00000000000000ff) |
+		((value>>40) & 0x000000000000ff00) |
+		((value>>24) & 0x0000000000ff0000) |
+		((value>>8)  & 0x00000000ff000000) |
+		((value<<8)  & 0x000000ff00000000) |
+		((value<<24) & 0x0000ff0000000000) |
+		((value<<40) & 0x00ff000000000000) |
+		((value<<56) & 0xff00000000000000));
+}     
+
+extern __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long size, unsigned long offset)
+{
+	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
+	unsigned long result = offset & ~63UL;
+	unsigned long tmp;
+
+	if (offset >= size)
+		return size;
+	size -= result;
+	offset &= 31UL;
+	if(offset) {
+		tmp = *(p++);
+		tmp |= __swab64(~0UL >> (64-offset));
+		if(size < 64)
+			goto found_first;
+		if(~tmp)
+			goto found_middle;
+		size -= 64;
+		result += 64;
+	}
+	while(size & ~63UL) {
+		if(~(tmp = *(p++)))
+			goto found_middle;
+		result += 64;
+		size -= 64;
+	}
+	if(!size)
+		return result;
+	tmp = *p;
+
+found_first:
+	return result + ffz(__swab32(tmp) | (~0UL << size));
+found_middle:
+	return result + ffz(__swab32(tmp));
+}
+
+#ifdef __KERNEL__
+
+#define ext2_set_bit			set_le_bit
+#define ext2_clear_bit			clear_le_bit
+#define ext2_test_bit  			test_le_bit
+#define ext2_find_first_zero_bit	find_first_zero_le_bit
+#define ext2_find_next_zero_bit		find_next_zero_le_bit
+
+#endif /* __KERNEL__ */
+
+#endif /* defined(_SPARC64_BITOPS_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/byteorder.h linux/include/asm-sparc64/byteorder.h
--- v2.1.15/linux/include/asm-sparc64/byteorder.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/byteorder.h	Fri Dec 13 11:37:41 1996
@@ -0,0 +1,56 @@
+/* $Id: byteorder.h,v 1.1 1996/11/20 14:01:53 davem Exp $ */
+#ifndef _SPARC64_BYTEORDER_H
+#define _SPARC64_BYTEORDER_H
+
+#define ntohl(x) x
+#define ntohs(x) x
+#define htonl(x) x
+#define htons(x) x
+
+/* Some programs depend upon these being around. */
+#define __constant_ntohl(x) x
+#define __constant_ntohs(x) x
+#define __constant_htonl(x) x
+#define __constant_htons(x) x
+
+#ifndef __BIG_ENDIAN
+#define __BIG_ENDIAN 4321
+#endif
+
+#ifndef __BIG_ENDIAN_BITFIELD
+#define __BIG_ENDIAN_BITFIELD
+#endif
+
+#ifdef __KERNEL__
+
+/* Convert from CPU byte order, to specified byte order. */
+extern __inline__ __u16 cpu_to_le16(__u16 value)
+{
+	return (value >> 8) | (value << 8);
+}
+
+extern __inline__ __u32 cpu_to_le32(__u32 value)
+{
+	return((value>>24) | ((value>>8)&0xff00) |
+	       ((value<<8)&0xff0000) | (value<<24));
+}
+#define cpu_to_be16(x)  (x)
+#define cpu_to_be32(x)  (x)
+
+/* Convert from specified byte order, to CPU byte order. */
+extern __inline__ __u16 le16_to_cpu(__u16 value)
+{
+	return (value >> 8) | (value << 8);
+}
+
+extern __inline__ __u32 le32_to_cpu(__u32 value)
+{
+	return((value>>24) | ((value>>8)&0xff00) |
+	       ((value<<8)&0xff0000) | (value<<24));
+}
+#define be16_to_cpu(x)  (x)
+#define be32_to_cpu(x)  (x)
+
+#endif /* __KERNEL__ */
+
+#endif /* !(_SPARC64_BYTEORDER_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/checksum.h linux/include/asm-sparc64/checksum.h
--- v2.1.15/linux/include/asm-sparc64/checksum.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/checksum.h	Fri Dec 13 11:37:41 1996
@@ -0,0 +1,166 @@
+/* $Id: checksum.h,v 1.3 1996/12/12 15:39:13 davem Exp $ */
+#ifndef __SPARC64_CHECKSUM_H
+#define __SPARC64_CHECKSUM_H
+
+/*  checksum.h:  IP/UDP/TCP checksum routines on the V9.
+ *
+ *  Copyright(C) 1995 Linus Torvalds
+ *  Copyright(C) 1995 Miguel de Icaza
+ *  Copyright(C) 1996 David S. Miller
+ *  Copyright(C) 1996 Eddie C. Dost
+ *
+ * derived from:
+ *	Alpha checksum c-code
+ *      ix86 inline assembly
+ *      RFC1071 Computing the Internet Checksum
+ */
+
+/* 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
+ */
+extern unsigned int csum_partial(unsigned char * buff, int len, unsigned int sum);
+
+/* the same as csum_partial, but copies from user space while it
+ * checksums
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+extern unsigned int csum_partial_copy(char *src, char *dst, int len, int sum);
+
+#define csum_partial_copy_fromuser(s, d, l, w)  \
+                       csum_partial_copy((char *) (s), (d), (l), (w))
+
+/* ihl is always 5 or greater, almost always is 5, and iph is word aligned
+ * the majority of the time.
+ */
+extern __inline__ unsigned short ip_fast_csum(__const__ unsigned char *iph,
+					      unsigned int ihl)
+{
+	unsigned short sum;
+
+	/* Note: We must read %2 before we touch %0 for the first time,
+	 *       because GCC can legitimately use the same register for
+	 *       both operands.
+	 */
+	__asm__ __volatile__("
+	sub		%2, 4, %%g4
+	lduw		[%1 + 0x00], %0
+	lduw		[%1 + 0x04], %%g2
+	lduw		[%1 + 0x08], %%g3
+	addcc		%%g2, %0, %0
+	addccc		%%g3, %0, %0
+	lduw		[%1 + 0x0c], %%g2
+	lduw		[%1 + 0x10], %%g3
+	addccc		%%g2, %0, %0
+	addc		%0, %%g0, %0
+1:
+	addcc		%%g3, %0, %0
+	add		%1, 4, %1
+	addccc		%0, %%g0, %0
+	subcc		%%g4, 1, %%g4
+	be,a,pt		%%icc, 2f
+	 sll		%0, 16, %%g2
+	ba,pt		1b
+	 lduw		[%1 + 0x10], %%g3
+2:
+	addcc		%0, %%g2, %%g2
+	srl		%%g2, 16, %0
+	addc		%0, %%g0, %0
+	xnor		%%g0, %0, %0
+"	: "=r" (sum), "=&r" (iph)
+	: "r" (ihl), "1" (iph)
+	: "g2", "g3", "g4");
+	return sum;
+}
+
+/* computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+extern __inline__ unsigned short csum_tcpudp_magic(unsigned long saddr,
+						   unsigned long daddr,
+						   unsigned int len,
+						   unsigned short proto,
+						   unsigned int sum)
+{
+	__asm__ __volatile__("
+	addcc		%1, %0, %0
+	addccc		%2, %0, %0
+	addccc		%3, %0, %0
+	addc		%0, %%g0, %0
+	sll		%0, 16, %1
+	addcc		%1, %0, %0
+	srl		%0, 16, %0
+	addc		%0, %%g0, %0
+	xnor		%%g0, %0, %0
+"	: "=r" (sum), "=r" (saddr)
+	: "r" (daddr), "r" ((proto<<16)+len), "0" (sum), "1" (saddr));
+	return sum;
+}
+
+/* Fold a partial checksum without adding pseudo headers. */
+extern __inline__ unsigned int csum_fold(unsigned int sum)
+{
+	unsigned int tmp;
+
+	__asm__ __volatile__("
+	addcc		%0, %1, %1
+	srl		%1, 16, %1
+	addc		%1, %%g0, %1
+	xnor		%%g0, %1, %0
+"	: "=&r" (sum), "=r" (tmp)
+	: "0" (sum), "1" (sum<<16));
+	return sum;
+}
+
+#define _HAVE_ARCH_IPV6_CSUM
+
+static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
+						     struct in6_addr *daddr,
+						     __u16 len,
+						     unsigned short proto,
+						     unsigned int sum) 
+{
+	__asm__ __volatile__ ("
+	addcc		%3, %4, %%g4
+	addccc		%5, %%g4, %%g4
+	lduw		[%2 + 0x0c], %%g2
+	lduw		[%2 + 0x08], %%g3
+	addccc		%%g2, %%g4, %%g4
+	lduw		[%2 + 0x04], %%g2
+	addccc		%%g3, %%g4, %%g4
+	lduw		[%2 + 0x00], %%g3
+	addccc		%%g2, %%g4, %%g4
+	lduw		[%1 + 0x0c], %%g2
+	addccc		%%g3, %%g4, %%g4
+	lduw		[%1 + 0x08], %%g3
+	addccc		%%g2, %%g4, %%g4
+	lduw		[%1 + 0x04], %%g2
+	addccc		%%g3, %%g4, %%g4
+	lduw		[%1 + 0x00], %%g3
+	addccc		%%g2, %%g4, %%g4
+	addccc		%%g3, %%g4, %0
+	addc		0, %0, %0
+"	: "=&r" (sum)
+	: "r" (saddr), "r" (daddr), "r"(htonl((__u32) (len))),
+	  "r"(htonl(proto)), "r"(sum)
+	: "g2", "g3", "g4");
+
+	return csum_fold(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 /* !(__SPARC64_CHECKSUM_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/delay.h linux/include/asm-sparc64/delay.h
--- v2.1.15/linux/include/asm-sparc64/delay.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/delay.h	Fri Dec 13 11:37:41 1996
@@ -0,0 +1,42 @@
+/* $Id: delay.h,v 1.3 1996/12/12 15:53:48 davem Exp $
+ * delay.h: Linux delay routines on the V9.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu).
+ */
+
+#ifndef __SPARC64_DELAY_H
+#define __SPARC64_DELAY_H
+
+extern unsigned long loops_per_sec;
+
+extern __inline__ void __delay(unsigned long loops)
+{
+	__asm__ __volatile__("
+	cmp	%0, 0
+1:
+	bne,pt	%%xcc, 1b
+	 subcc	%0, 1, %0
+"	: "=&r" (loops)
+	: "0" (loops));
+}
+
+extern __inline__ void udelay(unsigned long usecs)
+{
+	usecs *= 0x00000000000010c6UL;		/* 2**32 / 1000000 */
+
+	__asm__ __volatile__("
+	mulx	%1, %2, %0
+	srlx	%0, 32, %0
+"	: "=r" (usecs)
+	: "r" (usecs), "r" (loops_per_sec));
+
+	__delay(usecs);
+}
+
+extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
+{
+	return (a*b)/c;
+}
+
+#endif /* defined(__SPARC64_DELAY_H) */
+
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/dma.h linux/include/asm-sparc64/dma.h
--- v2.1.15/linux/include/asm-sparc64/dma.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/dma.h	Fri Dec 13 11:37:41 1996
@@ -0,0 +1,209 @@
+/* $Id: dma.h,v 1.1 1996/11/20 15:27:38 davem Exp $
+ * include/asm-sparc64/dma.h
+ *
+ * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _ASM_SPARC64_DMA_H
+#define _ASM_SPARC64_DMA_H
+
+#include <linux/kernel.h>
+
+#include <asm/vac-ops.h>  /* for invalidate's, etc. */
+#include <asm/sbus.h>
+#include <asm/delay.h>
+#include <asm/oplib.h>
+
+/* These are irrelevant for Sparc DMA, but we leave it in so that
+ * things can compile.
+ */
+#define MAX_DMA_CHANNELS 8
+#define MAX_DMA_ADDRESS  (~0UL)
+#define DMA_MODE_READ    1
+#define DMA_MODE_WRITE   2
+
+/* Useful constants */
+#define SIZE_16MB      (16*1024*1024)
+#define SIZE_64K       (64*1024)
+
+/* Structure to describe the current status of DMA registers on the Sparc */
+struct sparc_dma_registers {
+  __volatile__ unsigned int cond_reg;   /* DMA condition register */
+  __volatile__ char * st_addr;          /* Start address of this transfer */
+  __volatile__ unsigned int cnt;        /* How many bytes to transfer */
+  __volatile__ unsigned int dma_test;   /* DMA test register */
+};
+
+/* DVMA chip revisions */
+enum dvma_rev {
+	dvmarev0,
+	dvmaesc1,
+	dvmarev1,
+	dvmarev2,
+	dvmarev3,
+	dvmarevplus,
+	dvmahme
+};
+
+#define DMA_HASCOUNT(rev)  ((rev)==dvmaesc1)
+
+/* Linux DMA information structure, filled during probe. */
+struct Linux_SBus_DMA {
+	struct Linux_SBus_DMA *next;
+	struct linux_sbus_device *SBus_dev;
+	struct sparc_dma_registers *regs;
+
+	/* Status, misc info */
+	int node;                /* Prom node for this DMA device */
+	int running;             /* Are we doing DMA now? */
+	int allocated;           /* Are we "owned" by anyone yet? */
+
+	/* Transfer information. */
+	unsigned int addr;       /* Start address of current transfer */
+	int nbytes;              /* Size of current transfer */
+	int realbytes;           /* For splitting up large transfers, etc. */
+
+	/* DMA revision */
+	enum dvma_rev revision;
+};
+
+extern struct Linux_SBus_DMA *dma_chain;
+
+/* Broken hardware... */
+#define DMA_ISBROKEN(dma)    ((dma)->revision == dvmarev1)
+#define DMA_ISESC1(dma)      ((dma)->revision == dvmaesc1)
+
+/* Main routines in dma.c */
+extern void dump_dma_regs(struct sparc_dma_registers *);
+extern unsigned long dvma_init(struct linux_sbus *, unsigned long);
+
+/* Fields in the cond_reg register */
+/* First, the version identification bits */
+#define DMA_DEVICE_ID    0xf0000000        /* Device identification bits */
+#define DMA_VERS0        0x00000000        /* Sunray DMA version */
+#define DMA_ESCV1        0x40000000        /* DMA ESC Version 1 */
+#define DMA_VERS1        0x80000000        /* DMA rev 1 */
+#define DMA_VERS2        0xa0000000        /* DMA rev 2 */
+#define DMA_VERHME       0xb0000000        /* DMA hme gate array */
+#define DMA_VERSPLUS     0x90000000        /* DMA rev 1 PLUS */
+
+#define DMA_HNDL_INTR    0x00000001        /* An IRQ needs to be handled */
+#define DMA_HNDL_ERROR   0x00000002        /* We need to take an error */
+#define DMA_FIFO_ISDRAIN 0x0000000c        /* The DMA FIFO is draining */
+#define DMA_INT_ENAB     0x00000010        /* Turn on interrupts */
+#define DMA_FIFO_INV     0x00000020        /* Invalidate the FIFO */
+#define DMA_ACC_SZ_ERR   0x00000040        /* The access size was bad */
+#define DMA_FIFO_STDRAIN 0x00000040        /* DMA_VERS1 Drain the FIFO */
+#define DMA_RST_SCSI     0x00000080        /* Reset the SCSI controller */
+#define DMA_RST_ENET     DMA_RST_SCSI      /* Reset the ENET controller */
+#define DMA_ST_WRITE     0x00000100        /* write from device to memory */
+#define DMA_ENABLE       0x00000200        /* Fire up DMA, handle requests */
+#define DMA_PEND_READ    0x00000400        /* DMA_VERS1/0/PLUS Pending Read */
+#define DMA_ESC_BURST    0x00000800        /* 1=16byte 0=32byte */
+#define DMA_READ_AHEAD   0x00001800        /* DMA read ahead partial longword */
+#define DMA_DSBL_RD_DRN  0x00001000        /* No EC drain on slave reads */
+#define DMA_BCNT_ENAB    0x00002000        /* If on, use the byte counter */
+#define DMA_TERM_CNTR    0x00004000        /* Terminal counter */
+#define DMA_CSR_DISAB    0x00010000        /* No FIFO drains during csr */
+#define DMA_SCSI_DISAB   0x00020000        /* No FIFO drains during reg */
+#define DMA_DSBL_WR_INV  0x00020000        /* No EC inval. on slave writes */
+#define DMA_ADD_ENABLE   0x00040000        /* Special ESC DVMA optimization */
+#define DMA_E_BURST8	 0x00040000	   /* ENET: SBUS r/w burst size */
+#define DMA_BRST_SZ      0x000c0000        /* SCSI: SBUS r/w burst size */
+#define DMA_BRST64       0x00080000        /* SCSI: 64byte bursts (HME on UltraSparc only) */
+#define DMA_BRST32       0x00040000        /* SCSI: 32byte bursts */
+#define DMA_BRST16       0x00000000        /* SCSI: 16byte bursts */
+#define DMA_BRST0        0x00080000        /* SCSI: no bursts (non-HME gate arrays) */
+#define DMA_ADDR_DISAB   0x00100000        /* No FIFO drains during addr */
+#define DMA_2CLKS        0x00200000        /* Each transfer = 2 clock ticks */
+#define DMA_3CLKS        0x00400000        /* Each transfer = 3 clock ticks */
+#define DMA_EN_ENETAUI   DMA_3CLKS         /* Put lance into AUI-cable mode */
+#define DMA_CNTR_DISAB   0x00800000        /* No IRQ when DMA_TERM_CNTR set */
+#define DMA_AUTO_NADDR   0x01000000        /* Use "auto nxt addr" feature */
+#define DMA_SCSI_ON      0x02000000        /* Enable SCSI dma */
+#define DMA_PARITY_OFF   0x02000000        /* HME: disable parity checking */
+#define DMA_LOADED_ADDR  0x04000000        /* Address has been loaded */
+#define DMA_LOADED_NADDR 0x08000000        /* Next address has been loaded */
+
+/* Values describing the burst-size property from the PROM */
+#define DMA_BURST1       0x01
+#define DMA_BURST2       0x02
+#define DMA_BURST4       0x04
+#define DMA_BURST8       0x08
+#define DMA_BURST16      0x10
+#define DMA_BURST32      0x20
+#define DMA_BURST64      0x40
+#define DMA_BURSTBITS    0x7f
+
+/* Determine highest possible final transfer address given a base */
+#define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL))
+
+/* Yes, I hack a lot of elisp in my spare time... */
+#define DMA_ERROR_P(regs)  ((((regs)->cond_reg) & DMA_HNDL_ERROR))
+#define DMA_IRQ_P(regs)    ((((regs)->cond_reg) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)))
+#define DMA_WRITE_P(regs)  ((((regs)->cond_reg) & DMA_ST_WRITE))
+#define DMA_OFF(regs)      ((((regs)->cond_reg) &= (~DMA_ENABLE)))
+#define DMA_INTSOFF(regs)  ((((regs)->cond_reg) &= (~DMA_INT_ENAB)))
+#define DMA_INTSON(regs)   ((((regs)->cond_reg) |= (DMA_INT_ENAB)))
+#define DMA_PUNTFIFO(regs) ((((regs)->cond_reg) |= DMA_FIFO_INV))
+#define DMA_SETSTART(regs, addr)  ((((regs)->st_addr) = (char *) addr))
+#define DMA_BEGINDMA_W(regs) \
+        ((((regs)->cond_reg |= (DMA_ST_WRITE|DMA_ENABLE|DMA_INT_ENAB))))
+#define DMA_BEGINDMA_R(regs) \
+        ((((regs)->cond_reg |= ((DMA_ENABLE|DMA_INT_ENAB)&(~DMA_ST_WRITE)))))
+
+/* For certain DMA chips, we need to disable ints upon irq entry
+ * and turn them back on when we are done.  So in any ESP interrupt
+ * handler you *must* call DMA_IRQ_ENTRY upon entry and DMA_IRQ_EXIT
+ * when leaving the handler.  You have been warned...
+ */
+#define DMA_IRQ_ENTRY(dma, dregs) do { \
+        if(DMA_ISBROKEN(dma)) DMA_INTSOFF(dregs); \
+   } while (0)
+
+#define DMA_IRQ_EXIT(dma, dregs) do { \
+	if(DMA_ISBROKEN(dma)) DMA_INTSON(dregs); \
+   } while(0)
+
+/* Pause until counter runs out or BIT isn't set in the DMA condition
+ * register.
+ */
+extern __inline__ void sparc_dma_pause(struct sparc_dma_registers *regs,
+				       unsigned long bit)
+{
+	int ctr = 50000;   /* Let's find some bugs ;) */
+
+	/* Busy wait until the bit is not set any more */
+	while((regs->cond_reg&bit) && (ctr>0)) {
+		ctr--;
+		__delay(5);
+	}
+
+	/* Check for bogus outcome. */
+	if(!ctr)
+		panic("DMA timeout");
+}
+
+/* Reset the friggin' thing... */
+#define DMA_RESET(dma) do { \
+	struct sparc_dma_registers *regs = dma->regs;                      \
+	/* Let the current FIFO drain itself */                            \
+	sparc_dma_pause(regs, (DMA_FIFO_ISDRAIN));                         \
+	/* Reset the logic */                                              \
+	regs->cond_reg |= (DMA_RST_SCSI);     /* assert */                 \
+	__delay(400);                         /* let the bits set ;) */    \
+	regs->cond_reg &= ~(DMA_RST_SCSI);    /* de-assert */              \
+	sparc_dma_enable_interrupts(regs);    /* Re-enable interrupts */   \
+	/* Enable FAST transfers if available */                           \
+	if(dma->revision>dvmarev1) regs->cond_reg |= DMA_3CLKS;            \
+	dma->running = 0;                                                  \
+} while(0)
+
+#define for_each_dvma(dma) \
+        for((dma) = dma_chain; (dma); (dma) = (dma)->next)
+
+extern int get_dma_list(char *);
+extern int request_dma(unsigned int, __const__ char *);
+extern void free_dma(unsigned int);
+
+#endif /* !(_ASM_SPARC64_DMA_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/elf.h linux/include/asm-sparc64/elf.h
--- v2.1.15/linux/include/asm-sparc64/elf.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/elf.h	Fri Dec 13 11:37:41 1996
@@ -0,0 +1,34 @@
+/* $Id: elf.h,v 1.1 1996/11/20 15:27:38 davem Exp $ */
+#ifndef __ASM_SPARC64_ELF_H
+#define __ASM_SPARC64_ELF_H
+
+/*
+ * ELF register definitions..
+ */
+
+#include <asm/ptrace.h>
+
+typedef unsigned long elf_greg_t;
+
+#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef unsigned long elf_fpregset_t;
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ((x) == EM_SPARC)
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_ARCH	EM_SPARC
+#define ELF_CLASS	ELFCLASS32
+#define ELF_DATA	ELFDATA2MSB;
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE	4096
+
+
+#endif /* !(__ASM_SPARC64_ELF_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/errno.h linux/include/asm-sparc64/errno.h
--- v2.1.15/linux/include/asm-sparc64/errno.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/errno.h	Fri Dec 13 11:37:41 1996
@@ -0,0 +1,133 @@
+/* $Id: errno.h,v 1.1 1996/11/20 15:27:39 davem Exp $ */
+#ifndef _SPARC64_ERRNO_H
+#define _SPARC64_ERRNO_H
+
+/* These match the SunOS error numbering scheme. */
+#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	EWOULDBLOCK	EAGAIN	/* Operation would block */
+#define	EINPROGRESS	36	/* Operation now in progress */
+#define	EALREADY	37	/* Operation already in progress */
+#define	ENOTSOCK	38	/* Socket operation on non-socket */
+#define	EDESTADDRREQ	39	/* Destination address required */
+#define	EMSGSIZE	40	/* Message too long */
+#define	EPROTOTYPE	41	/* Protocol wrong type for socket */
+#define	ENOPROTOOPT	42	/* Protocol not available */
+#define	EPROTONOSUPPORT	43	/* Protocol not supported */
+#define	ESOCKTNOSUPPORT	44	/* Socket type not supported */
+#define	EOPNOTSUPP	45	/* Op not supported on transport endpoint */
+#define	EPFNOSUPPORT	46	/* Protocol family not supported */
+#define	EAFNOSUPPORT	47	/* Address family not supported by protocol */
+#define	EADDRINUSE	48	/* Address already in use */
+#define	EADDRNOTAVAIL	49	/* Cannot assign requested address */
+#define	ENETDOWN	50	/* Network is down */
+#define	ENETUNREACH	51	/* Network is unreachable */
+#define	ENETRESET	52	/* Net dropped connection because of reset */
+#define	ECONNABORTED	53	/* Software caused connection abort */
+#define	ECONNRESET	54	/* Connection reset by peer */
+#define	ENOBUFS		55	/* No buffer space available */
+#define	EISCONN		56	/* Transport endpoint is already connected */
+#define	ENOTCONN	57	/* Transport endpoint is not connected */
+#define	ESHUTDOWN	58	/* No send after transport endpoint shutdown */
+#define	ETOOMANYREFS	59	/* Too many references: cannot splice */
+#define	ETIMEDOUT	60	/* Connection timed out */
+#define	ECONNREFUSED	61	/* Connection refused */
+#define	ELOOP		62	/* Too many symbolic links encountered */
+#define	ENAMETOOLONG	63	/* File name too long */
+#define	EHOSTDOWN	64	/* Host is down */
+#define	EHOSTUNREACH	65	/* No route to host */
+#define	ENOTEMPTY	66	/* Directory not empty */
+#define EPROCLIM        67      /* SUNOS: Too many processes */
+#define	EUSERS		68	/* Too many users */
+#define	EDQUOT		69	/* Quota exceeded */
+#define	ESTALE		70	/* Stale NFS file handle */
+#define	EREMOTE		71	/* Object is remote */
+#define	ENOSTR		72	/* Device not a stream */
+#define	ETIME		73	/* Timer expired */
+#define	ENOSR		74	/* Out of streams resources */
+#define	ENOMSG		75	/* No message of desired type */
+#define	EBADMSG		76	/* Not a data message */
+#define	EIDRM		77	/* Identifier removed */
+#define	EDEADLK		78	/* Resource deadlock would occur */
+#define	ENOLCK		79	/* No record locks available */
+#define	ENONET		80	/* Machine is not on the network */
+#define ERREMOTE        81      /* SunOS: Too many lvls of remote in path */
+#define	ENOLINK		82	/* Link has been severed */
+#define	EADV		83	/* Advertise error */
+#define	ESRMNT		84	/* Srmount error */
+#define	ECOMM		85      /* Communication error on send */
+#define	EPROTO		86	/* Protocol error */
+#define	EMULTIHOP	87	/* Multihop attempted */
+#define	EDOTDOT		88	/* RFS specific error */
+#define	EREMCHG		89	/* Remote address changed */
+#define	ENOSYS		90	/* Function not implemented */
+
+/* The rest have no SunOS equivalent. */
+#define	ESTRPIPE	91	/* Streams pipe error */
+#define	EOVERFLOW	92	/* Value too large for defined data type */
+#define	EBADFD		93	/* File descriptor in bad state */
+#define	ECHRNG		94	/* Channel number out of range */
+#define	EL2NSYNC	95	/* Level 2 not synchronized */
+#define	EL3HLT		96	/* Level 3 halted */
+#define	EL3RST		97	/* Level 3 reset */
+#define	ELNRNG		98	/* Link number out of range */
+#define	EUNATCH		99	/* Protocol driver not attached */
+#define	ENOCSI		100	/* No CSI structure available */
+#define	EL2HLT		101	/* Level 2 halted */
+#define	EBADE		102	/* Invalid exchange */
+#define	EBADR		103	/* Invalid request descriptor */
+#define	EXFULL		104	/* Exchange full */
+#define	ENOANO		105	/* No anode */
+#define	EBADRQC		106	/* Invalid request code */
+#define	EBADSLT		107	/* Invalid slot */
+#define	EDEADLOCK	108	/* File locking deadlock error */
+#define	EBFONT		109	/* Bad font file format */
+#define	ELIBEXEC	110	/* Cannot exec a shared library directly */
+#define	ENODATA		111	/* No data available */
+#define	ELIBBAD		112	/* Accessing a corrupted shared library */
+#define	ENOPKG		113	/* Package not installed */
+#define	ELIBACC		114	/* Can not access a needed shared library */
+#define	ENOTUNIQ	115	/* Name not unique on network */
+#define	ERESTART	116	/* Interrupted syscall should be restarted */
+#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	EILSEQ		122	/* Illegal byte sequence */
+#define	ELIBMAX		123	/* Atmpt to link in too many shared libs */
+#define	ELIBSCN		124	/* .lib section in a.out corrupted */
+
+#endif /* !(_SPARC64_ERRNO_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/fbio.h linux/include/asm-sparc64/fbio.h
--- v2.1.15/linux/include/asm-sparc64/fbio.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/fbio.h	Fri Dec 13 11:37:46 1996
@@ -0,0 +1,279 @@
+#ifndef __LINUX_FBIO_H
+#define __LINUX_FBIO_H
+
+/* Constants used for fbio SunOS compatibility */
+/* (C) 1996 Miguel de Icaza */
+
+/* Frame buffer types */
+#define FBTYPE_NOTYPE           -1
+#define FBTYPE_SUN1BW           0   /* mono */
+#define FBTYPE_SUN1COLOR        1 
+#define FBTYPE_SUN2BW           2 
+#define FBTYPE_SUN2COLOR        3 
+#define FBTYPE_SUN2GP           4 
+#define FBTYPE_SUN5COLOR        5 
+#define FBTYPE_SUN3COLOR        6 
+#define FBTYPE_MEMCOLOR         7 
+#define FBTYPE_SUN4COLOR        8 
+ 
+#define FBTYPE_NOTSUN1          9 
+#define FBTYPE_NOTSUN2          10
+#define FBTYPE_NOTSUN3          11
+ 
+#define FBTYPE_SUNFAST_COLOR    12  /* cg6 */
+#define FBTYPE_SUNROP_COLOR     13
+#define FBTYPE_SUNFB_VIDEO      14
+#define FBTYPE_SUNGIFB          15
+#define FBTYPE_SUNGPLAS         16
+#define FBTYPE_SUNGP3           17
+#define FBTYPE_SUNGT            18
+#define FBTYPE_SUNLEO           19      /* zx Leo card */
+#define FBTYPE_MDICOLOR         20      /* cg14 */
+#define FBTYPE_TCXCOLOR		21	/* SUNW,tcx card */
+
+#define FBTYPE_LASTPLUSONE      21	/* This is not last + 1 in fact... */
+
+/* fbio ioctls */
+/* Returned by FBIOGTYPE */
+struct  fbtype {
+        int     fb_type;        /* fb type, see above */
+        int     fb_height;      /* pixels */
+        int     fb_width;       /* pixels */
+        int     fb_depth;
+        int     fb_cmsize;      /* color map entries */
+        int     fb_size;        /* fb size in bytes */
+};
+#define FBIOGTYPE _IOR('F', 0, struct fbtype)
+
+/* Used by FBIOPUTCMAP */
+struct  fbcmap {
+        int             index;          /* first element (0 origin) */
+        int             count;
+        unsigned char   *red;
+        unsigned char   *green;
+        unsigned char   *blue;
+};
+
+#define FBIOPUTCMAP _IOW('F', 3, struct fbcmap)
+#define FBIOGETCMAP _IOW('F', 4, struct fbcmap)
+
+/* # of device specific values */
+#define FB_ATTR_NDEVSPECIFIC    8
+/* # of possible emulations */
+#define FB_ATTR_NEMUTYPES       4
+ 
+struct fbsattr {
+        int     flags;
+        int     emu_type;	/* -1 if none */
+        int     dev_specific[FB_ATTR_NDEVSPECIFIC];
+};
+ 
+struct fbgattr {
+        int     real_type;	/* real frame buffer type */
+        int     owner;		/* unknown */
+        struct fbtype fbtype;	/* real frame buffer fbtype */
+        struct fbsattr sattr;   
+        int     emu_types[FB_ATTR_NEMUTYPES]; /* supported emulations */
+};
+#define FBIOSATTR  _IOW('F', 5, struct fbgattr) /* Unsupported: */
+#define FBIOGATTR  _IOR('F', 6, struct fbgattr)	/* supported */
+
+#define FBIOSVIDEO _IOW('F', 7, int)
+#define FBIOGVIDEO _IOR('F', 8, int)
+
+/* Cursor position */
+struct fbcurpos {
+#ifdef __KERNEL__
+	short fbx, fby;
+#else
+        short x, y;
+#endif
+};
+
+/* Cursor operations */
+#define FB_CUR_SETCUR   0x01	/* Enable/disable cursor display */
+#define FB_CUR_SETPOS   0x02	/* set cursor position */
+#define FB_CUR_SETHOT   0x04	/* set cursor hotspot */
+#define FB_CUR_SETCMAP  0x08	/* set color map for the cursor */
+#define FB_CUR_SETSHAPE 0x10	/* set shape */
+#define FB_CUR_SETALL   0x1F	/* all of the above */
+
+struct fbcursor {
+        short set;              /* what to set, choose from the list above */
+        short enable;           /* cursor on/off */
+        struct fbcurpos pos;    /* cursor position */
+        struct fbcurpos hot;    /* cursor hot spot */
+        struct fbcmap cmap;     /* color map info */
+        struct fbcurpos size;   /* cursor bit map size */
+        char *image;            /* cursor image bits */
+        char *mask;             /* cursor mask bits */
+};
+
+/* set/get cursor attributes/shape */
+#define FBIOSCURSOR     _IOW('F', 24, struct fbcursor)
+#define FBIOGCURSOR     _IOWR('F', 25, struct fbcursor)
+ 
+/* set/get cursor position */
+#define FBIOSCURPOS     _IOW('F', 26, struct fbcurpos)
+#define FBIOGCURPOS     _IOW('F', 27, struct fbcurpos)
+ 
+/* get max cursor size */
+#define FBIOGCURMAX     _IOR('F', 28, struct fbcurpos)
+
+/* wid manipulation */
+struct fb_wid_alloc {
+#define FB_WID_SHARED_8		0
+#define FB_WID_SHARED_24	1
+#define FB_WID_DBL_8		2
+#define FB_WID_DBL_24		3
+	__u32	wa_type;
+	__s32	wa_index;	/* Set on return */
+	__u32	wa_count;	
+};
+struct fb_wid_item {
+	__u32	wi_type;
+	__s32	wi_index;
+	__u32	wi_attrs;
+	__u32	wi_values[32];
+};
+struct fb_wid_list {
+	__u32	wl_flags;
+	__u32	wl_count;
+	struct fb_wid_item	*wl_list;
+};
+
+#define FBIO_WID_ALLOC	_IOWR('F', 30, struct fb_wid_alloc)
+#define FBIO_WID_FREE	_IOW('F', 31, struct fb_wid_alloc)
+#define FBIO_WID_PUT	_IOW('F', 32, struct fb_wid_list)
+#define FBIO_WID_GET	_IOWR('F', 33, struct fb_wid_list)
+
+/* Cg14 ioctls */
+#define MDI_IOCTL          ('M'<<8)
+#define MDI_RESET          (MDI_IOCTL|1)
+#define MDI_GET_CFGINFO    (MDI_IOCTL|2)
+#define MDI_SET_PIXELMODE  (MDI_IOCTL|3)
+#    define MDI_32_PIX     32
+#    define MDI_16_PIX     16
+#    define MDI_8_PIX      8
+
+struct mdi_cfginfo {
+	int     mdi_ncluts;     /* Number of implemented CLUTs in this MDI */
+        int     mdi_type;       /* FBTYPE name */
+        int     mdi_height;     /* height */
+        int     mdi_width;      /* widht */
+        int     mdi_size;       /* available ram */
+        int     mdi_mode;       /* 8bpp, 16bpp or 32bpp */
+        int     mdi_pixfreq;    /* pixel clock (from PROM) */
+};
+
+/* SparcLinux specific ioctl for the MDI, should be replaced for
+ * the SET_XLUT/SET_CLUTn ioctls instead
+ */
+#define MDI_CLEAR_XLUT       (MDI_IOCTL|9)
+
+/* leo ioctls */
+struct leo_clut_alloc {
+	__u32	clutid;	/* Set on return */
+ 	__u32	flag;
+ 	__u32	index;
+};
+
+struct leo_clut {
+#define LEO_CLUT_WAIT	0x00000001	/* Not yet implemented */
+ 	__u32	flag;
+ 	__u32	clutid;
+ 	__u32	offset;
+ 	__u32	count;
+ 	char *	red;
+ 	char *	green;
+ 	char *	blue;
+};
+#define LEO_CLUTALLOC	_IOWR('L', 53, struct leo_clut_alloc)
+#define LEO_CLUTFREE	_IOW('L', 54, struct leo_clut_alloc)
+#define LEO_CLUTREAD	_IOW('L', 55, struct leo_clut)
+#define LEO_CLUTPOST	_IOW('L', 56, struct leo_clut)
+#define LEO_SETGAMMA	_IOW('L', 68, int) /* Not yet implemented */
+#define LEO_GETGAMMA	_IOR('L', 69, int) /* Not yet implemented */
+
+#ifdef __KERNEL__
+/* Addresses on the fd of a cgsix that are mappable */
+#define CG6_FBC    0x70000000
+#define CG6_TEC    0x70001000
+#define CG6_BTREGS 0x70002000
+#define CG6_FHC    0x70004000
+#define CG6_THC    0x70005000
+#define CG6_ROM    0x70006000
+#define CG6_RAM    0x70016000
+#define CG6_DHC    0x80000000
+
+#define CG3_MMAP_OFFSET 0x4000000
+
+/* Addresses on the fd of a tcx that are mappable */
+#define TCX_RAM8BIT   		0x00000000
+#define TCX_RAM24BIT   		0x01000000
+#define TCX_UNK3   		0x10000000
+#define TCX_UNK4   		0x20000000
+#define TCX_CONTROLPLANE   	0x28000000
+#define TCX_UNK6   		0x30000000
+#define TCX_UNK7   		0x38000000
+#define TCX_TEC    		0x70000000
+#define TCX_BTREGS 		0x70002000
+#define TCX_THC    		0x70004000
+#define TCX_DHC    		0x70008000
+#define TCX_ALT	   		0x7000a000
+#define TCX_SYNC   		0x7000e000
+#define TCX_UNK2    		0x70010000
+
+/* CG14 definitions */
+
+/* Offsets into the OBIO space: */
+#define CG14_REGS        0       /* registers */
+#define CG14_CURSORREGS  0x1000  /* cursor registers */
+#define CG14_DACREGS     0x2000  /* DAC registers */
+#define CG14_XLUT        0x3000  /* X Look Up Table -- ??? */
+#define CG14_CLUT1       0x4000  /* Color Look Up Table */
+#define CG14_CLUT2       0x5000  /* Color Look Up Table */
+#define CG14_CLUT3       0x6000  /* Color Look Up Table */
+#define CG14_AUTO	 0xf000
+
+#endif /* KERNEL */
+
+/* These are exported to userland for applications to use */
+/* Mappable offsets for the cg14: control registers */
+#define MDI_DIRECT_MAP 0x10000000
+#define MDI_CTLREG_MAP 0x20000000
+#define MDI_CURSOR_MAP 0x30000000
+#define MDI_SHDW_VRT_MAP 0x40000000
+
+/* Mappable offsets for the cg14: frame buffer resolutions */
+/* 32 bits */
+#define MDI_CHUNKY_XBGR_MAP 0x50000000
+#define MDI_CHUNKY_BGR_MAP 0x60000000
+
+/* 16 bits */
+#define MDI_PLANAR_X16_MAP 0x70000000
+#define MDI_PLANAR_C16_MAP 0x80000000
+
+/* 8 bit is done as CG3 MMAP offset */
+/* 32 bits, planar */
+#define MDI_PLANAR_X32_MAP 0x90000000
+#define MDI_PLANAR_B32_MAP 0xa0000000
+#define MDI_PLANAR_G32_MAP 0xb0000000
+#define MDI_PLANAR_R32_MAP 0xc0000000
+
+/* Mappable offsets on leo */
+#define LEO_SS0_MAP            0x00000000
+#define LEO_LC_SS0_USR_MAP     0x00800000
+#define LEO_LD_SS0_MAP         0x00801000
+#define LEO_LX_CURSOR_MAP      0x00802000
+#define LEO_SS1_MAP            0x00803000
+#define LEO_LC_SS1_USR_MAP     0x01003000
+#define LEO_LD_SS1_MAP         0x01004000
+#define LEO_UNK_MAP            0x01005000
+#define LEO_LX_KRN_MAP         0x01006000
+#define LEO_LC_SS0_KRN_MAP     0x01007000
+#define LEO_LC_SS1_KRN_MAP     0x01008000
+#define LEO_LD_GBL_MAP         0x01009000
+#define LEO_UNK2_MAP           0x0100a000
+
+#endif /* __LINUX_FBIO_H */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/fcntl.h linux/include/asm-sparc64/fcntl.h
--- v2.1.15/linux/include/asm-sparc64/fcntl.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/fcntl.h	Fri Dec 13 11:37:46 1996
@@ -0,0 +1,60 @@
+/* $Id: fcntl.h,v 1.1 1996/11/20 15:28:41 davem Exp $ */
+#ifndef _SPARC64_FCNTL_H
+#define _SPARC64_FCNTL_H
+
+/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
+   located on an ext2 file system */
+#define O_RDONLY	0x0000
+#define O_WRONLY	0x0001
+#define O_RDWR		0x0002
+#define O_ACCMODE	0x0003
+#define O_NDELAY	0x0004
+#define O_APPEND	0x0008
+#define FASYNC		0x0040	/* fcntl, for BSD compatibility */
+#define O_CREAT		0x0200	/* not fcntl */
+#define O_TRUNC		0x0400	/* not fcntl */
+#define O_EXCL		0x0800	/* not fcntl */
+#define O_SYNC		0x2000
+#define O_NONBLOCK	0x4000
+#define O_NOCTTY	0x8000	/* not fcntl */
+
+#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_GETOWN	5	/*  for sockets. */
+#define F_SETOWN	6	/*  for sockets. */
+#define F_GETLK		7
+#define F_SETLK		8
+#define F_SETLKW	9
+
+/* for F_[GET|SET]FL */
+#define FD_CLOEXEC	1	/* actually anything with low bit set goes */
+
+/* for posix fcntl() and lockf() */
+#define F_RDLCK		1
+#define F_WRLCK		2
+#define F_UNLCK		3
+
+/* 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;
+	short __unused;
+};
+
+#endif /* !(_SPARC64_FCNTL_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/floppy.h linux/include/asm-sparc64/floppy.h
--- v2.1.15/linux/include/asm-sparc64/floppy.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/floppy.h	Fri Dec 13 11:37:47 1996
@@ -0,0 +1,360 @@
+/* $Id: floppy.h,v 1.1 1996/11/20 15:31:07 davem Exp $
+ * asm-sparc64/floppy.h: Sparc specific parts of the Floppy driver.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __ASM_SPARC64_FLOPPY_H
+#define __ASM_SPARC64_FLOPPY_H
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>
+#include <asm/oplib.h>
+#include <asm/auxio.h>
+#include <asm/irq.h>
+
+/* References:
+ * 1) Netbsd Sun floppy driver.
+ * 2) NCR 82077 controller manual
+ * 3) Intel 82077 controller manual
+ */
+struct sun_flpy_controller {
+	volatile unsigned char status_82072;  /* Main Status reg. */
+#define dcr_82072              status_82072   /* Digital Control reg. */
+#define status1_82077          status_82072   /* Auxiliary Status reg. 1 */
+
+	volatile unsigned char data_82072;    /* Data fifo. */
+#define status2_82077          data_82072     /* Auxiliary Status reg. 2 */
+
+	volatile unsigned char dor_82077;     /* Digital Output reg. */
+	volatile unsigned char tapectl_82077; /* What the? Tape control reg? */
+
+	volatile unsigned char status_82077;  /* Main Status Register. */
+#define drs_82077              status_82077   /* Digital Rate Select reg. */
+
+	volatile unsigned char data_82077;    /* Data fifo. */
+	volatile unsigned char ___unused;
+	volatile unsigned char dir_82077;     /* Digital Input reg. */
+#define dcr_82077              dir_82077      /* Config Control reg. */
+};
+
+/* You'll only ever find one controller on a SparcStation anyways. */
+static struct sun_flpy_controller *sun_fdc = NULL;
+volatile unsigned char *fdc_status;
+
+struct sun_floppy_ops {
+	unsigned char (*fd_inb)(int port);
+	void (*fd_outb)(unsigned char value, int port);
+};
+
+static struct sun_floppy_ops sun_fdops;
+
+#define fd_inb(port)              sun_fdops.fd_inb(port)
+#define fd_outb(value,port)       sun_fdops.fd_outb(value,port)
+#define fd_enable_dma()           sun_fd_enable_dma()
+#define fd_disable_dma()          sun_fd_disable_dma()
+#define fd_request_dma()          (0) /* nothing... */
+#define fd_free_dma()             /* nothing... */
+#define fd_clear_dma_ff()         /* nothing... */
+#define fd_set_dma_mode(mode)     sun_fd_set_dma_mode(mode)
+#define fd_set_dma_addr(addr)     sun_fd_set_dma_addr(addr)
+#define fd_set_dma_count(count)   sun_fd_set_dma_count(count)
+#define fd_enable_irq()           /* nothing... */
+#define fd_disable_irq()          /* nothing... */
+#define fd_cacheflush(addr, size) /* nothing... */
+#define fd_request_irq()          sun_fd_request_irq()
+#define fd_free_irq()             /* nothing... */
+#if 0  /* P3: added by Alain, these cause a MMU corruption. 19960524 XXX */
+#define fd_dma_mem_alloc(size)    ((unsigned long) vmalloc(size))
+#define fd_dma_mem_free(addr,size) (vfree((void *)(addr)))
+#endif
+
+#define FLOPPY_MOTOR_MASK         0x10
+
+/* It's all the same... */
+#define virt_to_bus(x)            (x)
+#define bus_to_virt(x)            (x)
+
+/* XXX This isn't really correct. XXX */
+#define get_dma_residue(x)        (0)
+
+#define FLOPPY0_TYPE  4
+#define FLOPPY1_TYPE  0
+
+/* Super paranoid... */
+#undef HAVE_DISABLE_HLT
+
+/* Here is where we catch the floppy driver trying to initialize,
+ * therefore this is where we call the PROM device tree probing
+ * routine etc. on the Sparc.
+ */
+#define FDC1                      sun_floppy_init()
+
+static int FDC2=-1;
+
+#define N_FDC    1
+#define N_DRIVE  8
+
+/* No 64k boundary crossing problems on the Sparc. */
+#define CROSS_64KB(a,s) (0)
+
+/* Routines unique to each controller type on a Sun. */
+static unsigned char sun_82072_fd_inb(int port)
+{
+	switch(port & 7) {
+	default:
+		printk("floppy: Asked to read unknown port %d\n", port);
+		panic("floppy: Port bolixed.");
+	case 4: /* FD_STATUS */
+		return sun_fdc->status_82072 & ~STATUS_DMA;
+	case 5: /* FD_DATA */
+		return sun_fdc->data_82072;
+	case 7: /* FD_DIR */
+		return (*AUXREG & AUXIO_FLPY_DCHG)? 0x80: 0;
+	};
+	panic("sun_82072_fd_inb: How did I get here?");
+}
+
+static void sun_82072_fd_outb(unsigned char value, int port)
+{
+	switch(port & 7) {
+	default:
+		printk("floppy: Asked to write to unknown port %d\n", port);
+		panic("floppy: Port bolixed.");
+	case 2: /* FD_DOR */
+		/* Oh geese, 82072 on the Sun has no DOR register,
+		 * the functionality is implemented via the AUXIO
+		 * I/O register.  So we must emulate the behavior.
+		 *
+		 * ASSUMPTIONS:  There will only ever be one floppy
+		 *               drive attached to a Sun controller
+		 *               and it will be at drive zero.
+		 */
+		{
+			unsigned bits = 0;
+			if (value & 0x10) bits |= AUXIO_FLPY_DSEL;
+			if ((value & 0x80) == 0) bits |= AUXIO_FLPY_EJCT;
+			set_auxio(bits, (~bits) & (AUXIO_FLPY_DSEL|AUXIO_FLPY_EJCT));
+		}
+		break;
+	case 5: /* FD_DATA */
+		sun_fdc->data_82072 = value;
+		break;
+	case 7: /* FD_DCR */
+		sun_fdc->dcr_82072 = value;
+		break;
+	case 4: /* FD_STATUS */
+		sun_fdc->status_82072 = value;
+		break;
+	};
+	return;
+}
+
+static unsigned char sun_82077_fd_inb(int port)
+{
+	switch(port & 7) {
+	default:
+		printk("floppy: Asked to read unknown port %d\n", port);
+		panic("floppy: Port bolixed.");
+	case 4: /* FD_STATUS */
+		return sun_fdc->status_82077 & ~STATUS_DMA;
+	case 5: /* FD_DATA */
+		return sun_fdc->data_82077;
+	case 7: /* FD_DIR */
+		/* XXX: Is DCL on 0x80 in sun4m? */
+		return sun_fdc->dir_82077;
+	};
+	panic("sun_82072_fd_inb: How did I get here?");
+}
+
+static void sun_82077_fd_outb(unsigned char value, int port)
+{
+	switch(port & 7) {
+	default:
+		printk("floppy: Asked to write to unknown port %d\n", port);
+		panic("floppy: Port bolixed.");
+	case 2: /* FD_DOR */
+		/* Happily, the 82077 has a real DOR register. */
+		sun_fdc->dor_82077 = value;
+		break;
+	case 5: /* FD_DATA */
+		sun_fdc->data_82077 = value;
+		break;
+	case 7: /* FD_DCR */
+		sun_fdc->dcr_82077 = value;
+		break;
+	case 4: /* FD_STATUS */
+		sun_fdc->status_82077 = value;
+		break;
+	};
+	return;
+}
+
+/* For pseudo-dma (Sun floppy drives have no real DMA available to
+ * them so we must eat the data fifo bytes directly ourselves) we have
+ * three state variables.  doing_pdma tells our inline low-level
+ * assembly floppy interrupt entry point whether it should sit and eat
+ * bytes from the fifo or just transfer control up to the higher level
+ * floppy interrupt c-code.  I tried very hard but I could not get the
+ * pseudo-dma to work in c-code without getting many overruns and
+ * underruns.  If non-zero, doing_pdma encodes the direction of
+ * the transfer for debugging.  1=read 2=write
+ */
+char *pdma_vaddr;
+unsigned long pdma_size;
+volatile int doing_pdma = 0;
+
+/* This is software state */
+char *pdma_base = 0;
+unsigned long pdma_areasize;
+
+/* Common routines to all controller types on the Sparc. */
+static __inline__ void virtual_dma_init(void)
+{
+	/* nothing... */
+}
+
+static __inline__ void sun_fd_disable_dma(void)
+{
+	doing_pdma = 0;
+	if (pdma_base) {
+		mmu_unlockarea(pdma_base, pdma_areasize);
+		pdma_base = 0;
+	}
+}
+
+static __inline__ void sun_fd_set_dma_mode(int mode)
+{
+	switch(mode) {
+	case DMA_MODE_READ:
+		doing_pdma = 1;
+		break;
+	case DMA_MODE_WRITE:
+		doing_pdma = 2;
+		break;
+	default:
+		printk("Unknown dma mode %d\n", mode);
+		panic("floppy: Giving up...");
+	}
+}
+
+static __inline__ void sun_fd_set_dma_addr(char *buffer)
+{
+	pdma_vaddr = buffer;
+}
+
+static __inline__ void sun_fd_set_dma_count(int length)
+{
+	pdma_size = length;
+}
+
+static __inline__ void sun_fd_enable_dma(void)
+{
+	pdma_vaddr = mmu_lockarea(pdma_vaddr, pdma_size);
+	pdma_base = pdma_vaddr;
+	pdma_areasize = pdma_size;
+}
+
+/* Our low-level entry point in arch/sparc/kernel/entry.S */
+extern void floppy_hardint(int irq, void *unused, struct pt_regs *regs);
+
+static int sun_fd_request_irq(void)
+{
+	static int once = 0;
+	int error;
+
+	if(!once) {
+		once = 1;
+		error = request_fast_irq(FLOPPY_IRQ, floppy_hardint, SA_INTERRUPT, "floppy");
+		return ((error == 0) ? 0 : -1);
+	} else return 0;
+}
+
+static struct linux_prom_registers fd_regs[2];
+
+static int sun_floppy_init(void)
+{
+	char state[128];
+	int tnode, fd_node, num_regs;
+
+	use_virtual_dma = 1;
+	
+	FLOPPY_IRQ = 11;
+	/* Forget it if we aren't on a machine that could possibly
+	 * ever have a floppy drive.
+	 */
+	if((sparc_cpu_model != sun4c && sparc_cpu_model != sun4m) ||
+	   ((idprom->id_machtype == (SM_SUN4C | SM_4C_SLC)) ||
+	    (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC)))) {
+		/* We certainly don't have a floppy controller. */
+		goto no_sun_fdc;
+	}
+	/* Well, try to find one. */
+	tnode = prom_getchild(prom_root_node);
+	fd_node = prom_searchsiblings(tnode, "obio");
+	if(fd_node != 0) {
+		tnode = prom_getchild(fd_node);
+		fd_node = prom_searchsiblings(tnode, "SUNW,fdtwo");
+	} else {
+		fd_node = prom_searchsiblings(tnode, "fd");
+	}
+	if(fd_node == 0) {
+		goto no_sun_fdc;
+	}
+
+	/* The sun4m lets us know if the controller is actually usable. */
+	if(sparc_cpu_model == sun4m) {
+		prom_getproperty(fd_node, "status", state, sizeof(state));
+		if(!strcmp(state, "disabled")) {
+			goto no_sun_fdc;
+		}
+	}
+	num_regs = prom_getproperty(fd_node, "reg", (char *) fd_regs, sizeof(fd_regs));
+	num_regs = (num_regs / sizeof(fd_regs[0]));
+	prom_apply_obio_ranges(fd_regs, num_regs);
+	sun_fdc = (struct sun_flpy_controller *) sparc_alloc_io(fd_regs[0].phys_addr,
+								0x0,
+								fd_regs[0].reg_size,
+								"floppy",
+								fd_regs[0].which_io,
+								0x0);
+	/* Last minute sanity check... */
+	if(sun_fdc->status_82072 == 0xff) {
+		sun_fdc = NULL;
+		goto no_sun_fdc;
+	}
+
+        if(sparc_cpu_model == sun4c) {
+                sun_fdops.fd_inb = sun_82072_fd_inb;
+                sun_fdops.fd_outb = sun_82072_fd_outb;
+                fdc_status = &sun_fdc->status_82072;
+                /* printk("AUXIO @0x%p\n", auxio_register); */ /* P3 */
+        } else {
+                sun_fdops.fd_inb = sun_82077_fd_inb;
+                sun_fdops.fd_outb = sun_82077_fd_outb;
+                fdc_status = &sun_fdc->status_82077;
+                /* printk("DOR @0x%p\n", &sun_fdc->dor_82077); */ /* P3 */
+	}
+
+	/* Success... */
+	return (int) sun_fdc;
+
+no_sun_fdc:
+	return -1;
+}
+
+static int sparc_eject(void)
+{
+	set_dor(0x00, 0xff, 0x90);
+	udelay(500);
+	set_dor(0x00, 0x6f, 0x00);
+	udelay(500);
+	return 0;
+}
+
+#define fd_eject(drive) sparc_eject()
+
+#endif /* !(__ASM_SPARC64_FLOPPY_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/idprom.h linux/include/asm-sparc64/idprom.h
--- v2.1.15/linux/include/asm-sparc64/idprom.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/idprom.h	Fri Dec 13 11:37:47 1996
@@ -0,0 +1,33 @@
+/* $Id: idprom.h,v 1.1 1996/11/20 15:33:43 davem Exp $
+ * idprom.h: Macros and defines for idprom routines
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC64_IDPROM_H
+#define _SPARC64_IDPROM_H
+
+/* Offset into the EEPROM where the id PROM is located on the 4c */
+#define IDPROM_OFFSET  0x7d8
+
+/* On sun4m; physical. */
+/* MicroSPARC(-II) does not decode 31rd bit, but it works. */
+#define IDPROM_OFFSET_M  0xfd8
+
+struct idprom
+{
+	unsigned char	id_format;	/* Format identifier (always 0x01) */
+	unsigned char	id_machtype;	/* Machine type */
+	unsigned char	id_ethaddr[6];	/* Hardware ethernet address */
+	int		id_date;	/* Date of manufacture */
+	unsigned int	id_sernum:24;	/* Unique serial number */
+	unsigned char	id_cksum;	/* Checksum - xor of the data bytes */
+	unsigned char	reserved[16];
+};
+
+extern struct idprom *idprom;
+extern void idprom_init(void);
+
+#define IDPROM_SIZE  (sizeof(struct idprom))
+
+#endif /* !(_SPARC_IDPROM_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/ioctl.h linux/include/asm-sparc64/ioctl.h
--- v2.1.15/linux/include/asm-sparc64/ioctl.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/ioctl.h	Fri Dec 13 11:37:47 1996
@@ -0,0 +1,43 @@
+/* $Id: ioctl.h,v 1.1 1996/12/02 00:05:36 davem Exp $ */
+#ifndef _SPARC64_IOCTL_H
+#define _SPARC64_IOCTL_H
+
+#define _IOC_NRBITS      8
+#define _IOC_TYPEBITS    8
+#define _IOC_SIZEBITS    8
+#define _IOC_RESVBITS    5
+#define _IOC_DIRBITS     3
+
+#define _IOC_NRMASK      ((1 << _IOC_NRBITS)-1)
+#define _IOC_TYPEMASK    ((1 << _IOC_TYPEBITS)-1)
+#define _IOC_RESVMASK    ((1 << _IOC_RESVBITS)-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_RESVSHIFT   (_IOC_SIZESHIFT + _IOC_SIZEBITS)
+#define _IOC_DIRSHIFT    (_IOC_RESVSHIFT + _IOC_RESVBITS)
+
+#define _IOC_NONE        1U
+#define _IOC_READ        2U
+#define _IOC_WRITE       4U
+
+#define _IOC(dir,type,nr,size) \
+        (((dir)  << _IOC_DIRSHIFT) | \
+         ((type) << _IOC_TYPESHIFT) | \
+         ((nr)   << _IOC_NRSHIFT) | \
+         ((size) << _IOC_SIZESHIFT))
+
+#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))
+
+#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)
+
+#endif /* !(_SPARC64_IOCTL_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/ioctls.h linux/include/asm-sparc64/ioctls.h
--- v2.1.15/linux/include/asm-sparc64/ioctls.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/ioctls.h	Fri Dec 13 11:37:47 1996
@@ -0,0 +1,129 @@
+/* $Id: ioctls.h,v 1.1 1996/12/02 00:05:36 davem Exp $ */
+#ifndef _ASM_SPARC64_IOCTLS_H
+#define _ASM_SPARC64_IOCTLS_H
+
+#include <asm/ioctl.h>
+
+/* Big T */
+#define TCGETA		_IOR('T', 1, struct termio)
+#define TCSETA		_IOW('T', 2, struct termio)
+#define TCSETAW		_IOW('T', 3, struct termio)
+#define TCSETAF		_IOW('T', 4, struct termio)
+#define TCSBRK		_IO('T', 5)
+#define TCXONC		_IO('T', 6)
+#define TCFLSH		_IO('T', 7)
+#define TCGETS		_IOR('T', 8, struct termios)
+#define TCSETS		_IOW('T', 9, struct termios)
+#define TCSETSW		_IOW('T', 10, struct termios)
+#define TCSETSF		_IOW('T', 11, struct termios)
+
+/* Note that all the ioctls that are not available in Linux have a 
+ * double underscore on the front to: a) avoid some programs to
+ * thing we support some ioctls under Linux (autoconfiguration stuff)
+ */
+/* Little t */
+#define TIOCGETD	_IOR('t', 0, int)
+#define TIOCSETD	_IOW('t', 1, int)
+#define __TIOCHPCL        _IO('t', 2) /* SunOS Specific */
+#define __TIOCMODG        _IOR('t', 3, int) /* SunOS Specific */
+#define __TIOCMODS        _IOW('t', 4, int) /* SunOS Specific */
+#define __TIOCGETP        _IOR('t', 8, struct sgttyb) /* SunOS Specific */
+#define __TIOCSETP        _IOW('t', 9, struct sgttyb) /* SunOS Specific */
+#define __TIOCSETN        _IOW('t', 10, struct sgttyb) /* SunOS Specific */
+#define TIOCEXCL	_IO('t', 13)
+#define TIOCNXCL	_IO('t', 14)
+#define __TIOCFLUSH       _IOW('t', 16, int) /* SunOS Specific */
+#define __TIOCSETC        _IOW('t', 17, struct tchars) /* SunOS Specific */
+#define __TIOCGETC        _IOR('t', 18, struct tchars) /* SunOS Specific */
+#define __TIOCTCNTL       _IOW('t', 32, int) /* SunOS Specific */
+#define __TIOCSIGNAL      _IOW('t', 33, int) /* SunOS Specific */
+#define __TIOCSETX        _IOW('t', 34, int) /* SunOS Specific */
+#define __TIOCGETX        _IOR('t', 35, int) /* SunOS Specific */
+#define TIOCCONS	_IO('t', 36)
+#define __TIOCSSIZE     _IOW('t', 37, struct sunos_ttysize) /* SunOS Specific */
+#define __TIOCGSIZE     _IOR('t', 38, struct sunos_ttysize) /* SunOS Specific */
+#define TIOCGSOFTCAR	_IOR('t', 100, int)
+#define TIOCSSOFTCAR	_IOW('t', 101, int)
+#define __TIOCUCNTL       _IOW('t', 102, int) /* SunOS Specific */
+#define TIOCSWINSZ	_IOW('t', 103, struct winsize)
+#define TIOCGWINSZ	_IOR('t', 104, struct winsize)
+#define __TIOCREMOTE      _IOW('t', 105, int) /* SunOS Specific */
+#define TIOCMGET	_IOR('t', 106, int)
+#define TIOCMBIC	_IOW('t', 107, int)
+#define TIOCMBIS	_IOW('t', 108, int)
+#define TIOCMSET	_IOW('t', 109, int)
+#define __TIOCSTART       _IO('t', 110) /* SunOS Specific */
+#define __TIOCSTOP        _IO('t', 111) /* SunOS Specific */
+#define TIOCPKT		_IOW('t', 112, int)
+#define TIOCNOTTY	_IO('t', 113)
+#define TIOCSTI		_IOW('t', 114, char)
+#define TIOCOUTQ	_IOR('t', 115, int)
+#define __TIOCGLTC        _IOR('t', 116, struct ltchars) /* SunOS Specific */
+#define __TIOCSLTC        _IOW('t', 117, struct ltchars) /* SunOS Specific */
+/* 118 is the non-posix setpgrp tty ioctl */
+/* 119 is the non-posix getpgrp tty ioctl */
+#define __TIOCCDTR        _IO('t', 120) /* SunOS Specific */
+#define __TIOCSDTR        _IO('t', 121) /* SunOS Specific */
+#define __TIOCCBRK        _IO('t', 122) /* SunOS Specific */
+#define __TIOCSBRK        _IO('t', 123) /* SunOS Specific */
+#define __TIOCLGET        _IOW('t', 124, int) /* SunOS Specific */
+#define __TIOCLSET        _IOW('t', 125, int) /* SunOS Specific */
+#define __TIOCLBIC        _IOW('t', 126, int) /* SunOS Specific */
+#define __TIOCLBIS        _IOW('t', 127, int) /* SunOS Specific */
+#define __TIOCISPACE      _IOR('t', 128, int) /* SunOS Specific */
+#define __TIOCISIZE       _IOR('t', 129, int) /* SunOS Specific */
+#define TIOCSPGRP	_IOW('t', 130, int)
+#define TIOCGPGRP	_IOR('t', 131, int)
+#define TIOCSCTTY	_IO('t', 132)
+
+/* Little f */
+#define FIOCLEX		_IO('f', 1)
+#define FIONCLEX	_IO('f', 2)
+#define FIOASYNC	_IOW('f', 125, int)
+#define FIONBIO		_IOW('f', 126, int)
+#define FIONREAD	_IOR('f', 127, int)
+#define TIOCINQ		FIONREAD
+
+/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it
+ * someday.  This is completely bogus, I know...
+ */
+#define __TCGETSTAT       _IO('T', 200) /* Rutgers specific */
+#define __TCSETSTAT       _IO('T', 201) /* Rutgers specific */
+
+/* Linux specific, no SunOS equivalent. */
+#define TIOCLINUX	0x541C
+#define TIOCGSERIAL	0x541E
+#define TIOCSSERIAL	0x541F
+#define TCSBRKP		0x5425
+#define TIOCTTYGSTRUCT	0x5426
+#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 */
+
+/* Kernel definitions */
+#ifdef __KERNEL__
+#define TIOCGETC __TIOCGETC
+#define TIOCGETP __TIOCGETP
+#define TIOCGLTC __TIOCGLTC
+#define TIOCSLTC __TIOCSLTC
+#define TIOCSETP __TIOCSETP
+#define TIOCSETN __TIOCSETN
+#define TIOCSETC __TIOCSETC
+#endif
+
+/* 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
+
+#endif /* !(_ASM_SPARC64_IOCTLS_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/kbio.h linux/include/asm-sparc64/kbio.h
--- v2.1.15/linux/include/asm-sparc64/kbio.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/kbio.h	Fri Dec 13 11:37:47 1996
@@ -0,0 +1,45 @@
+/* $Id: kbio.h,v 1.1 1996/12/02 00:06:41 davem Exp $ */
+#ifndef __LINUX_KBIO_H
+#define __LINUX_KBIO_H
+
+/* Return keyboard type */
+#define KIOCTYPE    _IOR('k', 9, int)
+/* Return Keyboard layout */
+#define KIOCLAYOUT  _IOR('k', 20, int)
+
+enum {
+    TR_NONE,
+    TR_ASCII,			/* keyboard is in regular state */
+    TR_EVENT,			/* keystrokes sent as firm events */
+    TR_UNTRANS_EVENT		/* EVENT+up and down+no translation */
+};
+
+/* Return the current keyboard translation */
+#define KIOCGTRANS  _IOR('k', 5, int)
+/* Set the keyboard translation */
+#define KIOCTRANS   _IOW('k', 0, int)
+
+/* Send a keyboard command */
+#define KIOCCMD     _IOW('k', 8, int)
+
+/* Return if keystrokes are being sent to /dev/kbd */
+
+/* Set routing of keystrokes to /dev/kbd */
+#define KIOCSDIRECT _IOW('k', 10, int)
+
+/* Set keyboard leds */
+#define KIOCSLED    _IOW('k', 14, unsigned char)
+
+/* Get keyboard leds */
+#define KIOCGLED    _IOR('k', 15, unsigned char)
+
+/* Top bit records if the key is up or down */
+#define KBD_UP      0x80
+
+/* Usable information */
+#define KBD_KEYMASK 0x7f
+
+/* All keys up */
+#define KBD_IDLE    0x75
+
+#endif /* __LINUX_KBIO_H */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/mman.h linux/include/asm-sparc64/mman.h
--- v2.1.15/linux/include/asm-sparc64/mman.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/mman.h	Fri Dec 13 11:37:47 1996
@@ -0,0 +1,49 @@
+/* $Id: mman.h,v 1.1 1996/12/02 00:07:29 davem Exp $ */
+#ifndef __SPARC64_MMAN_H__
+#define __SPARC64_MMAN_H__
+
+/* SunOS'ified... */
+
+#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_RENAME      MAP_ANONYMOUS   /* In SunOS terminology */
+#define MAP_NORESERVE   0x40            /* don't reserve swap pages */
+#define MAP_INHERIT     0x80            /* SunOS doesn't do this, but... */
+#define MAP_LOCKED      0x100           /* lock the mapping */
+#define _MAP_NEW        0x80000000      /* Binary compatibility is fun... */
+
+#define MAP_GROWSDOWN	0x0100		/* stack-like segment */
+#define MAP_DENYWRITE	0x0800		/* ETXTBSY */
+#define MAP_EXECUTABLE	0x1000		/* mark it as an executable */
+
+#define MS_ASYNC	1		/* sync memory asynchronously */
+#define MS_INVALIDATE	2		/* invalidate the caches */
+#define MS_SYNC		4		/* synchronous memory sync */
+
+#define MCL_CURRENT     0x2000          /* lock all currently mapped pages */
+#define MCL_FUTURE      0x4000          /* lock all additions to address space */
+
+/* XXX Need to add flags to SunOS's mctl, mlockall, and madvise system
+ * XXX calls.
+ */
+
+/* SunOS sys_mctl() stuff... */
+#define MC_SYNC         1  /* Sync pages in memory with storage (usu. a file) */
+#define MC_LOCK         2  /* Lock pages into core ram, do not allow swapping of them */
+#define MC_UNLOCK       3  /* Unlock pages locked via previous mctl() with MC_LOCK arg */
+#define MC_LOCKAS       5  /* Lock an entire address space of the calling process */
+#define MC_UNLOCKAS     6  /* Unlock entire address space of calling process */
+
+/* compatibility flags */
+#define MAP_ANON	MAP_ANONYMOUS
+#define MAP_FILE	0
+
+#endif /* __SPARC64_MMAN_H__ */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/page.h linux/include/asm-sparc64/page.h
--- v2.1.15/linux/include/asm-sparc64/page.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/page.h	Fri Dec 13 11:37:47 1996
@@ -0,0 +1,97 @@
+/* $Id: page.h,v 1.2 1996/12/02 00:01:06 davem Exp $ */
+
+#ifndef _SPARC64_PAGE_H
+#define _SPARC64_PAGE_H
+
+#define PAGE_SHIFT   13
+#define PAGE_SIZE    (1UL << PAGE_SHIFT)
+#define PAGE_MASK    (~(PAGE_SIZE-1))
+
+#ifdef __KERNEL__
+
+#define STRICT_MM_TYPECHECKS
+
+#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 iopte; } iopte_t;
+typedef struct { unsigned long pmd; } pmd_t;
+typedef struct { unsigned long pgd; } pgd_t;
+typedef struct { unsigned long ctxd; } ctxd_t;
+typedef struct { unsigned long pgprot; } pgprot_t;
+typedef struct { unsigned long iopgprot; } iopgprot_t;
+
+#define pte_val(x)	((x).pte)
+#define iopte_val(x)	((x).iopte)
+#define pmd_val(x)      ((x).pmd)
+#define pgd_val(x)	((x).pgd)
+#define ctxd_val(x)	((x).ctxd)
+#define pgprot_val(x)	((x).pgprot)
+#define iopgprot_val(x)	((x).iopgprot)
+
+#define __pte(x)	((pte_t) { (x) } )
+#define __iopte(x)	((iopte_t) { (x) } )
+#define __pmd(x)        ((pmd_t) { (x) } )
+#define __pgd(x)	((pgd_t) { (x) } )
+#define __ctxd(x)	((ctxd_t) { (x) } )
+#define __pgprot(x)	((pgprot_t) { (x) } )
+#define __iopgprot(x)	((iopgprot_t) { (x) } )
+
+#else
+/* .. while these make it easier on the compiler */
+typedef unsigned long pte_t;
+typedef unsigned long iopte_t;
+typedef unsigned long pmd_t;
+typedef unsigned long pgd_t;
+typedef unsigned long ctxd_t;
+typedef unsigned long pgprot_t;
+typedef unsigned long iopgprot_t;
+
+#define pte_val(x)	(x)
+#define iopte_val(x)	(x)
+#define pmd_val(x)      (x)
+#define pgd_val(x)	(x)
+#define ctxd_val(x)	(x)
+#define pgprot_val(x)	(x)
+#define iopgprot_val(x)	(x)
+
+#define __pte(x)	(x)
+#define __iopte(x)	(x)
+#define __pmd(x)        (x)
+#define __pgd(x)	(x)
+#define __ctxd(x)	(x)
+#define __pgprot(x)	(x)
+#define __iopgprot(x)	(x)
+
+#endif
+
+#define TASK_UNMAPPED_BASE	0x0000000070000000UL
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
+
+#define PAGE_OFFSET		0xFFFFF80000000000UL
+#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)
+
+/* The following structure is used to hold the physical
+ * memory configuration of the machine.  This is filled in
+ * probe_memory() and is later used by mem_init() to set up
+ * mem_map[].  We statically allocate SPARC_PHYS_BANKS of
+ * these structs, this is arbitrary.  The entry after the
+ * last valid one has num_bytes==0.
+ */
+
+struct sparc_phys_banks {
+  unsigned long base_addr;
+  unsigned long num_bytes;
+};
+
+#define SPARC_PHYS_BANKS 32
+
+extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
+
+#endif /* __KERNEL__ */
+
+#endif /* _SPARC64_PAGE_H */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/param.h linux/include/asm-sparc64/param.h
--- v2.1.15/linux/include/asm-sparc64/param.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/param.h	Fri Dec 13 11:37:47 1996
@@ -0,0 +1,21 @@
+/* $Id: param.h,v 1.1 1996/12/02 00:08:24 davem Exp $ */
+#ifndef _ASMSPARC64_PARAM_H
+#define _ASMSPARC64_PARAM_H
+
+#ifndef HZ
+#define HZ 100
+#endif
+
+#define EXEC_PAGESIZE	8192    /* Thanks for sun4's we carry baggage... */
+
+#ifndef NGROUPS
+#define NGROUPS		32
+#endif
+
+#ifndef NOGROUP
+#define NOGROUP		(-1)
+#endif
+
+#define MAXHOSTNAMELEN	64	/* max length of hostname */
+
+#endif /* _ASMSPARC64_PARAM_H */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/pconf.h linux/include/asm-sparc64/pconf.h
--- v2.1.15/linux/include/asm-sparc64/pconf.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/pconf.h	Fri Dec 13 11:37:47 1996
@@ -0,0 +1,25 @@
+/* $Id: pconf.h,v 1.1 1996/12/02 00:09:10 davem Exp $
+ * pconf.h: pathconf() and fpathconf() defines for SunOS
+ *          system call compatibility.
+ *
+ * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC64_PCONF_H
+#define _SPARC64_PCONF_H
+
+#include <linux/fs.h>
+#include <linux/limits.h>
+
+#define _PCONF_LINK       1 /* Max number of links to an object        */
+#define _PCONF_CANON      2 /* TTY input buffer line size              */
+#define _PCONF_INPUT      3 /* Biggest packet a tty can imbibe at once */
+#define _PCONF_NAME       4 /* Filename length max                     */
+#define _PCONF_PATH       5 /* Max size of a pathname                  */
+#define _PCONF_PIPE       6 /* Buffer size for a pipe                  */
+#define _PCONF_CHRESTRICT 7 /* Can only root chown files?              */
+#define _PCONF_NOTRUNC    8 /* Are pathnames truncated if too big?     */
+#define _PCONF_VDISABLE   9 /* Magic char to disable special tty chars */
+#define _PCONF_MAXPCONF   9
+
+#endif /* !(_SPARC64_PCONF_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.1.15/linux/include/asm-sparc64/pgtable.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/pgtable.h	Fri Dec 13 11:37:47 1996
@@ -0,0 +1,508 @@
+/* $Id: pgtable.h,v 1.1 1996/12/02 00:01:17 davem Exp $
+ * pgtable.h: SpitFire page table operations.
+ *
+ * Copyright 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC64_PGTABLE_H
+#define _SPARC64_PGTABLE_H
+
+/* This file contains the functions and defines necessary to modify and use
+ * the SpitFire page tables.
+ */
+
+#include <asm/asi.h>
+#include <asm/mmu_context.h>
+#include <asm/system.h>
+
+/* Certain architectures need to do special things when pte's
+ * 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	(PAGE_SHIFT + (PAGE_SHIFT-3))
+#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	(PAGE_SHIFT + 2*(PAGE_SHIFT-3))
+#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
+#define PGDIR_MASK	(~(PGDIR_SIZE-1))
+
+/* Entries per page directory level. */
+#define PTRS_PER_PTE	(1UL << (PAGE_SHIFT-3))
+#define PTRS_PER_PMD	(1UL << (PAGE_SHIFT-3))
+#define PTRS_PER_PGD	(1UL << (PAGE_SHIFT-3))
+
+/* the no. of pointers that fit on a page */
+#define PTRS_PER_PAGE	(1UL << (PAGE_SHIFT-3))
+
+#define VMALLOC_START		0xFFFFFE0000000000UL
+#define VMALLOC_VMADDR(x)	((unsigned long)(x))
+
+/* SpitFire TTE bits. */
+#define _PAGE_VALID	0x8000000000000000UL	/* Valid TTE                          */
+#define _PAGE_R		0x8000000000000000UL	/* Used to keep ref bit up to date    */
+#define _PAGE_SZ4MB	0x6000000000000000UL	/* 4MB Page                           */
+#define _PAGE_SZ512K	0x4000000000000000UL	/* 512K Page                          */
+#define _PAGE_SZ64K	0x2000000000000000UL	/* 64K Page                           */
+#define _PAGE_SZ8K	0x0000000000000000UL	/* 8K Page                            */
+#define _PAGE_NFO	0x1000000000000000UL	/* No Fault Only                      */
+#define _PAGE_IE	0x0800000000000000UL	/* Invert Endianness                  */
+#define _PAGE_SOFT2	0x07FC000000000000UL	/* Second set of software bits        */
+#define _PAGE_DIAG	0x0003FE0000000000UL	/* Diagnostic TTE bits                */
+#define _PAGE_PADDR	0x000001FFFFFFE000UL	/* Physical Address bits [40:13]      */
+#define _PAGE_SOFT	0x0000000000001F80UL	/* First set of software bits         */
+#define _PAGE_L		0x0000000000000040UL	/* Locked TTE                         */
+#define _PAGE_CP	0x0000000000000020UL	/* Cacheable in Physical Cache        */
+#define _PAGE_CV	0x0000000000000010UL	/* Cacheable in Virtual Cache         */
+#define _PAGE_E		0x0000000000000008UL    /* side-Effect                        */
+#define _PAGE_P		0x0000000000000004UL	/* Privileged Page                    */
+#define _PAGE_W		0x0000000000000002UL	/* Writable                           */
+#define _PAGE_G		0x0000000000000001UL	/* Global                             */
+
+/* Here are the SpitFire software bits we use in the TTE's. */
+#define _PAGE_PRESENT	0x0000000000001000UL	/* Present Page (ie. not swapped out) */
+#define _PAGE_MODIFIED	0x0000000000000800UL	/* Modified Page (ie. dirty)          */
+#define _PAGE_ACCESSED	0x0000000000000400UL	/* Accessed Page (ie. referenced)     */
+#define _PAGE_READ	0x0000000000000200UL	/* Readable SW Bit                    */
+#define _PAGE_WRITE	0x0000000000000100UL	/* Writable SW Bit                    */
+
+#define _PAGE_CACHE	(_PAGE_CP | _PAGE_CV)
+
+#define __DIRTY_BITS	(_PAGE_MODIFIED | _PAGE_WRITE | _PAGE_W)
+#define __ACCESS_BITS	(_PAGE_ACCESSED | _PAGE_READ | _PAGE_R)
+
+#define _PFN_MASK	_PAGE_PADDR
+
+#define _PAGE_TABLE	(_PAGE_PRESENT | __DIRTY_BITS | __ACCESS_BITS)
+#define _PAGE_CHG_MASK	(_PFN_MASK | _PAGE_MODIFIED | _PAGE_ACCESSED)
+
+#define PAGE_NONE	__pgprot(_PAGE_PRESENT | _PAGE_CACHE)
+#define PAGE_SHARED	__pgprot(_PAGE_PRESENT | __ACCESS_BITS | \
+				 _PAGE_WRITE | _PAGE_CACHE)
+#define PAGE_COPY	__pgprot(_PAGE_PRESENT | __ACCESS_BITS | _PAGE_CACHE)
+#define PAGE_READONLY	__pgprot(_PAGE_PRESENT | __ACCESS_BITS | _PAGE_CACHE)
+#define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | _PAGE_VALID | _PAGE_W| \
+				 _PAGE_CACHE | _PAGE_P | _PAGE_G)
+
+#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
+
+extern pte_t __bad_page(void);
+extern pmd_t *__bad_pagetable(void);
+extern unsigned long __zero_page(void);
+
+#define BAD_PAGETABLE	__bad_pagetable()
+#define BAD_PAGE	__bad_page()
+#define ZERO_PAGE	__zero_page()
+
+/* Cache and TLB flush operations. */
+
+extern __inline__ void spitfire_put_dcache_tag(unsigned long addr, unsigned long tag)
+{
+	__asm__ __volatile__("stxa	%0, [%1] %2"
+			     : /* No outputs */
+			     : "r" (tag), "r" (addr), "i" (ASI_DCACHE_TAG));
+}
+
+extern __inline__ void spitfire_put_icache_tag(unsigned long addr, unsigned long tag)
+{
+	__asm__ __volatile__("stxa	%0, [%1] %2"
+			     : /* No outputs */
+			     : "r" (tag), "r" (addr), "i" (ASI_IC_TAG));
+}
+
+/* This is a bit tricky to do most efficiently.  The I-CACHE on the
+ * SpitFire will snoop stores from _other_ processors and changes done
+ * by DMA, but it does _not_ snoop stores on the local processor.
+ * Also, even if the I-CACHE snoops the store from someone else correctly,
+ * you can still lose if the instructions are in the pipeline already.
+ * A big issue is that this cache is only 16K in size, using a pseudo
+ * 2-set associative scheme.  A full flush of the cache is far too much
+ * for me to accept, especially since most of the time when we get to
+ * running this code the icache data we want to flush is not even in
+ * the cache.  Thus the following seems to be the best method.
+ */
+extern __inline__ void spitfire_flush_icache_page(unsigned long page)
+{
+	unsigned long temp;
+
+	/* Commit all potential local stores to the instruction space
+	 * on this processor before the flush.
+	 */
+	membar("#StoreStore");
+
+	/* Actually perform the flush. */
+	__asm__ __volatile__("
+1:
+	flush		%0 + 0x00
+	flush		%0 + 0x08
+	flush		%0 + 0x10
+	flush		%0 + 0x18
+	flush		%0 + 0x20
+	flush		%0 + 0x28
+	flush		%0 + 0x30
+	flush		%0 + 0x38
+	subcc		%1, 0x40, %1
+	bge,pt		%icc, 1b
+	 add		%2, %1, %0
+"	: "=&r" (page), "=&r" (temp),
+	: "r" (page), "0" (page + PAGE_SIZE - 0x40), "1" (PAGE_SIZE - 0x40));
+}
+
+extern __inline__ void flush_cache_all(void)
+{
+	unsigned long addr;
+
+	flushw_all();
+	for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32) {
+		spitfire_put_dcache_tag(addr, 0x0UL);
+		spitfire_put_icache_tag(addr, 0x0UL);
+		membar("#Sync");
+	}
+}
+
+extern __inline__ void flush_cache_mm(struct mm_struct *mm)
+{
+	if(mm->context != NO_CONTEXT) {
+		unsigned long addr;
+
+		flushw_user();
+		for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32) {
+			spitfire_put_dcache_tag(addr, 0x0UL);
+			spitfire_put_icache_tag(addr, 0x0UL);
+			membar("#Sync");
+		}
+	}
+}
+
+extern __inline__ void flush_cache_range(struct mm_struct *mm, unsigned long start,
+					 unsigned long end)
+{
+	if(mm->context != NO_CONTEXT) {
+		unsigned long addr;
+
+		flushw_user();
+		for(addr = 0; addr < (PAGE_SIZE << 1); addr += 32) {
+			spitfire_put_icache_tag(addr, 0x0UL);
+			membar("#Sync");
+		}
+	}
+}
+
+extern __inline__ void flush_cache_page(struct vm_area_struct *vma, unsigned long page)
+{
+	struct mm_struct *mm = vma->vm_mm;
+
+	if(mm->context != NO_CONTEXT && (vma->vm_flags & VM_EXEC)) {
+		int ctx;
+
+		ctx = spitfire_get_primary_context();
+		flushw_user();
+		spitfire_set_primary_context(mm->context);
+		spitfire_flush_icache_page(page & PAGE_MASK);
+		spitfire_set_primary_context(ctx);
+	}
+}
+
+/* This operation in unnecessary on the SpitFire since D-CACHE is write-through. */
+#define flush_page_to_ram(page)		do { } while (0)
+
+extern __inline__ void flush_tlb_all(void)
+{
+	int entry;
+
+	/* Invalidate all non-locked TTE's in both the dtlb and itlb. */
+	for(entry = 0; entry < 64; entry++) {
+		unsigned long dtag, itag;
+
+		dtag = spitfire_get_dtlb_tag(entry);
+		itag = spitfire_get_itlb_tag(entry);
+		if(!(dtag & _PAGE_L))
+			spitfire_put_dtlb_tag(entry, 0x0UL);
+		if(!(itag & _PAGE_L))
+			spitfire_put_itlb_tag(entry, 0x0UL);
+	}
+}
+
+extern __inline__ void flush_tlb_mm(struct mm_struct *mm)
+{
+	if(mm->context != NO_CONTEXT) {
+		spitfire_set_secondary_context(mm->context);
+		spitfire_flush_dtlb_secondary_context();
+		spitfire_flush_itlb_secondary_context();
+	}
+}
+
+extern __inline__ void flush_tlb_range(struct mm_struct *mm, unsigned long start,
+				       unsigned long end)
+{
+	if(mm->context != NO_CONTEXT) {
+		start &= PAGE_MASK;
+		spitfire_set_secondary_context(mm->context);
+		while(start < end) {
+			spitfire_flush_dtlb_secondary_page(start);
+			spitfire_flush_itlb_secondary_page(start);
+			start += PAGE_SIZE;
+		}
+	}
+}
+
+extern __inline__ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+	struct mm_struct *mm = vma->vm_mm;
+
+	if(mm->context != NO_CONTEXT) {
+		spitfire_set_secondary_context(mm->context);
+		if(vma->vm_flags & VM_EXEC)
+			spitfire_flush_itlb_secondary_page(page);
+		spitfire_flush_dtlb_secondary_page(page);
+	}
+}
+
+extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
+{ return __pte((page - PAGE_OFFSET) | pgprot_val(pgprot)); }
+
+extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
+{ return __pte(physpage | pgprot_val(pgprot)); }
+
+extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
+
+extern inline void pmd_set(pmd_t *pmdp, pte_t *ptep)
+{ pmd_val(*pmdp) = _PAGE_TABLE | ((unsigned long) ptep); }
+
+extern inline void pgd_set(pgd_t *pgdp, pmd_t *pmdp)
+{ pgd_val(*pgdp) = _PAGE_TABLE | ((unsigned long) pmdp); }
+
+extern inline unsigned long pte_page(pte_t pte)
+{ return PAGE_OFFSET + (pte_val(pte) & _PFN_MASK); }
+
+extern inline unsigned long pmd_page(pmd_t pmd)
+{ return (pmd_val(pmd) & PAGE_MASK); }
+
+extern inline unsigned long pgd_page(pgd_t pgd)
+{ return (pgd_val(pgd) & PAGE_MASK); }
+
+extern inline int pte_none(pte_t pte) 		{ return !pte_val(pte); }
+extern inline int pte_present(pte_t pte)	{ return pte_val(pte) & _PAGE_PRESENT; }
+extern inline void pte_cleat(pte_t *pte)	{ pte_val(*pte) = 0; }
+
+extern inline int pmd_none(pmd_t pmd)		{ return !pmd_val(pmd); }
+extern inline int pmd_bad(pmd_t pmd)		{ return (pmd_val(pmd) & ~PAGE_MASK) != _PAGE_TABLE; }
+extern inline int pmd_present(pmd_t pmd)	{ return pmd_val(pmd) & _PAGE_PRESENT; }
+extern inline void pmd_clear(pmd_t *pmdp)	{ pmd_val(*pmdp) = 0; }
+
+extern inline int pgd_none(pgd_t pgd)		{ return !pgd_val(pgd); }
+extern inline int pgd_bad(pgd_t pgd)		{ return (pgd_val(pgd) & ~PAGE_MASK) != _PAGE_TABLE; }
+extern inline int pgd_present(pgd_t pgd)	{ return pgd_val(pgd) & _PAGE_PRESENT; }
+extern inline void pgd_clear(pgd_t *pgdp)	{ pgd_val(*pgdp) = 0; }
+
+/* The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+extern inline int pte_read(pte_t pte)		{ return pte_val(pte) & _PAGE_READ; }
+extern inline int pte_write(pte_t pte)		{ return pte_val(pte) & _PAGE_WRITE; }
+extern inline int pte_dirty(pte_t pte)		{ return pte_val(pte) & _PAGE_MODIFIED; }
+extern inline int pte_young(pte_t pte)		{ return pte_val(pte) & _PAGE_ACCESSED; }
+
+extern inline pte_t pte_wrprotect(pte_t pte)
+{ return __pte(pte_val(pte) & ~(_PAGE_WRITE|_PAGE_W)); }
+
+extern inline pte_t pte_rdprotect(pte_t pte)
+{ return __pte(pte_val(pte) & ~(_PAGE_READ|_PAGE_R)); }
+
+extern inline pte_t pte_mkclean(pte_t pte)
+{ return __pte(pte_val(pte) & ~(_PAGE_MODIFIED | _PAGE_W); }
+
+extern inline pte_t pte_mkold(pte_t pte)
+{ return __pte(pte_val(pte) & ~(_PAGE_ACCESSED | _PAGE_R)); }
+
+extern inline pte_t pte_mkwrite(pte_t pte)
+{
+	if(pte_val(pte) & _PAGE_MODIFIED)
+		return __pte(pte_val(pte) | (_PAGE_WRITE | _PAGE_W));
+	else
+		return __pte(pte_val(pte) | (_PAGE_WRITE));
+}
+
+extern inline pte_t pte_mkdirty(pte_t pte)
+{
+	if(pte_val(pte) & _PAGE_WRITE)
+		return __pte(pte_val(pte) | (_PAGE_MODIFIED | _PAGE_W));
+	else
+		return __pte(pte_val(pte) | _PAGE_MODIFIED);
+}
+
+extern inline pte_t pte_mkyoung(pte_t pte)
+{
+	if(pte_val(pte) & _PAGE_READ)
+		return __pte(pte_val(pte) | (_PAGE_ACCESSED | _PAGE_R));
+	else
+		return __pte(pte_val(pte) | _PAGE_ACCESSED);
+}
+
+extern inline void SET_PAGE_DIR(struct task_struct *tsk, pgd_t *pgdir)
+{ /* XXX */ }
+
+/* to find an entry in a page-table-directory. */
+extern inline pgd_t *pgd_offset(struct mm_struct *mm, unsigned long address)
+{ return mm->pgd + ((address >> PGDIR_SHIFT) & (PTRS_PER_PAGE - 1)); }
+
+/* Find an entry in the second-level page table.. */
+extern inline pmd_t *pmd_offset(pgd_t *dir, unsigned long address)
+{ return (pmd_t *) pgd_page(*dir) + ((address >> PMD_SHIFT) & (PTRS_PER_PAGE - 1)); }
+
+/* Find an entry in the third-level page table.. */
+extern inline pte_t *pte_offset(pmd_t *dir, unsigned long address)
+{ return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PAGE - 1)); }
+
+/* Allocate and free page tables. The xxx_kernel() versions are
+ * used to allocate a kernel page table - this turns on supervisor
+ * bits if any.
+ */
+extern inline void pte_free_kernel(pte_t *pte)
+{ free_page((unsigned long)pte); }
+
+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_free_page(GFP_KERNEL);
+		if (pmd_none(*pmd)) {
+			if (page) {
+				pmd_set(pmd, page);
+				return page + address;
+			}
+			pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+			return NULL;
+		}
+		free_page((unsigned long) page);
+	}
+	if (pmd_bad(*pmd)) {
+		printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
+		pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + address;
+}
+
+extern inline void pmd_free_kernel(pmd_t *pmd)
+{ free_page((unsigned long) pmd); }
+
+extern inline pmd_t * pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
+{
+	address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
+	if (pgd_none(*pgd)) {
+		pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
+		if (pgd_none(*pgd)) {
+			if (page) {
+				pgd_set(pgd, page);
+				return page + address;
+			}
+			pgd_set(pgd, BAD_PAGETABLE);
+			return NULL;
+		}
+		free_page((unsigned long) page);
+	}
+	if (pgd_bad(*pgd)) {
+		printk("Bad pgd in pmd_alloc_kernel: %08lx\n", pgd_val(*pgd));
+		pgd_set(pgd, BAD_PAGETABLE);
+		return NULL;
+	}
+	return (pmd_t *) pgd_page(*pgd) + address;
+}
+
+extern inline void pte_free(pte_t * pte)
+{ free_page((unsigned long)pte); }
+
+extern inline pte_t * pte_alloc(pmd_t *pmd, unsigned long address)
+{
+	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+	if (pmd_none(*pmd)) {
+		pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
+		if (pmd_none(*pmd)) {
+			if (page) {
+				pmd_set(pmd, page);
+				return page + address;
+			}
+			pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+			return NULL;
+		}
+		free_page((unsigned long) page);
+	}
+	if (pmd_bad(*pmd)) {
+		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+		pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + address;
+}
+
+extern inline void pmd_free(pmd_t * pmd)
+{ free_page((unsigned long) pmd); }
+
+extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
+{
+	address = (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
+	if (pgd_none(*pgd)) {
+		pmd_t *page = (pmd_t *) get_free_page(GFP_KERNEL);
+		if (pgd_none(*pgd)) {
+			if (page) {
+				pgd_set(pgd, page);
+				return page + address;
+			}
+			pgd_set(pgd, BAD_PAGETABLE);
+			return NULL;
+		}
+		free_page((unsigned long) page);
+	}
+	if (pgd_bad(*pgd)) {
+		printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
+		pgd_set(pgd, BAD_PAGETABLE);
+		return NULL;
+	}
+	return (pmd_t *) pgd_page(*pgd) + address;
+}
+
+extern inline void pgd_free(pgd_t * pgd)
+{ free_page((unsigned long)pgd); }
+
+extern inline pgd_t * pgd_alloc(void)
+{ return (pgd_t *) get_free_page(GFP_KERNEL); }
+
+#define pgd_flush(pgd)	do { } while (0)
+
+extern pgd_t swapper_pg_dir[1024];	/* XXX */
+
+extern inline void update_mmu_cache(struct vm_area_struct * vma,
+	unsigned long address, pte_t pte)
+{ /* XXX */ }
+
+/* Make a non-present pseudo-TTE. */
+extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
+{ pte_t pte; pte_val(pte) = (type) | (offset << 8); return pte; }
+
+#define SWP_TYPE(entry)		(((entry) & 0xff))
+#define SWP_OFFSET(entry)	((entry) >> 8)
+#define SWP_ENTRY(type,offset)	pte_val(mk_swap_pte((type),(offset)))
+
+#endif /* _SPARC64_PGTABLE_H */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/pstate.h linux/include/asm-sparc64/pstate.h
--- v2.1.15/linux/include/asm-sparc64/pstate.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/pstate.h	Fri Dec 13 11:37:47 1996
@@ -0,0 +1,79 @@
+/* $Id: pstate.h,v 1.1 1996/12/12 11:57:14 davem Exp $ */
+#ifndef _SPARC64_PSTATE_H
+#define _SPARC64_PSTATE_H
+
+/* The V9 PSTATE Register (with SpitFire extensions).
+ *
+ * -----------------------------------------------------------------------
+ * | Resv | IG | MG | CLE | TLE |  MM  | RED | PEF | AM | PRIV | IE | AG |
+ * -----------------------------------------------------------------------
+ *  63  12  11   10    9     8    7   6   5     4     3     2     1    0
+ */
+#define PSTATE_IG	0x0000000000000800	/* Interrupt Globals.		*/
+#define PSTATE_MG	0x0000000000000400	/* MMU Globals.			*/
+#define PSTATE_CLE	0x0000000000000200	/* Current Little Endian.	*/
+#define PSTATE_TLE	0x0000000000000100	/* Trap Little Endian.		*/
+#define PSTATE_MM	0x00000000000000c0	/* Memory Model.		*/
+#define PSTATE_RED	0x0000000000000020	/* Reset Error Debug State.	*/
+#define PSTATE_PEF	0x0000000000000010	/* Floating Point Enable.	*/
+#define PSTATE_AM	0x0000000000000008	/* Address Mask.		*/
+#define PSTATE_PRIV	0x0000000000000004	/* Privilege.			*/
+#define PSTATE_IE	0x0000000000000002	/* Interrupt Enable.		*/
+#define PSTATE_AG	0x0000000000000001	/* Alternate Globals.		*/
+
+/* The V9 TSTATE Register (with SpitFire extensions).
+ *
+ * ---------------------------------------------------------------
+ * |  Resv  |  CCR  |  ASI  |  Resv  |  PSTATE  |  Resv  |  CWP  |
+ * ---------------------------------------------------------------
+ *  63    40 39   32 31   24 23    20 19       8 7      5 4     0
+ */
+#define TSTATE_CCR	0x000000ff00000000	/* Condition Codes.		*/
+#define TSTATE_XNEG	0x0000008000000000	/* %xcc Negative.		*/
+#define TSTATE_XZERO	0x0000004000000000	/* %xcc Zero.			*/
+#define TSTATE_XOVFL	0x0000002000000000	/* %xcc Overflow.		*/
+#define TSTATE_XCARRY	0x0000001000000000	/* %xcc Carry.			*/
+#define TSTATE_INEG	0x0000000800000000	/* %icc Negative.		*/
+#define TSTATE_IZERO	0x0000000400000000	/* %icc Zero.			*/
+#define TSTATE_IOVFL	0x0000000200000000	/* %icc Overflow.		*/
+#define TSTATE_ICARRY	0x0000000100000000	/* %icc Carry.			*/
+#define TSTATE_ASI	0x00000000ff000000	/* Address Space Identifier.	*/
+#define TSTATE_PSTATE	0x00000000000fff00	/* PSTATE.			*/
+#define TSTATE_IG	0x0000000000080000	/* Interrupt Globals.		*/
+#define TSTATE_MG	0x0000000000040000	/* MMU Globals.			*/
+#define TSTATE_CLE	0x0000000000020000	/* Current Little Endian.	*/
+#define TSTATE_TLE	0x0000000000010000	/* Trap Little Endian.		*/
+#define TSTATE_MM	0x000000000000c000	/* Memory Model.		*/
+#define TSTATE_RED	0x0000000000002000	/* Reset Error Debug State.	*/
+#define TSTATE_PEF	0x0000000000001000	/* Floating Point Enable.	*/
+#define TSTATE_AM	0x0000000000000800	/* Address Mask.		*/
+#define TSTATE_PRIV	0x0000000000000400	/* Privilege.			*/
+#define TSTATE_IE	0x0000000000000200	/* Interrupt Enable.		*/
+#define TSTATE_AG	0x0000000000000100	/* Alternate Globals.		*/
+#define TSTATE_CWP	0x000000000000001f	/* Current Window Pointer.	*/
+
+/* Floating-Point Registers State Register.
+ *
+ * --------------------------------
+ * |  Resv  |  FEF  |  DU  |  DL  |
+ * --------------------------------
+ *  63     3    2       1      0
+ */
+#define FPRS_FEF	0x0000000000000004	/* Enable Floating Point.	*/
+#define FPRS_DU		0x0000000000000002	/* Dirty Upper.			*/
+#define FPRS_DL		0x0000000000000001	/* Dirty Lower.			*/
+
+/* Version Register.
+ *
+ * ------------------------------------------------------
+ * | MANUF | IMPL | MASK | Resv | MAXTL | Resv | MAXWIN |
+ * ------------------------------------------------------
+ *  63   48 47  32 31  24 23  16 15    8 7    5 4      0
+ */
+#define VERS_MANUF	0xffff000000000000	/* Manufacturer.		*/
+#define VERS_IMPL	0x0000ffff00000000	/* Implementation.		*/
+#define VERS_MASK	0x00000000ff000000	/* Mask Set Revision.		*/
+#define VERS_MAXTL	0x000000000000ff00	/* Maximum Trap Level.		*/
+#define VERS_MAXWIN	0x000000000000001f	/* Maximum Reg Window Index.	*/
+
+#endif /* !(_SPARC64_PSTATE_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/ptrace.h linux/include/asm-sparc64/ptrace.h
--- v2.1.15/linux/include/asm-sparc64/ptrace.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/ptrace.h	Fri Dec 13 11:37:47 1996
@@ -0,0 +1,89 @@
+/* $Id: ptrace.h,v 1.1 1996/12/12 11:59:35 davem Exp $ */
+#ifndef _SPARC64_PTRACE_H
+#define _SPARC64_PTRACE_H
+
+#include <asm/pstate.h>
+
+/* This struct defines the way the registers are stored on the 
+ * stack during a system call and basically all traps.
+ */
+
+#ifndef __ASSEMBLY__
+
+struct pt_regs {
+	unsigned long u_regs[16]; /* globals and ins */
+	unsigned long tstate;
+	unsigned long tpc;
+	unsigned long tnpc;
+	unsigned long y;
+};
+
+#define UREG_G0        0
+#define UREG_G1        1
+#define UREG_G2        2
+#define UREG_G3        3
+#define UREG_G4        4
+#define UREG_G5        5
+#define UREG_G6        6
+#define UREG_G7        7
+#define UREG_I0        8
+#define UREG_I1        9
+#define UREG_I2        10
+#define UREG_I3        11
+#define UREG_I4        12
+#define UREG_I5        13
+#define UREG_I6        14
+#define UREG_I7        15
+#define UREG_FP        UREG_I6
+#define UREG_RETPC     UREG_I7
+
+/* A V9 register window */
+struct reg_window {
+	unsigned long locals[8];
+	unsigned long ins[8];
+};
+
+/* A 32-bit register window. */
+struct reg_window_32 {
+	unsigned int locals[8];
+	unsigned int ins[8];
+};
+
+/* A V9 Sparc stack frame */
+struct sparc_stackf {
+	unsigned long locals[8];
+        unsigned long ins[6];
+	struct sparc_stackf *fp;
+	unsigned long callers_pc;
+	char *structptr;
+	unsigned long xargs[6];
+	unsigned long xxargs[1];
+};	
+
+/* A 32-bit Sparc stack frame */
+struct sparc_stackf_32 {
+	unsigned int locals[8];
+        unsigned int ins[6];
+	unsigned int fp;
+	unsigned int callers_pc;
+	unsigned int structptr;
+	unsigned int xargs[6];
+	unsigned int xxargs[1];
+};	
+
+#define TRACEREG_SZ   sizeof(struct pt_regs)
+#define STACKFRAME_SZ sizeof(struct sparc_stackf)
+#define REGWIN_SZ     sizeof(struct reg_window)
+
+#ifdef __KERNEL__
+#define user_mode(regs) (!((regs)->tstate & PSR_PS))
+#define instruction_pointer(regs) ((regs)->tpc)
+extern void show_regs(struct pt_regs *);
+#endif
+
+#else /* __ASSEMBLY__ */
+/* For assembly code. */
+#define TRACEREG_SZ       0x50
+#define STACKFRAME_SZ     0x60
+#define REGWIN_SZ         0x40
+#endif
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/semaphore.h linux/include/asm-sparc64/semaphore.h
--- v2.1.15/linux/include/asm-sparc64/semaphore.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/semaphore.h	Fri Dec 13 11:37:47 1996
@@ -0,0 +1,35 @@
+#ifndef _SPARC64_SEMAPHORE_H
+#define _SPARC64_SEMAPHORE_H
+
+/* These are actually reasonable on the V9. */
+
+#include <asm/atomic.h>
+
+struct semaphore {
+	atomic_t count;
+	atomic_t waiting;
+	struct wait_queue * wait;
+};
+
+#define MUTEX ((struct semaphore) { 1, 0, NULL })
+#define MUTEX_LOCKED ((struct semaphore) { 0, 0, NULL })
+
+extern void __down(struct semaphore * sem);
+extern void __up(struct semaphore * sem);
+
+extern __inline__ void down(struct semaphore * sem)
+{
+	for (;;) {
+		if (atomic_dec_return(&sem->count) >= 0)
+			break;
+		__down(sem);
+	}
+}
+
+extern __inline__ void up(struct semaphore * sem)
+{
+	if (atomic_inc_return(&sem->count) <= 0)
+		__up(sem);
+}	
+
+#endif /* !(_SPARC64_SEMAPHORE_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h
--- v2.1.15/linux/include/asm-sparc64/system.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/system.h	Fri Dec 13 11:37:47 1996
@@ -0,0 +1,90 @@
+/* $Id: system.h,v 1.2 1996/12/02 00:01:07 davem Exp $ */
+#ifndef __SPARC64_SYSTEM_H
+#define __SPARC64_SYSTEM_H
+
+#define setipl(__new_ipl) \
+	__asm__ __volatile__("wrpr	%0, %%pil"  : : "r" (__new_ipl) : "memory")
+
+#define cli() \
+	__asm__ __volatile__("wrpr	15, %%pil" : : : "memory")
+
+#define sti() \
+	__asm__ __volatile__("wrpr	0, %%pil" : : : "memory")
+
+#define getipl() \
+({ int retval; __asm__ __volatile__("rdpr	%%pil, %0" : "=r" (retval)); retval; })
+
+#define swap_pil(__new_pil) \
+({	int retval; \
+	__asm__ __volatile__("rdpr	%%pil, %0\n\t" \
+			     "wrpr	%1, %%pil" \
+			     : "=r" (retval) \
+			     : "r" (__new_pil) \
+			     : "memory"); \
+	retval; \
+})
+
+#define read_pil_and_cli() \
+({	int retval; \
+	__asm__ __volatile__("rdpr	%%pil, %0\n\t" \
+			     "wrpr	15, %%pil" \
+			     : "=r" (retval) \
+			     : : "memory"); \
+	retval; \
+})
+
+#define save_flags(flags)	((flags) = getipl())
+#define save_and_cli(flags)	((flags) = read_pil_and_cli())
+#define restore_flags(flags)	setipl((flags))
+
+#define mb()  		__asm__ __volatile__ ("stbar" : : : "memory")
+
+#define nop() 		__asm__ __volatile__ ("nop")
+
+#define membar(type)	__asm__ __volatile__ ("membar " type : : : "memory");
+
+/* Unlike the hybrid v7/v8 kernel, we can assume swap exists under V9. */
+extern __inline__ unsigned long xchg_u32(__volatile__ unsigned int *m, unsigned int val)
+{
+	__asm__ __volatile__("swap	[%1], %0"
+			     : "=&r" (val)
+			     : "r" (m), "0" (val));
+	return val;
+}
+
+/* Bolix, must use casx for 64-bit values. */
+extern __inline__ unsigned long xchg_u64(__volatile__ unsigned long *m,
+					 unsigned long val)
+{
+	unsigned long temp;
+	__asm__ __volatile__("
+	ldx		[%2], %1
+1:
+	casx		[%2], %1, %0
+	cmp		%1, %0
+	bne,a,pn	%%xcc, 1b
+	 ldx		[%2], %1
+"	: "=&r" (val), "=&r" (temp)
+	: "r" (m), "0" (val));
+	return val;
+}
+
+#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+#define tas(ptr) (xchg((ptr),1))
+
+extern void __xchg_called_with_bad_pointer(void);
+
+static __inline__ unsigned long __xchg(unsigned long x, __volatile__ void * ptr,
+				       int size)
+{
+	switch (size) {
+	case 4:
+		return xchg_u32(ptr, x);
+	case 8:
+		return xchg_u64(ptr, x);
+	};
+	__xchg_called_with_bad_pointer();
+	return x;
+}
+
+#endif /* !(__SPARC64_SYSTEM_H) */
diff -u --recursive --new-file v2.1.15/linux/include/asm-sparc64/types.h linux/include/asm-sparc64/types.h
--- v2.1.15/linux/include/asm-sparc64/types.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-sparc64/types.h	Fri Dec 13 11:37:47 1996
@@ -0,0 +1,48 @@
+/* $Id: types.h,v 1.1 1996/11/20 12:03:51 davem Exp $ */
+#ifndef _SPARC64_TYPES_H
+#define _SPARC64_TYPES_H
+
+/*
+ * This file is never included by application software unless
+ * explicitly requested (e.g., via linux/types.h) in which case the
+ * application is Linux specific so (user-) name space pollution is
+ * not a major issue.  However, for interoperability, libraries still
+ * need to be careful to avoid a name clashes.
+ */
+
+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;
+
+typedef __signed__ long __s64;
+typedef unsigned long __u64;
+
+#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 s64;
+typedef unsigned long u64;
+
+#endif /* __KERNEL__ */
+
+#endif /* defined(_SPARC64_TYPES_H) */
diff -u --recursive --new-file v2.1.15/linux/include/linux/baycom.h linux/include/linux/baycom.h
--- v2.1.15/linux/include/linux/baycom.h	Fri Nov  1 17:13:19 1996
+++ linux/include/linux/baycom.h	Wed Dec 18 12:29:11 1996
@@ -21,15 +21,9 @@
 	long debug3;
 };
 
-struct baycom_modem_type {
-	unsigned char modem_type;
-	unsigned int options;
-};
-
 struct baycom_ioctl {
 	int cmd;
 	union {
-		struct baycom_modem_type mt;
 		struct baycom_debug_data dbg;
 	} data;
 };
@@ -37,22 +31,8 @@
 /* -------------------------------------------------------------------- */
 
 /*
- * modem types
- */
-#define BAYCOM_MODEM_INVALID 0
-#define BAYCOM_MODEM_SER12   1
-#define BAYCOM_MODEM_PAR96   2
-
-/*
- * modem options; bit mask
- */
-#define BAYCOM_OPTIONS_SOFTDCD  1
-
-/*
- * ioctl values change for baycom_net
+ * ioctl values change for baycom
  */
-#define BAYCOMCTL_GETMODEMTYPE   0x90
-#define BAYCOMCTL_SETMODEMTYPE   0x91
 #define BAYCOMCTL_GETDEBUG       0x92
 
 /* -------------------------------------------------------------------- */
diff -u --recursive --new-file v2.1.15/linux/include/linux/elf.h linux/include/linux/elf.h
--- v2.1.15/linux/include/linux/elf.h	Wed Aug  7 10:08:46 1996
+++ linux/include/linux/elf.h	Fri Dec 13 15:57:36 1996
@@ -152,6 +152,62 @@
 #define R_386_GOTPC	10
 #define R_386_NUM	11
 
+/*
+ * Sparc ELF relocation types
+ */
+#define	R_SPARC_NONE		0
+#define	R_SPARC_8		1
+#define	R_SPARC_16		2
+#define	R_SPARC_32		3
+#define	R_SPARC_DISP8		4
+#define	R_SPARC_DISP16		5
+#define	R_SPARC_DISP32		6
+#define	R_SPARC_WDISP30		7
+#define	R_SPARC_WDISP22		8
+#define	R_SPARC_HI22		9
+#define	R_SPARC_22		10
+#define	R_SPARC_13		11
+#define	R_SPARC_LO10		12
+#define	R_SPARC_GOT10		13
+#define	R_SPARC_GOT13		14
+#define	R_SPARC_GOT22		15
+#define	R_SPARC_PC10		16
+#define	R_SPARC_PC22		17
+#define	R_SPARC_WPLT30		18
+#define	R_SPARC_COPY		19
+#define	R_SPARC_GLOB_DAT	20
+#define	R_SPARC_JMP_SLOT	21
+#define	R_SPARC_RELATIVE	22
+#define	R_SPARC_UA32		23
+#define	R_SPARC_NUM		24
+
+/*
+ * 68k ELF relocation types
+ */
+#define R_68K_NONE	0
+#define R_68K_32	1
+#define R_68K_16	2
+#define R_68K_8		3
+#define R_68K_PC32	4
+#define R_68K_PC16	5
+#define R_68K_PC8	6
+#define R_68K_GOT32	7
+#define R_68K_GOT16	8
+#define R_68K_GOT8	9
+#define R_68K_GOT32O	10
+#define R_68K_GOT16O	11
+#define R_68K_GOT8O	12
+#define R_68K_PLT32	13
+#define R_68K_PLT16	14
+#define R_68K_PLT8	15
+#define R_68K_PLT32O	16
+#define R_68K_PLT16O	17
+#define R_68K_PLT8O	18
+#define R_68K_COPY	19
+#define R_68K_GLOB_DAT	20
+#define R_68K_JMP_SLOT	21
+#define R_68K_RELATIVE	22
+
 typedef struct elf32_rel {
   Elf32_Addr	r_offset;
   Elf32_Word	r_info;
diff -u --recursive --new-file v2.1.15/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.1.15/linux/include/linux/fs.h	Fri Nov 15 23:49:10 1996
+++ linux/include/linux/fs.h	Wed Dec 18 12:45:12 1996
@@ -73,6 +73,7 @@
 #define S_WRITE		128	/* Write on file/directory/symlink */
 #define S_APPEND	256	/* Append-only file */
 #define S_IMMUTABLE	512	/* Immutable file */
+#define MS_NOATIME	1024	/* Do not update access times. */
 
 /*
  * Flags that can be altered by MS_REMOUNT
@@ -94,6 +95,7 @@
  * Exception: MS_RDONLY is always applied to the entire file system.
  */
 #define IS_RDONLY(inode) (((inode)->i_sb) && ((inode)->i_sb->s_flags & MS_RDONLY))
+#define DO_UPDATE_ATIME(inode) (!((inode)->i_flags & MS_NOATIME) && !IS_RDONLY(inode))
 #define IS_NOSUID(inode) ((inode)->i_flags & MS_NOSUID)
 #define IS_NODEV(inode) ((inode)->i_flags & MS_NODEV)
 #define IS_NOEXEC(inode) ((inode)->i_flags & MS_NOEXEC)
diff -u --recursive --new-file v2.1.15/linux/include/linux/hdlcdrv.h linux/include/linux/hdlcdrv.h
--- v2.1.15/linux/include/linux/hdlcdrv.h	Fri Nov  1 17:13:19 1996
+++ linux/include/linux/hdlcdrv.h	Wed Dec 18 12:34:31 1996
@@ -20,6 +20,7 @@
 	int iobase;
 	int irq;
 	int dma;
+	int dma2;
 	int seriobase;
 	int pariobase;
 	int midiiobase;
@@ -49,6 +50,8 @@
 		struct hdlcdrv_channel_state cs;
 		unsigned int calibrate;
 		unsigned char bits;
+		char modename[128];
+		char drivername[32];
 	} data;
 };
 
@@ -57,18 +60,38 @@
 /*
  * ioctl values
  */
-#define HDLCDRVCTL_GETMODEMPAR      0
-#define HDLCDRVCTL_SETMODEMPAR      1
-#define HDLCDRVCTL_GETCHANNELPAR    2
-#define HDLCDRVCTL_SETCHANNELPAR    3
-#define HDLCDRVCTL_GETSTAT          4
-#define HDLCDRVCTL_CALIBRATE        5
+#define HDLCDRVCTL_GETMODEMPAR       0
+#define HDLCDRVCTL_SETMODEMPAR       1
+#define HDLCDRVCTL_MODEMPARMASK      2  /* not handled by hdlcdrv */
+#define HDLCDRVCTL_GETCHANNELPAR    10
+#define HDLCDRVCTL_SETCHANNELPAR    11
+#define HDLCDRVCTL_GETSTAT          20
+#define HDLCDRVCTL_CALIBRATE        21
 
 /*
  * these are mainly for debugging purposes
  */
-#define HDLCDRVCTL_GETSAMPLES       10
-#define HDLCDRVCTL_GETBITS          11
+#define HDLCDRVCTL_GETSAMPLES       30
+#define HDLCDRVCTL_GETBITS          31
+
+/*
+ * not handled by hdlcdrv, but by its depending drivers
+ */
+#define HDLCDRVCTL_GETMODE          40
+#define HDLCDRVCTL_SETMODE          41
+#define HDLCDRVCTL_MODELIST         42
+#define HDLCDRVCTL_DRIVERNAME       43
+
+/*
+ * mask of needed modem parameters, returned by HDLCDRVCTL_MODEMPARMASK
+ */
+#define HDLCDRV_PARMASK_IOBASE      (1<<0)
+#define HDLCDRV_PARMASK_IRQ         (1<<1)
+#define HDLCDRV_PARMASK_DMA         (1<<2)
+#define HDLCDRV_PARMASK_DMA2        (1<<3)
+#define HDLCDRV_PARMASK_SERIOBASE   (1<<4)
+#define HDLCDRV_PARMASK_PARIOBASE   (1<<5)
+#define HDLCDRV_PARMASK_MIDIIOBASE  (1<<6)
 
 /* -------------------------------------------------------------------- */
 
@@ -79,7 +102,7 @@
 #define HDLCDRV_HDLCBUFFER  16 /* should be a power of 2 for speed reasons */
 #define HDLCDRV_BITBUFFER  256 /* should be a power of 2 for speed reasons */
 #undef HDLCDRV_LOOPBACK  /* define for HDLC debugging purposes */
-#undef HDLCDRV_DEBUG
+#define HDLCDRV_DEBUG
 
 /* maximum packet length, excluding CRC */
 #define HDLCDRV_MAXFLEN             400	
@@ -133,13 +156,15 @@
 	/*
 	 * first some informations needed by the hdlcdrv routines
 	 */
-	int bitrate;
+	const char *drvname;
+	const char *drvinfo;
 	/*
 	 * the routines called by the hdlcdrv routines
 	 */
 	int (*open)(struct device *);
 	int (*close)(struct device *);
-	int (*ioctl)(struct device *, struct ifreq *, int);
+	int (*ioctl)(struct device *, struct ifreq *, 
+		     struct hdlcdrv_ioctl *, int);
 };
 
 struct hdlcdrv_state {
@@ -149,7 +174,12 @@
 
 	const struct hdlcdrv_ops *ops;
 
+	struct {
+		int bitrate;
+	} par;
+
 	struct hdlcdrv_pttoutput {
+		int dma2;
 		int seriobase;
 		int pariobase;
 		int midiiobase;
@@ -262,12 +292,12 @@
 
 /* -------------------------------------------------------------------- */
 
-extern void hdlcdrv_putbits(struct hdlcdrv_state *s, unsigned int bits)
+extern inline void hdlcdrv_putbits(struct hdlcdrv_state *s, unsigned int bits)
 {
 	hdlcdrv_hbuf_put(&s->hdlcrx.hbuf, bits);
 }
 
-extern unsigned int hdlcdrv_getbits(struct hdlcdrv_state *s)
+extern inline unsigned int hdlcdrv_getbits(struct hdlcdrv_state *s)
 {
 	unsigned int ret;
 
@@ -285,19 +315,19 @@
 	return ret;
 }
 
-extern void hdlcdrv_channelbit(struct hdlcdrv_state *s, unsigned int bit)
+extern inline void hdlcdrv_channelbit(struct hdlcdrv_state *s, unsigned int bit)
 {
 #ifdef HDLCDRV_DEBUG
 	hdlcdrv_add_bitbuffer(&s->bitbuf_channel, bit);
 #endif /* HDLCDRV_DEBUG */
 }
 
-extern void hdlcdrv_setdcd(struct hdlcdrv_state *s, int dcd)
+extern inline void hdlcdrv_setdcd(struct hdlcdrv_state *s, int dcd)
 {
 	s->hdlcrx.dcd = !!dcd;
 }
 
-extern int hdlcdrv_ptt(struct hdlcdrv_state *s)
+extern inline int hdlcdrv_ptt(struct hdlcdrv_state *s)
 {
 	return s->hdlctx.ptt || (s->hdlctx.calibrate > 0);
 }
diff -u --recursive --new-file v2.1.15/linux/include/linux/icmp.h linux/include/linux/icmp.h
--- v2.1.15/linux/include/linux/icmp.h	Thu Dec 12 19:37:18 1996
+++ linux/include/linux/icmp.h	Wed Dec 18 12:07:55 1996
@@ -30,6 +30,7 @@
 #define ICMP_INFO_REPLY		16	/* Information Reply		*/
 #define ICMP_ADDRESS		17	/* Address Mask Request		*/
 #define ICMP_ADDRESSREPLY	18	/* Address Mask Reply		*/
+#define NR_ICMP_TYPES		18
 
 
 /* Codes for UNREACH. */
@@ -49,7 +50,7 @@
 #define ICMP_PKT_FILTERED	13	/* Packet filtered */
 #define ICMP_PREC_VIOLATION	14	/* Precedence violation */
 #define ICMP_PREC_CUTOFF	15	/* Precedence cut off */
-#define NR_ICMP_UNREACH	15	  /* instead of hardcoding immediate value */
+#define NR_ICMP_UNREACH		15	/* instead of hardcoding immediate value */
 
 /* Codes for REDIRECT. */
 #define ICMP_REDIR_NET		0	/* Redirect Net			*/
diff -u --recursive --new-file v2.1.15/linux/include/linux/if_pppvar.h linux/include/linux/if_pppvar.h
--- v2.1.15/linux/include/linux/if_pppvar.h	Tue Mar  5 10:01:27 1996
+++ linux/include/linux/if_pppvar.h	Wed Dec 18 12:34:31 1996
@@ -1,4 +1,4 @@
-/*	$Id: if_pppvar.h,v 1.2 1995/06/12 11:36:51 paulus Exp $	*/
+/*	$Id: if_pppvar.h,v 1.3 1996/09/01 07:45:23 davem Exp $	*/
 /*
  * if_pppvar.h - private structures and declarations for PPP.
  *
@@ -93,7 +93,7 @@
 	__s32		magic;		/* magic value for structure	*/
 
 	/* Bitmapped flag fields. */
-	__u8		inuse;		/* are we allocated?		*/
+	__u32		inuse;		/* are we allocated?		*/
 	__u8		escape;		/* 0x20 if prev char was PPP_ESC*/
 	__u8		toss;		/* toss this frame		*/
 
diff -u --recursive --new-file v2.1.15/linux/include/linux/miscdevice.h linux/include/linux/miscdevice.h
--- v2.1.15/linux/include/linux/miscdevice.h	Fri Apr 26 10:30:52 1996
+++ linux/include/linux/miscdevice.h	Fri Dec 13 11:37:47 1996
@@ -8,6 +8,8 @@
 #define AMIGAMOUSE_MINOR 4
 #define ATARIMOUSE_MINOR 5
 #define SUN_MOUSE_MINOR 6
+#define RTC_MINOR 135
+#define SUN_OPENPROM_MINOR 139
 #define MISC_DYNAMIC_MINOR 255
 
 extern int misc_init(void);
diff -u --recursive --new-file v2.1.15/linux/include/linux/ncp_mount.h linux/include/linux/ncp_mount.h
--- v2.1.15/linux/include/linux/ncp_mount.h	Sun Aug  4 15:14:16 1996
+++ linux/include/linux/ncp_mount.h	Mon Dec 16 14:36:16 1996
@@ -22,6 +22,9 @@
 #define NCP_MOUNT_SOFT 0x0001
 #define NCP_MOUNT_INTR 0x0002
 
+/* Gosh... */
+#define NCP_PATH_MAX 1024
+
 struct ncp_mount_data {
 	int version;
 	unsigned int ncp_fd;	/* The socket to the ncp port */
@@ -32,7 +35,7 @@
 	struct sockaddr_ipx serv_addr;
 	unsigned char server_name[NCP_BINDERY_NAME_LEN];
 
-	unsigned char mount_point[PATH_MAX+1];
+	unsigned char mount_point[NCP_PATH_MAX+1];
 	unsigned char mounted_vol[NCP_VOLNAME_LEN+1];
 
 	unsigned int time_out;	/* How long should I wait after
diff -u --recursive --new-file v2.1.15/linux/include/linux/netdevice.h linux/include/linux/netdevice.h
--- v2.1.15/linux/include/linux/netdevice.h	Thu Dec 12 19:37:19 1996
+++ linux/include/linux/netdevice.h	Wed Dec 18 12:47:21 1996
@@ -296,7 +296,10 @@
 
 /*
  *	This almost never occurs, isn't in performance critical paths
- *	and we can thus be relaxed about it
+ *	and we can thus be relaxed about it. 
+ *
+ *	FIXME: What if this is being run as a real time process ??
+ *		Linus: We need a way to force a yield here ?
  */
  
 extern __inline__ void dev_lock_wait(void)
@@ -347,6 +350,8 @@
 extern void 		dev_mc_delete(struct device *dev, void *addr, int alen, int all);
 extern void		dev_mc_add(struct device *dev, void *addr, int alen, int newonly);
 extern void		dev_mc_discard(struct device *dev);
+/* Load a device via the kerneld */
+extern void		dev_load(const char *name);
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.1.15/linux/include/linux/openpromio.h linux/include/linux/openpromio.h
--- v2.1.15/linux/include/linux/openpromio.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/openpromio.h	Fri Dec 13 11:37:47 1996
@@ -0,0 +1,6 @@
+#ifndef _LINUX_OPENPROMIO_H
+#define _LINUX_OPENPROMIO_H 1
+
+#include <asm/openpromio.h>
+
+#endif
diff -u --recursive --new-file v2.1.15/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.1.15/linux/include/linux/pci.h	Thu Dec 12 19:37:19 1996
+++ linux/include/linux/pci.h	Wed Dec 18 12:07:55 1996
@@ -415,6 +415,7 @@
 #define PCI_DEVICE_ID_3COM_3C595TX	0x5950
 #define PCI_DEVICE_ID_3COM_3C595T4	0x5951
 #define PCI_DEVICE_ID_3COM_3C595MII	0x5952
+#define PCI_DEVICE_ID_3COM_3C900TPO	0x9000
 
 #define PCI_VENDOR_ID_AL		0x10b9
 #define PCI_DEVICE_ID_AL_M1445		0x1445
@@ -524,6 +525,13 @@
 #define PCI_DEVICE_ID_CYCLOM_Y_Hi	0x0101
 #define PCI_DEVICE_ID_CYCLOM_Z_Lo	0x0200
 #define PCI_DEVICE_ID_CYCLOM_Z_Hi	0x0201
+
+#define PCI_VENDOR_ID_OPTIBASE		0x1255
+#define PCI_DEVICE_ID_OPTIBASE_FORGE	0x1110
+#define PCI_DEVICE_ID_OPTIBASE_FUSION	0x1210
+#define PCI_DEVICE_ID_OPTIBASE_VPLEX	0x2120
+#define PCI_DEVICE_ID_OPTIBASE_VPLEXCC	0x2120
+#define PCI_DEVICE_ID_OPTIBASE_VQUEST	0x2130
 
 #define PCI_VENDOR_ID_SYMPHONY		0x1c1c
 #define PCI_DEVICE_ID_SYMPHONY_101	0x0001
diff -u --recursive --new-file v2.1.15/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.1.15/linux/include/linux/proc_fs.h	Thu Dec 12 19:37:19 1996
+++ linux/include/linux/proc_fs.h	Wed Dec 18 12:45:23 1996
@@ -117,6 +117,9 @@
 	PROC_NET_RS_ROUTES,
 	PROC_NET_RS,
 	PROC_NET_CL2LLC,
+	PROC_NET_X25_LINKS,
+	PROC_NET_X25_ROUTES,
+	PROC_NET_X25,
 	PROC_NET_LAST
 };
 
@@ -150,6 +153,7 @@
 	PROC_SCSI_NCR53C406A,
 	PROC_SCSI_PPA,
 	PROC_SCSI_ESP,
+	PROC_SCSI_QLOGICPTI,
 	PROC_SCSI_A3000,
 	PROC_SCSI_A2091,
 	PROC_SCSI_GVP11,
diff -u --recursive --new-file v2.1.15/linux/include/linux/rose.h linux/include/linux/rose.h
--- v2.1.15/linux/include/linux/rose.h	Tue Nov 19 15:53:57 1996
+++ linux/include/linux/rose.h	Sat Dec 14 13:40:12 1996
@@ -16,6 +16,7 @@
 #define	ROSE_T3		4
 #define	ROSE_IDLE	5
 #define	ROSE_HDRINCL	6
+#define	ROSE_HOLDBACK	7
 
 #define	ROSE_KILL	99
 
diff -u --recursive --new-file v2.1.15/linux/include/linux/skbuff.h linux/include/linux/skbuff.h
--- v2.1.15/linux/include/linux/skbuff.h	Thu Dec 12 19:37:19 1996
+++ linux/include/linux/skbuff.h	Wed Dec 18 12:45:23 1996
@@ -93,11 +93,11 @@
 	struct neighbour *nexthop;
 #endif		
 	struct  dst_entry *dst;
+	char    	cb[32];
 
 	__u32		seq;			/* TCP sequence number				*/
 	__u32		end_seq;		/* seq [+ fin] [+ syn] + datalen		*/
 	__u32		ack_seq;		/* TCP ack sequence number			*/
-	char    	cb[32];
   
 	unsigned int 	len;			/* Length of actual data			*/
 	unsigned int	csum;			/* Checksum 					*/
diff -u --recursive --new-file v2.1.15/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.1.15/linux/include/linux/sysctl.h	Thu Dec 12 19:37:19 1996
+++ linux/include/linux/sysctl.h	Sat Dec 14 13:40:12 1996
@@ -61,6 +61,7 @@
 #define KERN_NFSRADDRS	18	/* NFS root addresses */
 #define KERN_JAVA_INTERPRETER 19 /* path to Java(tm) interpreter */
 #define KERN_JAVA_APPLETVIEWER 20 /* path to Java(tm) appletviewer */
+#define KERN_SPARC_REBOOT 21 /* reboot command on Sparc */
 
 /* CTL_VM names: */
 #define VM_SWAPCTL	1	/* struct: Set vm swapping control */
@@ -127,35 +128,42 @@
 /* /proc/sys/net/appletalk */
 
 /* /proc/sys/net/netrom */
-#define	NET_NETROM_DEFAULT_PATH_QUALITY			1
-#define	NET_NETROM_OBSOLESCENCE_COUNT_INITIALISER	2
-#define	NET_NETROM_NETWORK_TTL_INITIALISER		3
-#define	NET_NETROM_TRANSPORT_TIMEOUT			4
-#define	NET_NETROM_TRANSPORT_MAXIMUM_TRIES		5
-#define	NET_NETROM_TRANSPORT_ACKNOWLEDGE_DELAY		6
-#define	NET_NETROM_TRANSPORT_BUSY_DELAY			7
-#define	NET_NETROM_TRANSPORT_REQUESTED_WINDOW_SIZE	8
-#define	NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT	9
-#define	NET_NETROM_TRANSPORT_PACKET_LENGTH		10
-#define	NET_NETROM_ROUTING_CONTROL			11
+enum {
+	NET_NETROM_DEFAULT_PATH_QUALITY = 1,
+	NET_NETROM_OBSOLESCENCE_COUNT_INITIALISER,
+	NET_NETROM_NETWORK_TTL_INITIALISER,
+	NET_NETROM_TRANSPORT_TIMEOUT,
+	NET_NETROM_TRANSPORT_MAXIMUM_TRIES,
+	NET_NETROM_TRANSPORT_ACKNOWLEDGE_DELAY,
+	NET_NETROM_TRANSPORT_BUSY_DELAY,
+	NET_NETROM_TRANSPORT_REQUESTED_WINDOW_SIZE,
+	NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT,
+	NET_NETROM_TRANSPORT_PACKET_LENGTH,
+	NET_NETROM_ROUTING_CONTROL
+};
 
 /* /proc/sys/net/ax25 */
 /* Values are generated dynamically */
 
 /* /proc/sys/net/rose */
-#define	NET_ROSE_RESTART_REQUEST_TIMEOUT		1
-#define	NET_ROSE_CALL_REQUEST_TIMEOUT			2
-#define	NET_ROSE_RESET_REQUEST_TIMEOUT			3
-#define	NET_ROSE_CLEAR_REQUEST_TIMEOUT			4
-#define	NET_ROSE_NO_ACTIVITY_TIMEOUT			5
-#define	NET_ROSE_ROUTING_CONTROL			6
+enum {
+	NET_ROSE_RESTART_REQUEST_TIMEOUT = 1,
+	NET_ROSE_CALL_REQUEST_TIMEOUT,
+	NET_ROSE_RESET_REQUEST_TIMEOUT,
+	NET_ROSE_CLEAR_REQUEST_TIMEOUT,
+	NET_ROSE_NO_ACTIVITY_TIMEOUT,
+	NET_ROSE_ACK_HOLD_BACK_TIMEOUT,
+	NET_ROSE_ROUTING_CONTROL
+};
 
 /* /proc/sys/net/x25 */
-#define	NET_X25_RESTART_REQUEST_TIMEOUT			1
-#define	NET_X25_CALL_REQUEST_TIMEOUT			2
-#define	NET_X25_RESET_REQUEST_TIMEOUT			3
-#define	NET_X25_CLEAR_REQUEST_TIMEOUT			4
-#define	NET_X25_ACK_HOLDBACK_TIMEOUT			5
+enum {
+	NET_X25_RESTART_REQUEST_TIMEOUT = 1,
+	NET_X25_CALL_REQUEST_TIMEOUT,
+	NET_X25_RESET_REQUEST_TIMEOUT,
+	NET_X25_CLEAR_REQUEST_TIMEOUT,
+	NET_X25_ACK_HOLD_BACK_TIMEOUT
+};
 
 /* CTL_PROC names: */
 
diff -u --recursive --new-file v2.1.15/linux/include/linux/x25.h linux/include/linux/x25.h
--- v2.1.15/linux/include/linux/x25.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/x25.h	Wed Dec 18 12:07:55 1996
@@ -0,0 +1,98 @@
+/*
+ * These are the public elements of the Linux kernel X.25 implementation.
+ */
+ 
+#ifndef	X25_KERNEL_H
+#define	X25_KERNEL_H
+
+#define PF_X25			AF_X25
+
+#define	SIOCX25SETSUBSCR	(SIOCPROTOPRIVATE + 0)
+
+/*
+ *	Values for {get,set}sockopt.
+ */
+#define	X25_QBITINCL		1
+#define	X25_PACKET_SIZE		10
+#define	X25_WINDOW_SIZE		11
+#define	X25_THROUGHPUT_SPEED	12
+#define	X25_REVERSE_CHARGE	13
+
+/*
+ *	X.25 Packet Size values.
+ */
+#define	X25_PS16		4
+#define	X25_PS32		5
+#define	X25_PS64		6
+#define	X25_PS128		7
+#define	X25_PS256		8
+#define	X25_PS512		9
+#define	X25_PS1024		10
+#define	X25_PS2048		11
+#define	X25_PS4096		12
+
+/*
+ *	X.25 Reset error and diagnostic codes.
+ */
+#define	X25_ERR_RESET		100	/* Call Reset			*/
+#define	X25_ERR_ROUT		101	/* Out of Order			*/
+#define	X25_ERR_RRPE		102	/* Remote Procedure Error	*/
+#define	X25_ERR_RLPE		103	/* Local Procedure Error	*/
+#define	X25_ERR_RNCG		104	/* Network Congestion		*/
+#define	X25_ERR_RRDO		105	/* Remote DTE Operational	*/
+#define	X25_ERR_RNOP		106	/* Network Operational		*/
+#define	X25_ERR_RINV		107	/* Invalid Call			*/
+#define	X25_ERR_RNOO		108	/* Network Out of Order		*/
+
+/*
+ *	X.25 Clear error and diagnostic codes.
+ */
+#define	X25_ERR_CLEAR		110	/* Call Cleared			*/
+#define	X25_ERR_CBUSY		111	/* Number Busy			*/
+#define	X25_ERR_COUT		112	/* Out of Order			*/
+#define	X25_ERR_CRPE		113	/* Remote Procedure Error	*/
+#define	X25_ERR_CRRC		114	/* Collect Call Refused		*/
+#define	X25_ERR_CINV		115	/* Invalid Call			*/
+#define	X25_ERR_CNFS		116	/* Invalid Fast Select		*/
+#define	X25_ERR_CSA		117	/* Ship Absent			*/
+#define	X25_ERR_CIFR		118	/* Invalid Facility Request	*/
+#define	X25_ERR_CAB		119	/* Access Barred		*/
+#define	X25_ERR_CLPE		120	/* Local Procedure Error	*/
+#define	X25_ERR_CNCG		121	/* Network Congestion		*/
+#define	X25_ERR_CNOB		122	/* Not Obtainable		*/
+#define	X25_ERR_CROO		123	/* RPOA Out of Order		*/
+
+/*
+ * An X.121 address, it is held as ASCII text, null terminated, up to 15
+ * digits and a null terminator.
+ */
+typedef struct {
+	char x25_addr[16];
+} x25_address;
+
+/*
+ *	Linux X.25 Address structure, used for bind, and connect mostly.
+ */
+struct sockaddr_x25 {
+	sa_family_t	sx25_family;		/* Must be AF_X25 */
+	x25_address	sx25_addr;		/* X.121 Address */
+};
+
+/*
+ *	DTE/DCE subscription options.
+ */
+struct x25_subscrip_struct {
+	char device[200];
+	unsigned int	extended;
+};
+
+/*
+ *	Routing table control structure.
+ */
+struct x25_route_struct {
+	x25_address	address;
+	unsigned int	sigdigits;
+	char		device[200];
+};
+
+#endif
diff -u --recursive --new-file v2.1.15/linux/include/net/ipx.h linux/include/net/ipx.h
--- v2.1.15/linux/include/net/ipx.h	Thu Dec 12 19:37:20 1996
+++ linux/include/net/ipx.h	Wed Dec 18 12:47:26 1996
@@ -26,7 +26,7 @@
 #define ipx_broadcast_node	"\377\377\377\377\377\377"
 #define ipx_this_node           "\0\0\0\0\0\0"
 
-typedef struct ipx_packet
+struct ipxhdr
 {
 	unsigned short	ipx_checksum __attribute__ ((packed));
 #define IPX_NO_CHECKSUM	0xFFFF
@@ -41,7 +41,7 @@
 #define IPX_TYPE_PPROP		0x14	/* complicated flood fill brdcast [Not supported] */
 	ipx_address	ipx_dest __attribute__ ((packed));
 	ipx_address	ipx_source __attribute__ ((packed));
-} ipx_packet;
+};
 
 #include <net/ipxcall.h>
 extern int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt);
diff -u --recursive --new-file v2.1.15/linux/include/net/llc.h linux/include/net/llc.h
--- v2.1.15/linux/include/net/llc.h	Thu Dec 12 19:37:20 1996
+++ linux/include/net/llc.h	Wed Dec 18 12:26:49 1996
@@ -105,18 +105,32 @@
 #define MODE_ADM 1
 #define MODE_ABM 2
 
-	struct sk_buff *rtq_front;	/* oldest skb in the re-transmit queue */
-	struct sk_buff *rtq_back;
+	int llc_callbacks;		/* Pending callbacks */
+#define LLC_CONNECT_INDICATION	1	
+#define LLC_CONNECT_CONFIRM	2
+#define LLC_DATA_INDICATION	4
+#define LLC_DISC_INDICATION	8
+#define LLC_RESET_INDIC_LOC	16
+#define LLC_RESET_INDIC_REM	32
+#define LLC_RESET_CONFIRM	64
+#define LLC_FRMR_RECV		128
+#define LLC_FRMR_SENT		256
+#define LLC_REMOTE_BUSY		512
+#define LLC_REMOTE_NOTBUSY	1024
+#define LLC_SET_REMOTE_BUSY	2048
 
-	struct sk_buff *atq_front;	/* oldest skb in the await-transmit queue */
-	struct sk_buff *atq_back; 
+	struct sk_buff *inc_skb;	/* Saved data buffer for indications */
+	
+	struct sk_buff_head rtq;	/* Retransmit queue */
+	struct sk_buff_head atq;	/* Await transit queue */
       
 	unsigned char xid_count;
-	char * nextllc;			/* ptr to next llc struct in proto chain */
+
+	struct llc_struct *nextllc;	/* ptr to next llc struct in proto chain */
 };
 
-#define ADD_TO_RTQ(skb) llc_add_to_queue(skb, &lp->rtq_front, &lp->rtq_back) 
-#define ADD_TO_ATQ(skb) llc_add_to_queue(skb, &lp->atq_front, &lp->atq_back) 
+#define ADD_TO_RTQ(skb) skb_queue_tail(&lp->rtq,skb)
+#define ADD_TO_ATQ(skb) skb_queue_tail(&lp->atq,skb)
 
 void 		llc_cancel_timers(llcptr lp);
 int		llc_decode_frametype(frameptr fr);
diff -u --recursive --new-file v2.1.15/linux/include/net/netrom.h linux/include/net/netrom.h
--- v2.1.15/linux/include/net/netrom.h	Tue Nov 12 15:56:14 1996
+++ linux/include/net/netrom.h	Sat Dec 14 13:40:12 1996
@@ -53,7 +53,7 @@
 	struct device		*device;
 	unsigned char		my_index,   my_id;
 	unsigned char		your_index, your_id;
-	unsigned char		state, condition, bpqext, hdrincl;
+	unsigned char		state, condition, bpqext, hdrincl, window;
 	unsigned short		vs, vr, va, vl;
 	unsigned char		n2, n2count;
 	unsigned short		t1, t2, t4, idle, rtt;
diff -u --recursive --new-file v2.1.15/linux/include/net/rose.h linux/include/net/rose.h
--- v2.1.15/linux/include/net/rose.h	Tue Nov 12 15:56:14 1996
+++ linux/include/net/rose.h	Sat Dec 14 13:40:12 1996
@@ -48,6 +48,7 @@
 #define ROSE_DEFAULT_T1		(200 * PR_SLOWHZ)	/* Default T11 T21 value */
 #define ROSE_DEFAULT_T2		(180 * PR_SLOWHZ)	/* Default T12 T22 value */
 #define	ROSE_DEFAULT_T3		(180 * PR_SLOWHZ)	/* Default T13 T23 value */
+#define	ROSE_DEFAULT_HB		(5 * PR_SLOWHZ)		/* Default Holdback value */
 #define	ROSE_DEFAULT_IDLE	(20 * 60 * PR_SLOWHZ)	/* Default No Activity value */
 #define	ROSE_DEFAULT_WINDOW	2			/* Default Window Size	*/
 #define ROSE_MODULUS 		8
@@ -104,7 +105,7 @@
 	unsigned char		state, condition, hdrincl;
 	unsigned short		vs, vr, va, vl;
 	unsigned short		timer;
-	unsigned short		t1, t2, t3, idle;
+	unsigned short		t1, t2, t3, hb, idle;
 	unsigned short		fraglen;
 	struct sk_buff_head	ack_queue;
 	struct sk_buff_head	frag_queue;
@@ -117,6 +118,7 @@
 extern int  sysctl_rose_reset_request_timeout;
 extern int  sysctl_rose_clear_request_timeout;
 extern int  sysctl_rose_no_activity_timeout;
+extern int  sysctl_rose_ack_hold_back_timeout;
 extern int  sysctl_rose_routing_control;
 extern int  rosecmp(rose_address *, rose_address *);
 extern char *rose2asc(rose_address *);
diff -u --recursive --new-file v2.1.15/linux/include/net/sock.h linux/include/net/sock.h
--- v2.1.15/linux/include/net/sock.h	Thu Dec 12 19:37:20 1996
+++ linux/include/net/sock.h	Wed Dec 18 12:47:26 1996
@@ -49,7 +49,7 @@
 #include <linux/skbuff.h>	/* struct sk_buff */
 #include <net/protocol.h>		/* struct inet_protocol */
 #if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
-#/* notyet */include <net/x25.h>
+#include <net/x25.h>
 #endif
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 #include <net/ax25.h>
@@ -376,8 +376,6 @@
 	unsigned short		cong_count;
 	atomic_t		packets_out;
 	unsigned short		shutdown;
-
-	unsigned short		window;		/* used by netrom/ax.25 */
 
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
 	union {
diff -u --recursive --new-file v2.1.15/linux/include/net/x25.h linux/include/net/x25.h
--- v2.1.15/linux/include/net/x25.h	Thu Jan  1 02:00:00 1970
+++ linux/include/net/x25.h	Wed Dec 18 12:07:55 1996
@@ -0,0 +1,204 @@
+/*
+ *	Declarations of X.25 Packet Layer type objects.
+ *
+ *	Jonathan Naylor		17/11/96
+ */
+ 
+#ifndef _X25_H
+#define _X25_H 
+#include <linux/x25.h>
+
+#define	X25_SLOWHZ			1	/* Run timing at 1 Hz */
+
+#define	X25_ADDR_LEN			16
+
+#define	X25_MAX_L2_LEN			18	/* 802.2 LLC */
+
+#define	X25_STD_MIN_LEN			3
+#define	X25_EXT_MIN_LEN			4
+
+#define	X25_GFI_SEQ_MASK		0x30
+#define	X25_GFI_STDSEQ			0x10
+#define	X25_GFI_EXTSEQ			0x20
+
+#define	X25_Q_BIT			0x80
+#define	X25_D_BIT			0x40
+#define	X25_STD_M_BIT			0x10
+#define	X25_EXT_M_BIT			0x01
+ 
+#define	X25_CALL_REQUEST		0x0B
+#define	X25_CALL_ACCEPTED		0x0F
+#define	X25_CLEAR_REQUEST		0x13
+#define	X25_CLEAR_CONFIRMATION		0x17
+#define	X25_DATA			0x00
+#define	X25_INTERRUPT			0x23
+#define	X25_INTERRUPT_CONFIRMATION	0x27
+#define	X25_RR				0x01
+#define	X25_RNR				0x05
+#define	X25_REJ				0x09
+#define	X25_RESET_REQUEST		0x1B
+#define	X25_RESET_CONFIRMATION		0x1F
+#define	X25_REGISTRATION_REQUEST	0xF3
+#define	X25_REGISTRATION_CONFIRMATION	0xF7
+#define	X25_RESTART_REQUEST		0xFB
+#define	X25_RESTART_CONFIRMATION	0xFF
+#define	X25_DIAGNOSTIC			0xF1
+#define	X25_ILLEGAL			0xFD
+
+/* Define the various conditions that may exist */
+
+#define	X25_COND_ACK_PENDING	0x01
+#define	X25_COND_OWN_RX_BUSY	0x02
+#define	X25_COND_PEER_RX_BUSY	0x04
+
+/* Define Link State constants. */
+
+#define X25_STATE_0		0		/* Ready */
+#define X25_STATE_1		1		/* Awaiting Call Accepted */
+#define X25_STATE_2		2		/* Awaiting Clear Confirmation */
+#define X25_STATE_3		3		/* Data Transfer */
+#define	X25_STATE_4		4		/* Awaiting Reset Confirmation */
+
+#define X25_DEFAULT_T20		(180 * X25_SLOWHZ)	/* Default T20 value */
+#define X25_DEFAULT_T21		(200 * X25_SLOWHZ)	/* Default T21 value */
+#define X25_DEFAULT_T22		(180 * X25_SLOWHZ)	/* Default T22 value */
+#define	X25_DEFAULT_T23		(180 * X25_SLOWHZ)	/* Default T23 value */
+#define	X25_DEFAULT_T2		(3   * X25_SLOWHZ)	/* Default ack holdback value */
+
+#define	X25_DEFAULT_WINDOW_SIZE	2			/* Default Window Size	*/
+#define	X25_DEFAULT_PACKET_SIZE	X25_PS128		/* Default Packet Size */
+#define	X25_DEFAULT_THROUGHPUT	0x0A			/* Deafult Throughput */
+#define	X25_DEFAULT_REVERSE	0x00			/* Default Reverse Charging */
+
+#define X25_SMODULUS 		8
+#define	X25_EMODULUS		128
+
+/*
+ *	X.25 Facilities constants.
+ */
+
+#define	X25_FAC_CLASS_MASK	0xC0
+
+#define	X25_FAC_CLASS_A		0x00
+#define	X25_FAC_CLASS_B		0x40
+#define	X25_FAC_CLASS_C		0x80
+#define	X25_FAC_CLASS_D		0xC0
+
+#define	X25_FAC_REVERSE		0x01
+#define	X25_FAC_THROUGHPUT	0x02
+#define	X25_FAC_PACKET_SIZE	0x42
+#define	X25_FAC_WINDOW_SIZE	0x43
+
+#define	X25_MAX_FAC_LEN		20		/* Plenty to spare */
+
+struct x25_route {
+	struct x25_route	*next;
+	x25_address		address;	/* Start of address range */
+	unsigned int		sigdigits;	/* Number of sig digits */
+	struct device		*dev;		/* More than one for MLP */
+};
+
+struct x25_neigh {
+	struct x25_neigh	*next;
+	struct device		*dev;
+	unsigned int		state;
+	unsigned int		extended;
+	struct sk_buff_head	queue;
+	unsigned short		t20, t20timer;
+	struct timer_list	timer;
+};
+
+struct x25_facilities {
+	int window_size;
+	int packet_size;
+	int throughput;
+	int reverse;
+};
+
+typedef struct {
+	x25_address		source_addr, dest_addr;
+	struct x25_neigh	*neighbour;
+	unsigned int		lci;
+	unsigned char		state, condition, qbitincl, intflg;
+	unsigned short		vs, vr, va, vl;
+	unsigned short		timer;
+	unsigned short		t2, t21, t22, t23;
+	unsigned short		fraglen;
+	struct sk_buff_head	ack_queue;
+	struct sk_buff_head	fragment_queue;
+	struct sk_buff_head	interrupt_queue;
+	struct sock		*sk;		/* Backlink to socket */
+	struct x25_facilities	facilities;
+} x25_cb;
+
+/* af_x25.c */
+extern int  sysctl_x25_restart_request_timeout;
+extern int  sysctl_x25_call_request_timeout;
+extern int  sysctl_x25_reset_request_timeout;
+extern int  sysctl_x25_clear_request_timeout;
+extern int  sysctl_x25_ack_holdback_timeout;
+
+extern int  x25_addr_ntoa(unsigned char *, x25_address *, x25_address *);
+extern int  x25_addr_aton(unsigned char *, x25_address *, x25_address *);
+extern unsigned int x25_new_lci(void);
+extern struct sock *x25_find_socket(unsigned int);
+extern void x25_destroy_socket(struct sock *);
+extern int  x25_rx_call_request(struct sk_buff *, struct x25_neigh *, unsigned int);
+
+#include <net/x25call.h>
+
+/* x25_dev.c */
+extern int  x25_link_up(struct device *);
+extern void x25_send_frame(struct sk_buff *, struct device *);
+extern int  x25_lapb_receive_frame(struct sk_buff *, struct device *, struct packet_type *);
+extern int  x25_llc_receive_frame(struct sk_buff *, struct device *, struct packet_type *);
+
+/* x25_in.c */
+extern int  x25_process_rx_frame(struct sock *, struct sk_buff *);
+
+/* x25_link.c */
+extern void x25_link_control(struct sk_buff *, struct x25_neigh *, unsigned short);
+extern void x25_link_device_up(struct device *);
+extern void x25_link_device_down(struct device *);
+extern void x25_transmit_restart_request(struct x25_neigh *);
+extern void x25_transmit_restart_confirmation(struct x25_neigh *);
+extern void x25_transmit_diagnostic(struct x25_neigh *, unsigned char);
+extern void x25_transmit_clear_request(struct x25_neigh *, unsigned int, unsigned char);
+extern void x25_transmit_link(struct sk_buff *, struct x25_neigh *);
+extern int  x25_subscr_ioctl(unsigned int, void *);
+extern struct x25_neigh *x25_get_neigh(struct device *);
+extern int  x25_link_get_info(char *, char **, off_t, int, int);
+extern void x25_link_free(void);
+
+/* x25_out.c */
+extern void x25_output(struct sock *, struct sk_buff *);
+extern void x25_kick(struct sock *);
+extern void x25_enquiry_response(struct sock *);
+extern void x25_check_iframes_acked(struct sock *, unsigned short);
+
+/* x25_route.c */
+extern struct device *x25_get_route(x25_address *);
+extern struct device *x25_dev_get(char *);
+extern void x25_route_device_down(struct device *);
+extern int  x25_route_ioctl(unsigned int, void *);
+extern int  x25_routes_get_info(char *, char **, off_t, int, int);
+extern void x25_route_free(void);
+
+/* x25_subr.c */
+extern void x25_clear_queues(struct sock *);
+extern void x25_frames_acked(struct sock *, unsigned short);
+extern void x25_requeue_frames(struct sock *);
+extern int  x25_validate_nr(struct sock *, unsigned short);
+extern void x25_write_internal(struct sock *, int);
+extern int  x25_decode(struct sock *, struct sk_buff *, int *, int *, int *, int *, int *);
+extern int  x25_parse_facilities(struct sk_buff *, struct x25_facilities *);
+extern int  x25_create_facilities(unsigned char *, struct x25_facilities *);
+
+/* x25_timer.c */
+extern void x25_set_timer(struct sock *);
+
+/* sysctl_net_x25.c */
+extern void x25_register_sysctl(void);
+extern void x25_unregister_sysctl(void);
+
+#endif
diff -u --recursive --new-file v2.1.15/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v2.1.15/linux/kernel/sysctl.c	Thu Dec 12 19:37:21 1996
+++ linux/kernel/sysctl.c	Fri Dec 13 11:37:47 1996
@@ -101,6 +101,10 @@
 
 extern char binfmt_java_interpreter[], binfmt_java_appletviewer[];
 
+#ifdef __sparc__
+extern char reboot_command [];
+#endif
+
 /* The default sysctl tables: */
 
 static ctl_table root_table[] = {
@@ -148,6 +152,10 @@
 	 64, 0644, NULL, &proc_dostring, &sysctl_string },
 	{KERN_JAVA_APPLETVIEWER, "java-appletviewer", binfmt_java_appletviewer,
 	 64, 0644, NULL, &proc_dostring, &sysctl_string },
+#endif
+#ifdef __sparc__
+	{KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
+	 256, 0644, NULL, &proc_dostring, &sysctl_string },
 #endif
 	{0}
 };
diff -u --recursive --new-file v2.1.15/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.1.15/linux/mm/swapfile.c	Sat Nov 30 12:03:13 1996
+++ linux/mm/swapfile.c	Sat Dec 14 14:24:06 1996
@@ -83,7 +83,9 @@
 
 	type = swap_list.next;
 	if (type < 0)
-	  return 0;
+		return 0;
+	if (nr_swap_pages == 0)
+		return 0;
 
 	while (1) {
 		p = &swap_info[type];
diff -u --recursive --new-file v2.1.15/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.1.15/linux/mm/vmscan.c	Tue Oct 29 19:58:48 1996
+++ linux/mm/vmscan.c	Sat Dec 14 14:24:06 1996
@@ -108,13 +108,8 @@
 		} else {
 			if (page_map->count != 1)
 				return 0;
-			if (!(entry = get_swap_page())) {
-				/* Aieee!!! Out of swap space! */
-				int retval = -1;
-				if (nr_swapfiles == 0)
-					retval = 0;
-				return retval;
-			}
+			if (!(entry = get_swap_page()))
+				return 0;
 			vma->vm_mm->rss--;
 			flush_cache_page(vma, address);
 			set_pte(page_table, __pte(entry));
@@ -317,9 +312,6 @@
 		if (!--p->swap_cnt)
 			swap_task++;
 		switch (swap_out_process(p, dma, wait)) {
-			/* out of swap space? */
-			case -1:
-				return 0;
 			case 0:
 				if (p->swap_cnt)
 					swap_task++;
@@ -428,9 +420,22 @@
 
 void swap_tick(void)
 {
-	if ((nr_free_pages + nr_async_pages) < free_pages_low ||
-	    ((nr_free_pages + nr_async_pages) < free_pages_high && 
-	     jiffies >= next_swap_jiffies)) {
+	int	want_wakeup = 0;
+	static int	last_wakeup_low = 0;
+
+	if ((nr_free_pages + nr_async_pages) < free_pages_low) {
+		if (last_wakeup_low)
+			want_wakeup = jiffies >= next_swap_jiffies;
+		else
+			last_wakeup_low = want_wakeup = 1;
+	}
+	else if (((nr_free_pages + nr_async_pages) < free_pages_high) && 
+	         jiffies >= next_swap_jiffies) {
+		last_wakeup_low = 0;
+		want_wakeup = 1;
+	}
+
+	if (want_wakeup) {
 		if (!kswapd_awake && kswapd_ctl.maxpages > 0) {
 			wake_up(&kswapd_wait);
 			need_resched = 1;
diff -u --recursive --new-file v2.1.15/linux/net/802/cl2llc.c linux/net/802/cl2llc.c
--- v2.1.15/linux/net/802/cl2llc.c	Thu Dec 12 19:37:21 1996
+++ linux/net/802/cl2llc.c	Wed Dec 18 12:07:55 1996
@@ -422,7 +422,7 @@
 				{
 					lp->retry_count = 0;
 					llc_stop_timer(lp, ACK_TIMER);  
-					if (lp->rtq_front != NULL)
+					if (skb_peek(&lp->rtq) != NULL)
 					{
 						/*
  						 *	Re-transmit queue not empty 
diff -u --recursive --new-file v2.1.15/linux/net/802/cl2llc.pre linux/net/802/cl2llc.pre
--- v2.1.15/linux/net/802/cl2llc.pre	Thu Dec 12 19:37:21 1996
+++ linux/net/802/cl2llc.pre	Wed Dec 18 12:07:55 1996
@@ -422,7 +422,7 @@
 				{
 					lp->retry_count = 0;
 					llc_stop_timer(lp, ACK_TIMER);  
-					if (lp->rtq_front != NULL)
+					if (skb_peek(&lp->rtq) != NULL)
 					{
 						/*
  						 *	Re-transmit queue not empty 
diff -u --recursive --new-file v2.1.15/linux/net/802/llc_macinit.c linux/net/802/llc_macinit.c
--- v2.1.15/linux/net/802/llc_macinit.c	Thu Dec 12 19:37:21 1996
+++ linux/net/802/llc_macinit.c	Wed Dec 18 12:07:55 1996
@@ -173,6 +173,8 @@
 	lp->state = 0;
 	lp->llc_mode = MODE_ADM;
 	lp->remote_sap = dsap;
+	skb_queue_head_init(&lp->atq);
+	skb_queue_head_init(&lp->rtq);
 	MOD_INC_USE_COUNT;
 	return 0;
 }
diff -u --recursive --new-file v2.1.15/linux/net/802/llc_sendpdu.c linux/net/802/llc_sendpdu.c
--- v2.1.15/linux/net/802/llc_sendpdu.c	Thu Dec 12 19:37:21 1996
+++ linux/net/802/llc_sendpdu.c	Wed Dec 18 12:07:55 1996
@@ -162,8 +162,9 @@
 		lp->dev->hard_header(skb, lp->dev, ETH_P_802_3,
 			 lp->remote_mac, NULL, fl);
 		skb->arp = 1;
-		skb->free = 1;
-		dev_queue_xmit(skb, lp->dev, SOPRI_NORMAL);
+		skb->priority=SOPRI_NORMAL;
+		skb->dev=lp->dev;
+		dev_queue_xmit(skb);
 	}
 	else
 		printk(KERN_DEBUG "cl2llc: skb_alloc() in llc_sendpdu() failed\n");     
@@ -196,7 +197,8 @@
 void llc_sendipdu(llcptr lp, char type, char pf, struct sk_buff *skb)
 {
 	frameptr fr;                /* ptr to output pdu buffer */
-
+	struct sk_buff *tmp;
+	
 	fr = (frameptr) skb->data;
 
 	fr->pdu_hdr.dsap = lp->remote_sap;
@@ -213,9 +215,14 @@
 	lp->dev->hard_header(skb, lp->dev, ETH_P_802_3,
 		lp->remote_mac, NULL, skb->len);
 	skb->arp = 1;
-	skb->free = 0;              /* thanks, Alan */
 	ADD_TO_RTQ(skb);		/* add skb to the retransmit queue */
-	dev_queue_xmit(skb, lp->dev, SOPRI_NORMAL);
+	tmp=skb_clone(skb, GFP_ATOMIC);
+	if(tmp!=NULL)
+	{
+		tmp->dev=lp->dev;
+		tmp->priority=SOPRI_NORMAL;
+		dev_queue_xmit(tmp);
+	}
 }
 
 
@@ -230,22 +237,21 @@
 
 int llc_resend_ipdu(llcptr lp, unsigned char ack_nr, unsigned char type, char p)
 {
-	struct sk_buff *skb;
+	struct sk_buff *skb,*tmp;
 	int resend_count;
 	frameptr fr;
+	unsigned long flags;
+	
 
 	resend_count = 0;
-	skb = lp->rtq_front;
+	
+	save_flags(flags);
+	cli();
+	
+	skb = skb_peek(&lp->rtq);
 
-	while(skb != NULL)
+	while(skb && skb != (struct sk_buff *)&lp->rtq)
 	{
-		/* 
-		 *	Should not occur: 
-		 */
-		 
-		if (skb_device_locked(skb)) 
-			return resend_count;
-		
 		fr = (frameptr) (skb->data + lp->dev->hard_header_len);
 		if (resend_count == 0) 
 		{
@@ -277,12 +283,18 @@
 		lp->vs++;
 		if (lp->vs > 127) 
 			lp->vs = 0;
-		skb->arp = 1;
-		skb->free = 0;
-		dev_queue_xmit(skb, lp->dev, SOPRI_NORMAL);
+		tmp=skb_clone(skb, GFP_ATOMIC);
+		if(tmp!=NULL)
+		{
+			tmp->arp = 1;
+			tmp->dev = lp->dev;
+			tmp->priority = SOPRI_NORMAL;
+			dev_queue_xmit(skb);
+		}
 		resend_count++;
-		skb = skb->link3;
+		skb = skb->next;
 	}
+	restore_flags(flags);
 	return resend_count;
 }
 
@@ -290,28 +302,6 @@
 
 
 /*
- *	Add_to_queue() adds an skb at back of an I-frame queue.
- *	this function is used for both atq and rtq.
- *	the front and back pointers identify the queue being edited.
- *	this function is called with macros ADD_TO_RTQ() and ADD_TO_ATQ() .
- */
-
-void llc_add_to_queue(struct sk_buff *skb,
-	struct sk_buff **front, struct sk_buff **back) 
-{
-	struct sk_buff *t;
-
-	skb->link3 = NULL;		/* there is no more recent skb */ 
-	t = *back;			/* save current back ptr */
-	*back = skb;
-	if (t != NULL) 
-		t->link3 = skb;
-	if (*front == NULL) 
-		*front = *back;
-}
-
-
-/*
  *	Remove one skb from the front of the awaiting transmit queue
  *	(this is the skb longest on the queue) and return a pointer to 
  *	that skb. 
@@ -319,18 +309,7 @@
 
 struct sk_buff *llc_pull_from_atq(llcptr lp) 
 {
-	struct sk_buff *t;
-
-	if (lp->atq_front == NULL) 
-		return NULL;     /* empty queue */
-
-	t = lp->atq_front;
-	lp->atq_front = t->link3;
-	if (lp->atq_front == NULL) 
-	{
-		lp->atq_back = lp->atq_front;
-	}
-	return t;
+	return skb_dequeue(&lp->atq);
 }
  
 /*
@@ -346,6 +325,7 @@
 	int ack_count;
 	unsigned char ack; 	/* N(S) of most recently ack'ed pdu */
 	unsigned char ns_save; 
+	unsigned long flags;
 
 	if (pdu_ack > 0) 
 		ack = pdu_ack -1;
@@ -353,28 +333,31 @@
 		ack = 127;
 
 	ack_count = 0;
-	pp = lp->rtq_front; 
+
+	save_flags(flags);
+	cli();
+
+	pp = skb_dequeue(&lp->rtq); 
 	while (pp != NULL)
 	{
 		/* 
 		 *	Locate skb with N(S) == ack 
 		 */
-		lp->rtq_front = pp->link3;
+
+		/*
+		 *	BUG: FIXME - use skb->h.*
+		 */
 		fr = (frameptr) (pp->data + lp->dev->hard_header_len);
 		ns_save = fr->i_hdr.ns;
-		if (skb_device_locked(pp)) 
-			return ack_count;
 
 		kfree_skb(pp, FREE_WRITE);
 		ack_count++;
 
 		if (ns_save == ack) 
 			break;  
-		pp = lp->rtq_front;   
+		pp = skb_dequeue(&lp->rtq);
 	}
-	if (pp == NULL)			/* if rtq empty now */ 
-		lp->rtq_back = NULL;		/* correct back pointer */
-
+	restore_flags(flags);
 	return ack_count; 
 }
 
diff -u --recursive --new-file v2.1.15/linux/net/802/transit/timertr.h linux/net/802/transit/timertr.h
--- v2.1.15/linux/net/802/transit/timertr.h	Thu Dec 12 19:37:21 1996
+++ linux/net/802/transit/timertr.h	Wed Dec 18 12:07:55 1996
@@ -1,5 +1,5 @@
 
-/* this file was generated on Thu Dec  5 13:58:11 GMT 1996  */
+/* this file was generated on Mon Dec 16 22:26:17 GMT 1996  */
 
 
 /* size of transition table is 898 bytes */
diff -u --recursive --new-file v2.1.15/linux/net/Config.in linux/net/Config.in
--- v2.1.15/linux/net/Config.in	Thu Dec 12 19:37:21 1996
+++ linux/net/Config.in	Wed Dec 18 12:07:55 1996
@@ -32,8 +32,8 @@
   dep_tristate 'Amateur Radio X.25 PLP (Rose)' CONFIG_ROSE $CONFIG_AX25
 fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-# tristate 'CCITT X.25 Packet Layer' CONFIG_X25
+  tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
   bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE
-#  bool '802.2 LLC (EXPERIMENTAL)' CONFIG_LLC
+  bool '802.2 LLC (VERY EXPERIMENTAL)' CONFIG_LLC
 fi
 endmenu
diff -u --recursive --new-file v2.1.15/linux/net/Makefile linux/net/Makefile
--- v2.1.15/linux/net/Makefile	Tue Nov 12 15:56:15 1996
+++ linux/net/Makefile	Wed Dec 18 12:07:55 1996
@@ -9,7 +9,7 @@
 
 MOD_SUB_DIRS := ipv4
 ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipv6 ipx unix appletalk \
-		netrom rose #decnet
+		netrom rose x25 #decnet
 SUB_DIRS     := core ethernet unix
 MOD_LIST_NAME := NET_MISC_MODULES
 
@@ -46,6 +46,14 @@
 else
   ifeq ($(CONFIG_ATALK),m)
   MOD_SUB_DIRS += appletalk
+  endif
+endif
+
+ifeq ($(CONFIG_X25),y)
+SUB_DIRS += x25
+else
+  ifeq ($(CONFIG_X25),m)
+  MOD_SUB_DIRS += x25
   endif
 endif
 
diff -u --recursive --new-file v2.1.15/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v2.1.15/linux/net/appletalk/ddp.c	Thu Dec 12 19:37:22 1996
+++ linux/net/appletalk/ddp.c	Fri Dec 13 11:24:44 1996
@@ -2110,7 +2110,7 @@
 	dev_remove_pack(&ltalk_packet_type);
 	dev_remove_pack(&ppptalk_packet_type);
 	unregister_snap_client(ddp_snap_id);
-	sock_unregister(atalk_proto_ops.family);
+	sock_unregister(&atalk_family_ops);
 
 	free_route_list();
 	free_interface_list();
diff -u --recursive --new-file v2.1.15/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v2.1.15/linux/net/ax25/af_ax25.c	Thu Dec 12 19:37:22 1996
+++ linux/net/ax25/af_ax25.c	Sat Dec 14 13:40:12 1996
@@ -1165,7 +1165,8 @@
 		return -ENOMEM;
 	}
 
-	sock->ops=&ax25_proto_ops;
+	sock->ops = &ax25_proto_ops;
+
 	skb_queue_head_init(&sk->receive_queue);
 	skb_queue_head_init(&sk->write_queue);
 	skb_queue_head_init(&sk->back_log);
@@ -1188,8 +1189,8 @@
 	sk->error_report = def_callback1;
 
 	if (sock != NULL) {
-		sock->sk = sk;
-		sk->sleep  = &sock->wait;
+		sock->sk  = sk;
+		sk->sleep = &sock->wait;
 	}
 
 	ax25->sk          = sk;
@@ -1238,7 +1239,6 @@
 	sk->sndbuf      = osk->sndbuf;
 	sk->debug       = osk->debug;
 	sk->state       = TCP_ESTABLISHED;
-	sk->window      = osk->window;
 	sk->mtu         = osk->mtu;
 	sk->sleep       = osk->sleep;
 	sk->zapped      = osk->zapped;
@@ -1356,8 +1356,8 @@
 		ax25_destroy_socket(sk->protinfo.ax25);
 	}
 
-	sock->sk = NULL;	
-	sk->socket = NULL;	/* Not used, but we should do this. **/
+	sock->sk   = NULL;	
+	sk->socket = NULL;	/* Not used, but we should do this */
 
 	return 0;
 }
@@ -1965,7 +1965,7 @@
 	int lv;
 	int addr_len = msg->msg_namelen;
 	
-	if ((msg->msg_flags&~MSG_DONTWAIT) || msg->msg_control)
+	if (msg->msg_flags & ~MSG_DONTWAIT)
 		return -EINVAL;
 
 	if (sk->zapped)
@@ -2033,8 +2033,7 @@
 	/* Assume the worst case */
 	size = len + 3 + size_ax25_addr(dp) + AX25_BPQ_HEADER_LEN;
 
-	if ((skb = sock_alloc_send_skb(sk, size, 0, 
-		msg->msg_flags&MSG_DONTWAIT, &err)) == NULL)
+	if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
 		return err;
 
 	skb->sk   = sk;
@@ -2088,8 +2087,9 @@
 		*asmptr = LAPB_UI;
 
 		/* Datagram frames go straight out of the door as UI */
-		skb->dev=sk->protinfo.ax25->device;
-		skb->priority=SOPRI_NORMAL;
+		skb->dev      = sk->protinfo.ax25->device;
+		skb->priority = SOPRI_NORMAL;
+
 		ax25_queue_xmit(skb);
 
 		return len;
@@ -2115,7 +2115,7 @@
 		return -ENOTCONN;
 
 	/* Now we can treat all alike */
-	if ((skb = skb_recv_datagram(sk, flags, flags&MSG_DONTWAIT, &er)) == NULL)
+	if ((skb = skb_recv_datagram(sk, flags, msg->msg_flags & MSG_DONTWAIT, &er)) == NULL)
 		return er;
 
 	if (sk->protinfo.ax25->hdrincl) {
@@ -2136,8 +2136,7 @@
 
 	skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 	
-	if (sax) 
-	{
+	if (sax != NULL) {
 		ax25_digi digi;
 		ax25_address dest;
 
@@ -2150,8 +2149,7 @@
 		sax->sax25_ndigis = digi.ndigi;
 		sax->sax25_call   = dest;
 
-		if (sax->sax25_ndigis != 0) 
-		{
+		if (sax->sax25_ndigis != 0) {
 			int ct           = 0;
 			struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)sax;
 
@@ -2159,11 +2157,11 @@
 				fsa->fsa_digipeater[ct] = digi.calls[ct];
 				ct++;
 			}
-
 		}
 	}
 
-	msg->msg_namelen=sizeof(struct full_sockaddr_ax25);
+	msg->msg_namelen = sizeof(struct full_sockaddr_ax25);
+
 	skb_free_datagram(sk, skb);
 
 	return copied;
@@ -2460,6 +2458,7 @@
 
 	ptr = skb_push(skb, 1);
 	*ptr++ = 0;			/* KISS */
+
 	dev_queue_xmit(skb);
 }
 
@@ -2526,8 +2525,8 @@
 {
 	struct sk_buff *ourskb;
 	int mode;
-	unsigned char *bp=skb->data;
-	struct device *dev=skb->dev;
+	unsigned char *bp  = skb->data;
+	struct device *dev = skb->dev;
 
   	if (arp_find(bp + 1, skb))
   		return 1;
@@ -2576,8 +2575,10 @@
   	 *		  over ethernet. I don't know if this is valid, though.
   	 */
 	ax25_dg_build_path(skb, (ax25_address *)(bp + 1), dev);
-	skb->dev=dev;
-	skb->priority=SOPRI_NORMAL;
+
+	skb->dev      = dev;
+	skb->priority = SOPRI_NORMAL;
+
 	ax25_queue_xmit(skb);
 
   	return 1;
diff -u --recursive --new-file v2.1.15/linux/net/ax25/ax25_out.c linux/net/ax25/ax25_out.c
--- v2.1.15/linux/net/ax25/ax25_out.c	Thu Dec 12 19:37:22 1996
+++ linux/net/ax25/ax25_out.c	Sat Dec 14 13:40:12 1996
@@ -270,9 +270,10 @@
 	ptr = skb_push(skb, size_ax25_addr(ax25->digipeat));
 	build_ax25_addr(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type, ax25->modulus);
 
-	skb->arp = 1;
-	skb->dev=ax25->device;
-	skb->priority=SOPRI_NORMAL;
+	skb->arp      = 1;
+	skb->dev      = ax25->device;
+	skb->priority = SOPRI_NORMAL;
+
 	ax25_queue_xmit(skb);
 }
 
diff -u --recursive --new-file v2.1.15/linux/net/ax25/ax25_subr.c linux/net/ax25/ax25_subr.c
--- v2.1.15/linux/net/ax25/ax25_subr.c	Thu Dec 12 19:37:22 1996
+++ linux/net/ax25/ax25_subr.c	Sat Dec 14 13:40:12 1996
@@ -64,21 +64,17 @@
 {
 	struct sk_buff *skb;
 
-	while ((skb = skb_dequeue(&ax25->write_queue)) != NULL) {
+	while ((skb = skb_dequeue(&ax25->write_queue)) != NULL)
 		kfree_skb(skb, FREE_WRITE);
-	}
 
-	while ((skb = skb_dequeue(&ax25->ack_queue)) != NULL) {
+	while ((skb = skb_dequeue(&ax25->ack_queue)) != NULL)
 		kfree_skb(skb, FREE_WRITE);
-	}
 
-	while ((skb = skb_dequeue(&ax25->reseq_queue)) != NULL) {
+	while ((skb = skb_dequeue(&ax25->reseq_queue)) != NULL)
 		kfree_skb(skb, FREE_READ);
-	}
 
-	while ((skb = skb_dequeue(&ax25->frag_queue)) != NULL) {
+	while ((skb = skb_dequeue(&ax25->frag_queue)) != NULL)
 		kfree_skb(skb, FREE_READ);
-	}
 }
 
 /*
@@ -271,8 +267,8 @@
 	dptr  = skb_push(skb, size_ax25_addr(digi));
 	dptr += build_ax25_addr(dptr, dest, src, &retdigi, C_RESPONSE, MODULUS);
 
-	skb->arp  = 1;
-	skb->dev = dev;
+	skb->arp      = 1;
+	skb->dev      = dev;
 	skb->priority = SOPRI_NORMAL;
 
 	ax25_queue_xmit(skb);
@@ -534,11 +530,12 @@
 
 	p = skb_put(skb, 2);
 
-	*p++=cmd;
-	*p  =param;
+	*p++ = cmd;
+	*p++ = param;
+
+	skb->dev      = ax25->device;
+	skb->priority = SOPRI_NORMAL;
 
-	skb->dev=ax25->device;
-	skb->priority=SOPRI_NORMAL;
 	dev_queue_xmit(skb);
 }
 
diff -u --recursive --new-file v2.1.15/linux/net/bridge/br.c linux/net/bridge/br.c
--- v2.1.15/linux/net/bridge/br.c	Thu Dec 12 19:37:22 1996
+++ linux/net/bridge/br.c	Wed Dec 18 12:07:55 1996
@@ -980,7 +980,7 @@
 			skb->h.eth->h_dest[3],
 			skb->h.eth->h_dest[4],
 			skb->h.eth->h_dest[5]);
-	skb->h.eth->h_proto = htonl(0x8038);	/* XXX verify */
+	skb->h.eth->h_proto = htons(0x8038);
 
 	skb->h.raw += skb->dev->hard_header_len;
 	memcpy(skb->h.raw, config_bpdu, sizeof(Config_bpdu));
@@ -1036,12 +1036,12 @@
 			skb->h.eth->h_dest[3],
 			skb->h.eth->h_dest[4],
 			skb->h.eth->h_dest[5]);
-	skb->h.eth->h_proto = 0x8038;	/* XXX verify */
+	skb->h.eth->h_proto = htons(0x8038);
 
 	skb->h.raw += skb->dev->hard_header_len;
 	memcpy(skb->h.raw, bpdu, sizeof(Tcn_bpdu));
 
-	/* mark that's we've been here... */
+	/* mark that we've been here... */
 	skb->pkt_bridged = IS_BRIDGED;
 	skb->arp = 1;	/* do not resolve... */
 	skb->h.raw = skb->data + ETH_HLEN;
diff -u --recursive --new-file v2.1.15/linux/net/core/dev.c linux/net/core/dev.c
--- v2.1.15/linux/net/core/dev.c	Thu Dec 12 19:37:22 1996
+++ linux/net/core/dev.c	Sat Dec 14 15:13:40 1996
@@ -1028,7 +1028,7 @@
 			       stats->qual.noise,
 			       stats->qual.updated & 3 ? '.' : ' ',
 			       stats->discard.nwid,
-			       stats->discard.crypt,
+			       stats->discard.codec,
 			       stats->discard.misc);
 	else
 		size = 0;
diff -u --recursive --new-file v2.1.15/linux/net/ipv4/arp.c linux/net/ipv4/arp.c
--- v2.1.15/linux/net/ipv4/arp.c	Thu Dec 12 19:37:25 1996
+++ linux/net/ipv4/arp.c	Wed Dec 18 12:07:55 1996
@@ -1074,7 +1074,7 @@
 	add_timer(&entry->timer);
 #ifdef CONFIG_ARPD
 	if (!arpd_not_running)
-		arpd_lookup(entry->ip, entry->dev);
+		arpd_lookup(entry->ip, dev);
 	else
 #endif
 		arp_send(ARPOP_REQUEST, ETH_P_ARP, entry->ip, dev,
diff -u --recursive --new-file v2.1.15/linux/net/ipv4/fib.c linux/net/ipv4/fib.c
--- v2.1.15/linux/net/ipv4/fib.c	Thu Dec 12 19:37:25 1996
+++ linux/net/ipv4/fib.c	Sun Dec 15 19:41:56 1996
@@ -66,7 +66,7 @@
 
 static int fib_stamp;
 
-static int rtmsg_process(struct nlmsghdr *n, struct in_rtmsg *r);
+int rtmsg_process(struct nlmsghdr *n, struct in_rtmsg *r);
 
 
 #ifdef CONFIG_RTNETLINK
@@ -119,7 +119,7 @@
 static struct wait_queue *fib_wait;
 atomic_t fib_users;
 
-static void fib_lock(void)
+void fib_lock(void)
 {
 	while (fib_users)
 		sleep_on(&fib_wait);
@@ -127,7 +127,7 @@
 	dev_lock_list();
 }
 
-static void fib_unlock(void)
+void fib_unlock(void)
 {
 	dev_unlock_list();
 	if (atomic_dec_and_test(&fib_users)) {
@@ -566,7 +566,7 @@
 	if (op)
 		return arp_req_set(&r, NULL);
 	
-	fz = &local_class.fib_zone_list[logmask];
+	fz = local_class.fib_zones[logmask];
 
 	for (f1 = fz_hash(f->fib_key, fz); f1; f1=f1->fib_next)	{
 		if (f->fib_key != f1->fib_key || f1->fib_flag ||
@@ -838,7 +838,7 @@
 	struct fib_zone * fz;
 	struct fib_info * fi;
 
-	int logmask = 32 - r->rtmsg_prefixlen;
+	long logmask = 32L - r->rtmsg_prefixlen;	/* gcc bug work-around: must be "L" and "long" */
 	u32 dst = ntohl(r->rtmsg_prefix.s_addr);
 	u32 gw  = r->rtmsg_gateway.s_addr;
 	short metric = r->rtmsg_metric;
@@ -1397,7 +1397,7 @@
 
 #endif
 
-static int rtmsg_process(struct nlmsghdr *n, struct in_rtmsg *r)
+int rtmsg_process(struct nlmsghdr *n, struct in_rtmsg *r)
 {
 	unsigned long cmd=n->nlmsg_type;
 	struct device * dev = NULL;
diff -u --recursive --new-file v2.1.15/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.1.15/linux/net/ipv4/icmp.c	Thu Dec 12 19:37:25 1996
+++ linux/net/ipv4/icmp.c	Wed Dec 18 12:07:55 1996
@@ -337,7 +337,7 @@
 	struct icmp_xrlim *xrlim;	/* Transmit rate limit control structure or NULL for no limits */
 };
 
-static struct icmp_control icmp_pointers[19];
+static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1];
 
 /*
  *	Build xmit assembly blocks
@@ -378,7 +378,7 @@
 	int type, entry;
 	struct icmp_xrlim *xr;
 
-	for (type=0; type<=18; type++) {
+	for (type=0; type<=NR_ICMP_TYPES; type++) {
 		xr = icmp_pointers[type].xrlim;
 		if (xr) {
 			for (entry=0; entry<XRLIM_CACHE_SIZE; entry++)
@@ -401,7 +401,7 @@
 	struct icmp_xrl_cache *c;
 	unsigned long now;
 
-	if (type > 18)			/* No time limit present */
+	if (type > NR_ICMP_TYPES)		/* No time limit present */
 		return 1;
 	r = icmp_pointers[type].xrlim;
 	if (!r)
@@ -466,7 +466,7 @@
  
 static void icmp_out_count(int type)
 {
-	if (type>18)
+	if (type>NR_ICMP_TYPES)
 		return;
 	(*icmp_pointers[type].output)++;
 	icmp_statistics.IcmpOutMsgs++;
@@ -602,7 +602,7 @@
 			 *	Assume any unknown ICMP type is an error. This isn't
 			 *	specified by the RFC, but think about it..
 			 */
-			if (icmph->type>18 || icmp_pointers[icmph->type].error)
+			if (icmph->type>NR_ICMP_TYPES || icmp_pointers[icmph->type].error)
 				return;
 		}
 	}
@@ -985,7 +985,7 @@
 {
 	struct icmphdr *icmph=(struct icmphdr *)(skb->nh.raw + skb->nh.iph->ihl*4);
 	struct iphdr *iph = (struct iphdr *) (icmph + 1);
-	void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len) = icmp_pointers[icmph->type].handler;
+	void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, int len) = icmp_pointers[icmph->type].handler;
 
 	if (handler == icmp_unreach || handler == icmp_redirect) {
 		struct sock *sk;
@@ -1064,7 +1064,7 @@
 	 *	RFC 1122: 3.2.2  Unknown ICMP messages types MUST be silently discarded.
 	 */
 	 
-	if (icmph->type > 18) {
+	if (icmph->type > NR_ICMP_TYPES) {
 		icmp_statistics.IcmpInErrors++;		/* Is this right - or do we ignore ? */
 		kfree_skb(skb,FREE_READ);
 		return(0);
@@ -1108,7 +1108,7 @@
  *	This table is the definition of how we handle ICMP.
  */
  
-static struct icmp_control icmp_pointers[19] = {
+static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1] = {
 /* ECHO REPLY (0) */
  { &icmp_statistics.IcmpOutEchoReps, &icmp_statistics.IcmpInEchoReps, icmp_discard, 0, NULL },
  { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, NULL },
diff -u --recursive --new-file v2.1.15/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c
--- v2.1.15/linux/net/ipv4/ip_forward.c	Thu Dec 12 19:37:25 1996
+++ linux/net/ipv4/ip_forward.c	Wed Dec 18 12:07:55 1996
@@ -28,6 +28,8 @@
 #include <linux/netdevice.h>
 #include <net/sock.h>
 #include <net/ip.h>
+#include <net/tcp.h>
+#include <net/udp.h>
 #include <net/icmp.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
diff -u --recursive --new-file v2.1.15/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.1.15/linux/net/ipv4/route.c	Thu Dec 12 19:37:27 1996
+++ linux/net/ipv4/route.c	Wed Dec 18 12:07:55 1996
@@ -132,7 +132,7 @@
 	pos = 128;
 
 	if (offset<128)	{
-		sprintf(buffer,"%-127s\n","Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tSource\t\tMTU\tWindow\tIRTT\tTOS\tHH\tARP");
+		sprintf(buffer,"%-127s\n", "Iface\tDestination\tGateway \tFlags\t\tRefCnt\tUse\tMetric\tSource\t\tMTU\tWindow\tIRTT\tTOS\tHHRef\tHHUptod\tSpecDst\tHash");
 		len = 128;
   	}
 	
@@ -151,7 +151,7 @@
 				continue;
 			}
 					
-			sprintf(temp, "%s\t%08lX\t%08lX\t%X\t%d\t%u\t%d\t%08lX\t%d\t%u\t%u\t%02x\t%d\t%1d\t%08x\t%02x",
+			sprintf(temp, "%s\t%08lX\t%08lX\t%8X\t%d\t%u\t%d\t%08lX\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X\t%02X",
 				r->u.dst.dev ? r->u.dst.dev->name : "*",
 				(unsigned long)r->rt_dst,
 				(unsigned long)r->rt_gateway,
diff -u --recursive --new-file v2.1.15/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.1.15/linux/net/ipv4/tcp_ipv4.c	Thu Dec 12 19:37:30 1996
+++ linux/net/ipv4/tcp_ipv4.c	Wed Dec 18 12:07:55 1996
@@ -721,7 +721,7 @@
 	struct rtable *rt;
 	int snd_mss;
 
-	newsk = (struct sock *) kmalloc(sizeof(struct sock), GFP_ATOMIC);
+	newsk = sk_alloc(GFP_ATOMIC);
 	if (newsk == NULL)
 	{
 		return NULL;
@@ -1018,7 +1018,7 @@
 
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
 	if (IPCB(skb)->redirport)
-		sk = get_sock_proxy(&tcp_prot, th->dest, saddr, th->source, daddr, dev->pa_addr, IPCB(skb)->redirport);
+		sk = get_sock_proxy(&tcp_prot, th->dest, saddr, th->source, daddr, skb->dev->pa_addr, IPCB(skb)->redirport);
 	else
 #endif
 	sk = get_tcp_sock(saddr, th->source, daddr, th->dest);
diff -u --recursive --new-file v2.1.15/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.1.15/linux/net/ipv4/udp.c	Thu Dec 12 19:37:30 1996
+++ linux/net/ipv4/udp.c	Wed Dec 18 12:07:55 1996
@@ -824,7 +824,7 @@
 
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
 	if (IPCB(skb)->redirport)
-		sk = get_sock_proxy(&udp_prot, uh->dest, saddr, uh->source, daddr, dev->pa_addr, IPCB(skb)->redirport);
+		sk = get_sock_proxy(&udp_prot, uh->dest, saddr, uh->source, daddr, skb->dev->pa_addr, IPCB(skb)->redirport);
 	else
 #endif
 	sk = get_udp_sock(uh->dest, saddr, uh->source, daddr);
diff -u --recursive --new-file v2.1.15/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
--- v2.1.15/linux/net/ipv6/af_inet6.c	Thu Dec 12 19:37:30 1996
+++ linux/net/ipv6/af_inet6.c	Wed Dec 18 12:07:55 1996
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/af_inet.c
  *
- *	$Id: af_inet6.c,v 1.13 1996/10/31 19:47:17 roque Exp $
+ *	$Id: af_inet6.c,v 1.6 1996/12/12 19:22:09 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -127,7 +127,7 @@
 		case SOCK_SEQPACKET:
 			if (protocol && protocol != IPPROTO_TCP) 
 			{
-				kfree_s((void *)sk, sizeof(*sk));
+				sk_free(sk);
 				return(-EPROTONOSUPPORT);
 			}
 			protocol = IPPROTO_TCP;
@@ -139,7 +139,7 @@
 		case SOCK_DGRAM:
 			if (protocol && protocol != IPPROTO_UDP) 
 			{
-				kfree_s((void *)sk, sizeof(*sk));
+				sk_free(sk);
 				return(-EPROTONOSUPPORT);
 			}
 			protocol = IPPROTO_UDP;
@@ -151,12 +151,12 @@
 		case SOCK_RAW:
 			if (!suser()) 
 			{
-				kfree_s((void *)sk, sizeof(*sk));
+				sk_free(sk);
 				return(-EPERM);
 			}
 			if (!protocol) 
 			{
-				kfree_s((void *)sk, sizeof(*sk));
+				sk_free(sk);
 				return(-EPROTONOSUPPORT);
 			}
 			prot = &rawv6_prot;
@@ -165,7 +165,7 @@
 			sk->num = protocol;
 			break;
 		default:
-			kfree_s((void *)sk, sizeof(*sk));
+			sk_free(sk);
 			return(-ESOCKTNOSUPPORT);
 	}
 
diff -u --recursive --new-file v2.1.15/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.1.15/linux/net/ipv6/tcp_ipv6.c	Thu Dec 12 19:37:31 1996
+++ linux/net/ipv6/tcp_ipv6.c	Wed Dec 18 12:07:55 1996
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.15 1996/10/29 22:45:53 roque Exp $
+ *	$Id: tcp_ipv6.c,v 1.6 1996/12/12 19:22:18 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -598,7 +598,7 @@
 		return newsk;
 	}
 
-	newsk = (struct sock *) kmalloc(sizeof(struct sock), GFP_ATOMIC);
+	newsk = sk_alloc(GFP_ATOMIC);
 	if (newsk == NULL)
 	{
 		return NULL;
diff -u --recursive --new-file v2.1.15/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v2.1.15/linux/net/ipx/af_ipx.c	Thu Dec 12 19:37:31 1996
+++ linux/net/ipx/af_ipx.c	Mon Dec 16 14:36:16 1996
@@ -403,7 +403,7 @@
 static int
 ipxitf_demux_socket(ipx_interface *intrfc, struct sk_buff *skb, int copy) 
 {
-	ipx_packet	*ipx = (ipx_packet *)(skb->h.raw);
+	struct ipxhdr	*ipx = skb->nh.ipxh;
 	struct sock	*s;
 
 	int is_broadcast = (memcmp(ipx->ipx_dest.node, ipx_broadcast_node,
@@ -467,7 +467,7 @@
 static int
 ipxitf_demux_socket(ipx_interface *intrfc, struct sk_buff *skb, int copy) 
 {
-	ipx_packet	*ipx = (ipx_packet *)(skb->h.raw);
+	struct ipxhdr	*ipx = skb->nh.ipxh;
 	struct sock	*sock1 = NULL, *sock2 = NULL;
 	struct sk_buff	*skb1 = NULL, *skb2 = NULL;
 
@@ -581,6 +581,7 @@
 	skb2 = alloc_skb(len, GFP_ATOMIC);
 	if (skb2 != NULL) {
 		skb_reserve(skb2,out_offset);
+		skb2->nh.raw=
 		skb2->h.raw=skb_put(skb2,skb->len);
 		skb2->arp=1;
 		memcpy(skb2->h.raw, skb->h.raw, skb->len);
@@ -591,7 +592,7 @@
 
 static int ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node)
 {
-	ipx_packet	*ipx = (ipx_packet *)(skb->h.raw);
+	struct ipxhdr	*ipx = skb->nh.ipxh;
 	struct device	*dev = intrfc->if_dev;
 	struct datalink_proto	*dl = intrfc->if_dlink;
 	char		dest_node[IPX_NODE_LEN];
@@ -617,8 +618,10 @@
 	{
 		/*
 		 *	To our own node, loop and free the original.
+		 *	The internal net will receive on all node address.
 		 */
-		if (memcmp(intrfc->if_node, node, IPX_NODE_LEN) == 0) 
+		if ((intrfc == ipx_internal_net)
+		    || memcmp(intrfc->if_node, node, IPX_NODE_LEN) == 0) 
 		{
 			/*
 			 *	Don't charge sender
@@ -695,8 +698,8 @@
 	 *	Now log the packet just before transmission 
 	 */
 	 
-	dump_pkt("IPX snd:", (ipx_packet *)skb->h.raw);
-	dump_data("ETH hdr:", skb->sk, skb->h.raw - skb->sk);
+	dump_pkt("IPX snd:", skb->nh.ipxh);
+	dump_data("ETH hdr:", skb->mac.raw, skb->nh.raw - skb->mac.raw);
 #endif
 
 	/*
@@ -720,7 +723,7 @@
 
 static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
 {
-	ipx_packet	*ipx = (ipx_packet *) (skb->h.raw);
+	struct ipxhdr	*ipx = skb->nh.ipxh;
 	ipx_interface	*i;
 
 #ifdef CONFIG_FIREWALL	
@@ -782,7 +785,7 @@
 #endif
 
 	  c = (char *) skb->data;
-	  c += sizeof( struct ipx_packet );
+	  c += sizeof( struct ipxhdr );
 
 	  l = (long *) c;
 
@@ -1280,7 +1283,7 @@
  
 /* Note: We assume ipx_tctrl==0 and htons(length)==ipx_pktsize */
 
-static __u16 ipx_set_checksum(ipx_packet *packet,int length) 
+static __u16 ipx_set_checksum(struct ipxhdr *packet,int length) 
 {
 	/* 
 	 *	NOTE: sum is a net byte order quantity, which optimizes the 
@@ -1341,7 +1344,7 @@
 {
 	struct sk_buff *skb;
 	ipx_interface *intrfc;
-	ipx_packet *ipx;
+	struct ipxhdr *ipx;
 	int size;
 	int ipx_offset;
 	ipx_route *rt = NULL;
@@ -1363,7 +1366,7 @@
 	}
 	
 	ipx_offset = intrfc->if_ipx_offset;
-	size=sizeof(ipx_packet)+len;
+	size=sizeof(struct ipxhdr)+len;
 	size += ipx_offset;
 
 	skb=sock_alloc_send_skb(sk, size, 0, noblock, &err);
@@ -1375,11 +1378,11 @@
 	skb->sk=sk;
 
 	/* Fill in IPX header */
-	ipx=(ipx_packet *)skb_put(skb,sizeof(ipx_packet));
-	ipx->ipx_pktsize=htons(len+sizeof(ipx_packet));
+	ipx=(struct ipxhdr *)skb_put(skb,sizeof(struct ipxhdr));
+	ipx->ipx_pktsize=htons(len+sizeof(struct ipxhdr));
 	ipx->ipx_tctrl=0;
 	ipx->ipx_type=usipx->sipx_type;
-	skb->h.raw = (unsigned char *)ipx;
+	skb->h.raw = (void *)skb->nh.ipxh = ipx;
 
 	ipx->ipx_source.net = sk->protinfo.af_ipx.intrfc->if_netnum;
 #ifdef CONFIG_IPX_INTERN
@@ -1416,7 +1419,7 @@
 	if(sk->no_check || intrfc->if_dlink_type==IPX_FRAME_8023)
 		ipx->ipx_checksum=0xFFFF;
 	else
-		ipx->ipx_checksum=ipx_set_checksum(ipx, len+sizeof(ipx_packet));
+		ipx->ipx_checksum=ipx_set_checksum(ipx, len+sizeof(struct ipxhdr));
 
 #ifdef CONFIG_FIREWALL	
 	if(call_out_firewall(PF_IPX, skb->dev, ipx, NULL)!=FW_ACCEPT)
@@ -1433,7 +1436,7 @@
 static int
 ipxrtr_route_skb(struct sk_buff *skb)
 {
-	ipx_packet	*ipx = (ipx_packet *) (skb->h.raw);
+	struct ipxhdr	*ipx = skb->nh.ipxh;
 	ipx_route	*r;
 	ipx_interface	*i;
 
@@ -2076,25 +2079,25 @@
 			*(p++) = ' ';
     *p = '\000';
     d += i;
-    printk("%s-%04X: %s\n",str,l*8,b);
+    printk(KERN_DEBUG"%s-%04X: %s\n",str,l*8,b);
   }
 }
 
 void dump_addr(char *str,ipx_address *p) {
-  printk("%s: %08X:%02X%02X%02X%02X%02X%02X:%04X\n",
+  printk(KERN_DEBUG"%s: %08X:%02X%02X%02X%02X%02X%02X:%04X\n",
    str,ntohl(p->net),p->node[0],p->node[1],p->node[2],
    p->node[3],p->node[4],p->node[5],ntohs(p->sock));
 }
 
-void dump_hdr(char *str,ipx_packet *p) {
-  printk("%s: CHKSUM=%04X SIZE=%d (%04X) HOPS=%d (%02X) TYPE=%02X\n",
+void dump_hdr(char *str,struct ipxhdr *p) {
+  printk(KERN_DEBUG"%s: CHKSUM=%04X SIZE=%d (%04X) HOPS=%d (%02X) TYPE=%02X\n",
    str,p->ipx_checksum,ntohs(p->ipx_pktsize),ntohs(p->ipx_pktsize),
    p->ipx_tctrl,p->ipx_tctrl,p->ipx_type);
   dump_addr("  IPX-DST",&p->ipx_dest);
   dump_addr("  IPX-SRC",&p->ipx_source);
 }
 
-void dump_pkt(char *str,ipx_packet *p) {
+void dump_pkt(char *str,struct ipxhdr *p) {
   int len = ntohs(p->ipx_pktsize);
   dump_hdr(str,p);
   if (len > 30)
@@ -2106,13 +2109,12 @@
 {
 	/* NULL here for pt means the packet was looped back */
 	ipx_interface	*intrfc;
-	ipx_packet *ipx;
-	
-	ipx=(ipx_packet *)skb->h.raw;
-	
-	/* Too small */
+	struct ipxhdr *ipx;
+
+	skb->h.raw = (void *)ipx = skb->nh.ipxh;
 	
-	if(ntohs(ipx->ipx_pktsize)<sizeof(ipx_packet)) {
+	/* Too small? */
+	if(ntohs(ipx->ipx_pktsize)<sizeof(struct ipxhdr)) {
 		kfree_skb(skb,FREE_READ);
 		return 0;
 	}
@@ -2208,7 +2210,7 @@
 {
 	struct sock *sk=sock->sk;
 	struct sockaddr_ipx *sipx=(struct sockaddr_ipx *)msg->msg_name;
-	struct ipx_packet *ipx = NULL;
+	struct ipxhdr *ipx = NULL;
 	int copied = 0;
 	int truesize;
 	struct sk_buff *skb;
@@ -2220,9 +2222,9 @@
 	skb=skb_recv_datagram(sk,flags&~MSG_DONTWAIT,flags&MSG_DONTWAIT,&err);
 	if(skb==NULL)
 		return err;
-	
-	ipx = (ipx_packet *)(skb->h.raw);
-	truesize=ntohs(ipx->ipx_pktsize) - sizeof(ipx_packet);
+
+	ipx = skb->nh.ipxh;
+	truesize=ntohs(ipx->ipx_pktsize) - sizeof(struct ipxhdr);
 	
 	copied = truesize;
 	if(copied > size)
@@ -2230,8 +2232,8 @@
 		copied=size;
 		msg->msg_flags|=MSG_TRUNC;
 	}
-	
-	err = skb_copy_datagram_iovec(skb,sizeof(struct ipx_packet),msg->msg_iov,copied);
+
+	err = skb_copy_datagram_iovec(skb,sizeof(struct ipxhdr),msg->msg_iov,copied);
 	
 	if (err)
 		return err;
@@ -2247,6 +2249,7 @@
 		sipx->sipx_type = ipx->ipx_type;
 	}
 	skb_free_datagram(sk, skb);
+
 	return(copied);
 }		
 
@@ -2272,7 +2275,7 @@
 			struct sk_buff *skb;
 			/* These two are safe on a single CPU system as only user tasks fiddle here */
 			if((skb=skb_peek(&sk->receive_queue))!=NULL)
-				amount=skb->len-sizeof(struct ipx_packet);
+				amount=skb->len-sizeof(struct ipxhdr);
 			return put_user(amount, (int *)arg);
 		}
 		case SIOCADDRT:
diff -u --recursive --new-file v2.1.15/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v2.1.15/linux/net/netrom/af_netrom.c	Thu Dec 12 19:37:31 1996
+++ linux/net/netrom/af_netrom.c	Sat Dec 14 13:40:12 1996
@@ -580,7 +580,6 @@
 	sk->priority      = SOPRI_NORMAL;
 	sk->mtu           = NETROM_MTU;	/* 236 */
 	sk->zapped        = 1;
-	sk->window	  = sysctl_netrom_transport_requested_window_size;
 
 	sk->state_change = def_callback1;
 	sk->data_ready   = def_callback2;
@@ -588,8 +587,8 @@
 	sk->error_report = def_callback1;
 
 	if (sock != NULL) {
-		sock->sk = sk;
-		sk->sleep  = &sock->wait;
+		sock->sk  = sk;
+		sk->sleep = &sock->wait;
 	}
 
 	skb_queue_head_init(&nr->ack_queue);
@@ -605,6 +604,7 @@
 	nr->t4       = sysctl_netrom_transport_busy_delay;
 	nr->idle     = sysctl_netrom_transport_no_activity_timeout;
 	nr->paclen   = sysctl_netrom_transport_packet_length;
+	nr->window   = sysctl_netrom_transport_requested_window_size;
 
 	nr->t1timer   = 0;
 	nr->t2timer   = 0;
@@ -669,7 +669,6 @@
 	sk->sndbuf      = osk->sndbuf;
 	sk->debug       = osk->debug;
 	sk->state       = TCP_ESTABLISHED;
-	sk->window      = osk->window;
 	sk->mtu         = osk->mtu;
 	sk->sleep       = osk->sleep;
 	sk->zapped      = osk->zapped;
@@ -690,6 +689,7 @@
 	nr->t4       = osk->protinfo.nr->t4;
 	nr->idle     = osk->protinfo.nr->idle;
 	nr->paclen   = osk->protinfo.nr->paclen;
+	nr->window   = osk->protinfo.nr->window;
 
 	nr->device   = osk->protinfo.nr->device;
 	nr->bpqext   = osk->protinfo.nr->bpqext;
@@ -774,8 +774,8 @@
 			break;
 	}
 
-	sock->sk = NULL;	
-	sk->socket = NULL;	/* Not used, but we should do this. **/
+	sock->sk   = NULL;	
+	sk->socket = NULL;	/* Not used, but we should do this */
 
 	return 0;
 }
@@ -1090,8 +1090,8 @@
 	circuit++;
 
 	/* Window negotiation */
-	if (window < make->window)
-		make->window = window;
+	if (window < make->protinfo.nr->window)
+		make->protinfo.nr->window = window;
 
 	/* L4 timeout negotiation */
 	if (skb->len == 37) {
@@ -1136,7 +1136,7 @@
 	unsigned char *asmptr;
 	int size;
 	
-	if (msg->msg_flags&~MSG_DONTWAIT)
+	if (msg->msg_flags & ~MSG_DONTWAIT)
 		return -EINVAL;
 
 	if (sk->zapped)
@@ -1174,7 +1174,7 @@
 
 	size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
 
-	if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags&MSG_DONTWAIT, &err)) == NULL)
+	if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
 		return err;
 
 	skb->sk   = sk;
@@ -1248,7 +1248,7 @@
 		return -ENOTCONN;
 
 	/* Now we can treat all alike */
-	if ((skb = skb_recv_datagram(sk, flags, msg->msg_flags&MSG_DONTWAIT, &er)) == NULL)
+	if ((skb = skb_recv_datagram(sk, flags, msg->msg_flags & MSG_DONTWAIT, &er)) == NULL)
 		return er;
 
 	if (!sk->protinfo.nr->hdrincl) {
@@ -1272,12 +1272,12 @@
 		memcpy(&addr.sax25_call, skb->data + 7, AX25_ADDR_LEN);
 
 		*sax = addr;
-
 	}
 
 	msg->msg_namelen=sizeof(*sax);
 
 	skb_free_datagram(sk, skb);
+
 	return copied;
 }
 
@@ -1389,7 +1389,7 @@
 			s->protinfo.nr->t2      / PR_SLOWHZ,
 			s->protinfo.nr->n2count, s->protinfo.nr->n2,
 			s->protinfo.nr->rtt     / PR_SLOWHZ,
-			s->window, s->protinfo.nr->paclen,
+			s->protinfo.nr->window, s->protinfo.nr->paclen,
 			s->wmem_alloc, s->rmem_alloc);
 		
 		pos = begin + len;
diff -u --recursive --new-file v2.1.15/linux/net/netrom/nr_dev.c linux/net/netrom/nr_dev.c
--- v2.1.15/linux/net/netrom/nr_dev.c	Thu Dec 12 19:37:31 1996
+++ linux/net/netrom/nr_dev.c	Sat Dec 14 13:40:12 1996
@@ -112,10 +112,11 @@
 
 static int nr_rebuild_header(struct sk_buff *skb)
 {
-	struct device *dev=skb->dev;
+	struct device *dev = skb->dev;
 	struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
 	struct sk_buff *skbn;
-	unsigned char *bp=skb->data;
+	unsigned char *bp = skb->data;
+
 	if (!arp_find(bp + 7, skb)) {
 		kfree_skb(skb, FREE_WRITE);
 		return 1;
diff -u --recursive --new-file v2.1.15/linux/net/netrom/nr_in.c linux/net/netrom/nr_in.c
--- v2.1.15/linux/net/netrom/nr_in.c	Thu Dec 12 19:37:31 1996
+++ linux/net/netrom/nr_in.c	Sat Dec 14 13:40:12 1996
@@ -109,7 +109,7 @@
 			sk->protinfo.nr->vl	    = 0;
 			sk->protinfo.nr->state      = NR_STATE_3;
 			sk->protinfo.nr->n2count    = 0;
-			sk->window                  = skb->data[20];
+			sk->protinfo.nr->window     = skb->data[20];
 			sk->state                   = TCP_ESTABLISHED;
 			/* For WAIT_SABM connections we will produce an accept ready socket here */
 			if (!sk->dead)
@@ -290,7 +290,7 @@
 			/*
 			 * Window is full, ack it immediately.
 			 */
-			if (((sk->protinfo.nr->vl + sk->window) % NR_MODULUS) == sk->protinfo.nr->vr) {
+			if (((sk->protinfo.nr->vl + sk->protinfo.nr->window) % NR_MODULUS) == sk->protinfo.nr->vr) {
 				nr_enquiry_response(sk);
 			} else {
 				if (!(sk->protinfo.nr->condition & ACK_PENDING_CONDITION)) {
diff -u --recursive --new-file v2.1.15/linux/net/netrom/nr_out.c linux/net/netrom/nr_out.c
--- v2.1.15/linux/net/netrom/nr_out.c	Thu Dec 12 19:37:31 1996
+++ linux/net/netrom/nr_out.c	Sat Dec 14 13:40:12 1996
@@ -145,7 +145,7 @@
 	del_timer(&sk->timer);
 
 	start = (skb_peek(&sk->protinfo.nr->ack_queue) == NULL) ? sk->protinfo.nr->va : sk->protinfo.nr->vs;
-	end   = (sk->protinfo.nr->va + sk->window) % NR_MODULUS;
+	end   = (sk->protinfo.nr->va + sk->protinfo.nr->window) % NR_MODULUS;
 
 	if (!(sk->protinfo.nr->condition & PEER_RX_BUSY_CONDITION) &&
 	    start != end                                  &&
diff -u --recursive --new-file v2.1.15/linux/net/netrom/nr_subr.c linux/net/netrom/nr_subr.c
--- v2.1.15/linux/net/netrom/nr_subr.c	Thu Dec 12 19:37:31 1996
+++ linux/net/netrom/nr_subr.c	Sat Dec 14 13:40:12 1996
@@ -131,7 +131,7 @@
 int nr_in_rx_window(struct sock *sk, unsigned short ns)
 {
 	unsigned short vc = sk->protinfo.nr->vr;
-	unsigned short vt = (sk->protinfo.nr->vl + sk->window) % NR_MODULUS;
+	unsigned short vt = (sk->protinfo.nr->vl + sk->protinfo.nr->window) % NR_MODULUS;
 
 	while (vc != vt) {
 		if (ns == vc) return 1;
@@ -188,7 +188,7 @@
 			*dptr++  = 0;
 			*dptr++  = 0;
 			*dptr++  = frametype;
-			*dptr++  = sk->window;
+			*dptr++  = sk->protinfo.nr->window;
 			memcpy(dptr, &sk->protinfo.nr->user_addr, AX25_ADDR_LEN);
 			dptr[6] &= ~LAPB_C;
 			dptr[6] &= ~LAPB_E;
@@ -209,7 +209,7 @@
 			*dptr++ = sk->protinfo.nr->my_index;
 			*dptr++ = sk->protinfo.nr->my_id;
 			*dptr++ = frametype;
-			*dptr++ = sk->window;
+			*dptr++ = sk->protinfo.nr->window;
 			if (sk->protinfo.nr->bpqext) *dptr++ = sysctl_netrom_network_ttl_initialiser;
 			break;
 
diff -u --recursive --new-file v2.1.15/linux/net/netsyms.c linux/net/netsyms.c
--- v2.1.15/linux/net/netsyms.c	Thu Dec 12 19:37:31 1996
+++ linux/net/netsyms.c	Sat Dec 14 14:25:26 1996
@@ -88,10 +88,13 @@
 	X(sk_free),
 	X(sock_wake_async),
 	X(sock_alloc_send_skb),
+	X(sock_rfree),
+	X(sock_wfree),
 	X(skb_recv_datagram),
 	X(skb_free_datagram),
 	X(skb_copy_datagram),
 	X(skb_copy_datagram_iovec),
+	X(skb_realloc_headroom),
 	X(datagram_select),
 
 	/* ?? needed by smbfs.o */
@@ -119,6 +122,8 @@
 	X(arp_send),
 	X(ip_id_count),
 	X(ip_send_check),
+	X(ip_fragment),
+	X(ip_dev_find_tunnel),
 	X(inet_family_ops),
 
 	X(__scm_send),
diff -u --recursive --new-file v2.1.15/linux/net/rose/af_rose.c linux/net/rose/af_rose.c
--- v2.1.15/linux/net/rose/af_rose.c	Thu Dec 12 19:37:31 1996
+++ linux/net/rose/af_rose.c	Sat Dec 14 13:40:12 1996
@@ -55,6 +55,7 @@
 int sysctl_rose_reset_request_timeout   = ROSE_DEFAULT_T2;
 int sysctl_rose_clear_request_timeout   = ROSE_DEFAULT_T3;
 int sysctl_rose_no_activity_timeout     = ROSE_DEFAULT_IDLE;
+int sysctl_rose_ack_hold_back_timeout   = ROSE_DEFAULT_HB;
 int sysctl_rose_routing_control         = 1;
 
 static unsigned int lci = 1;
@@ -389,6 +390,14 @@
 	  		restore_flags(flags);
 	  		break;
 
+	  	case ROSE_HOLDBACK:
+	  		if (rose_ctl.arg < 1) 
+	  			return -EINVAL;
+	  		save_flags(flags); cli();
+	  		sk->protinfo.rose->hb = rose_ctl.arg * PR_SLOWHZ;
+	  		restore_flags(flags);
+	  		break;
+
 	  	case ROSE_IDLE:
 	  		if (rose_ctl.arg < 1) 
 	  			return -EINVAL;
@@ -449,6 +458,12 @@
 			sk->protinfo.rose->t3 = opt * PR_SLOWHZ;
 			return 0;
 			
+		case ROSE_HOLDBACK:
+			if (opt < 1)
+				return -EINVAL;
+			sk->protinfo.rose->hb = opt * PR_SLOWHZ;
+			return 0;
+			
 		case ROSE_IDLE:
 			if (opt < 1)
 				return -EINVAL;
@@ -496,6 +511,10 @@
 			val = sk->protinfo.rose->t3 / PR_SLOWHZ;
 			break;
 						
+		case ROSE_HOLDBACK:
+			val = sk->protinfo.rose->hb / PR_SLOWHZ;
+			break;
+						
 		case ROSE_IDLE:
 			val = sk->protinfo.rose->idle / (PR_SLOWHZ * 60);
 			break;
@@ -583,7 +602,6 @@
 	sk->priority      = SOPRI_NORMAL;
 	sk->mtu           = ROSE_MTU;	/* 128 */
 	sk->zapped        = 1;
-	sk->window	  = ROSE_DEFAULT_WINDOW;
 
 	sk->state_change = def_callback1;
 	sk->data_ready   = def_callback2;
@@ -591,7 +609,7 @@
 	sk->error_report = def_callback1;
 
 	if (sock != NULL) {
-		sock->sk = sk;
+		sock->sk  = sk;
 		sk->sleep = &sock->wait;
 	}
 
@@ -603,6 +621,7 @@
 	rose->t1       = sysctl_rose_call_request_timeout;
 	rose->t2       = sysctl_rose_reset_request_timeout;
 	rose->t3       = sysctl_rose_clear_request_timeout;
+	rose->hb       = sysctl_rose_ack_hold_back_timeout;
 	rose->idle     = sysctl_rose_no_activity_timeout;
 
 	rose->timer    = 0;
@@ -664,7 +683,6 @@
 	sk->sndbuf      = osk->sndbuf;
 	sk->debug       = osk->debug;
 	sk->state       = TCP_ESTABLISHED;
-	sk->window      = osk->window;
 	sk->mtu         = osk->mtu;
 	sk->sleep       = osk->sleep;
 	sk->zapped      = osk->zapped;
@@ -680,6 +698,7 @@
 	rose->t1       = osk->protinfo.rose->t1;
 	rose->t2       = osk->protinfo.rose->t2;
 	rose->t3       = osk->protinfo.rose->t3;
+	rose->hb       = osk->protinfo.rose->hb;
 	rose->idle     = osk->protinfo.rose->idle;
 
 	rose->device   = osk->protinfo.rose->device;
@@ -1073,7 +1092,7 @@
 	unsigned char *asmptr;
 	int size;
 	
-	if (msg->msg_flags&~MSG_DONTWAIT)
+	if (msg->msg_flags & ~MSG_DONTWAIT)
 		return -EINVAL;
 
 	if (sk->zapped)
@@ -1087,7 +1106,7 @@
 	if (sk->protinfo.rose->device == NULL)
 		return -ENETUNREACH;
 		
-	if (usrose) {
+	if (usrose != NULL) {
 		if (msg->msg_namelen < sizeof(srose))
 			return -EINVAL;
 		srose = *usrose;
@@ -1124,8 +1143,7 @@
 
 	size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN;
 
-	if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags&MSG_DONTWAIT,
-			&err)) == NULL)
+	if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
 		return err;
 
 	skb->sk   = sk;
@@ -1196,7 +1214,7 @@
 		return -ENOTCONN;
 
 	/* Now we can treat all alike */
-	if ((skb = skb_recv_datagram(sk, flags, flags&MSG_DONTWAIT, &er)) == NULL)
+	if ((skb = skb_recv_datagram(sk, flags, msg->msg_flags & MSG_DONTWAIT, &er)) == NULL)
 		return er;
 
 	if (!sk->protinfo.rose->hdrincl) {
@@ -1227,9 +1245,9 @@
 		}
 
 		*srose = addr;
-
 	}
-	msg->msg_namelen=sizeof(*srose);
+
+	msg->msg_namelen = sizeof(struct sockaddr_rose);
 
 	skb_free_datagram(sk, skb);
 
@@ -1319,7 +1337,7 @@
   
 	cli();
 
-	len += sprintf(buffer, "dest_addr  dest_call dest_digi src_addr   src_call  src_digi  dev   lci st vs vr va   t  t1  t2  t3 Snd-Q Rcv-Q\n");
+	len += sprintf(buffer, "dest_addr  dest_call dest_digi src_addr   src_call  src_digi  dev   lci st vs vr va   t  t1  t2  t3  hb  Snd-Q Rcv-Q\n");
 
 	for (s = rose_list; s != NULL; s = s->next) {
 		if ((dev = s->protinfo.rose->device) == NULL)
@@ -1341,7 +1359,7 @@
 		len += sprintf(buffer + len, "%-10s %-9s ",
 			rose2asc(&s->protinfo.rose->source_addr),
 			callsign);
-		len += sprintf(buffer + len, "%-9s %-5s %3.3X  %d  %d  %d  %d %3d %3d %3d %3d %5d %5d\n",
+		len += sprintf(buffer + len, "%-9s %-5s %3.3X  %d  %d  %d  %d %3d %3d %3d %3d %3d %5d %5d\n",
 			ax2asc(&s->protinfo.rose->source_digi),
 			devname,  s->protinfo.rose->lci & 0x0FFF,
 			s->protinfo.rose->state,
@@ -1350,6 +1368,7 @@
 			s->protinfo.rose->t1    / PR_SLOWHZ,
 			s->protinfo.rose->t2    / PR_SLOWHZ,
 			s->protinfo.rose->t3    / PR_SLOWHZ,
+			s->protinfo.rose->hb    / PR_SLOWHZ,
 			s->wmem_alloc, s->rmem_alloc);
 		
 		pos = begin + len;
diff -u --recursive --new-file v2.1.15/linux/net/rose/rose_dev.c linux/net/rose/rose_dev.c
--- v2.1.15/linux/net/rose/rose_dev.c	Thu Dec 12 19:37:31 1996
+++ linux/net/rose/rose_dev.c	Sat Dec 14 13:40:12 1996
@@ -93,7 +93,7 @@
 
 static int rose_rebuild_header(struct sk_buff *skb)
 {
-	struct device *dev=skb->dev;
+	struct device *dev = skb->dev;
 	struct enet_statistics *stats = (struct enet_statistics *)dev->priv;
 	unsigned char *bp = (unsigned char *)skb->data;
 	struct sk_buff *skbn;
diff -u --recursive --new-file v2.1.15/linux/net/rose/rose_in.c linux/net/rose/rose_in.c
--- v2.1.15/linux/net/rose/rose_in.c	Thu Dec 12 19:37:31 1996
+++ linux/net/rose/rose_in.c	Sat Dec 14 13:40:12 1996
@@ -94,13 +94,14 @@
 	switch (frametype) {
 
 		case ROSE_CALL_ACCEPTED:
-			sk->protinfo.rose->timer = 0;
-			sk->protinfo.rose->vs    = 0;
-			sk->protinfo.rose->va    = 0;
-			sk->protinfo.rose->vr    = 0;
-			sk->protinfo.rose->vl    = 0;
-			sk->protinfo.rose->state = ROSE_STATE_3;
-			sk->state                = TCP_ESTABLISHED;
+			sk->protinfo.rose->condition = 0x00;
+			sk->protinfo.rose->timer     = 0;
+			sk->protinfo.rose->vs        = 0;
+			sk->protinfo.rose->va        = 0;
+			sk->protinfo.rose->vr        = 0;
+			sk->protinfo.rose->vl        = 0;
+			sk->protinfo.rose->state     = ROSE_STATE_3;
+			sk->state                    = TCP_ESTABLISHED;
 			if (!sk->dead)
 				sk->state_change(sk);
 			break;
@@ -167,6 +168,7 @@
 			rose_clear_queues(sk);
 			rose_write_internal(sk, ROSE_RESET_CONFIRMATION);
 			sk->protinfo.rose->condition = 0x00;
+			sk->protinfo.rose->timer     = 0;
 			sk->protinfo.rose->vs        = 0;
 			sk->protinfo.rose->vr        = 0;
 			sk->protinfo.rose->va        = 0;
@@ -241,10 +243,17 @@
 				}
 			}
 			/*
-			 * If the window is full, ack the frame.
+			 * If the window is full, ack the frame, else start the
+			 * acknowledge hold back timer.
 			 */
-			if (((sk->protinfo.rose->vl + sk->window) % ROSE_MODULUS) == sk->protinfo.rose->vr)
+			if (((sk->protinfo.rose->vl + ROSE_DEFAULT_WINDOW) % ROSE_MODULUS) == sk->protinfo.rose->vr) {
+				sk->protinfo.rose->condition &= ~ACK_PENDING_CONDITION;
+				sk->protinfo.rose->timer      = 0;
 				rose_enquiry_response(sk);
+			} else {
+				sk->protinfo.rose->condition |= ACK_PENDING_CONDITION;
+				sk->protinfo.rose->timer      = sk->protinfo.rose->hb;
+			}
 			break;
 
 		default:
diff -u --recursive --new-file v2.1.15/linux/net/rose/rose_link.c linux/net/rose/rose_link.c
--- v2.1.15/linux/net/rose/rose_link.c	Thu Dec 12 19:37:32 1996
+++ linux/net/rose/rose_link.c	Sat Dec 14 13:40:12 1996
@@ -165,7 +165,7 @@
 	*dptr++ = 0x00;
 	*dptr++ = 0;
 
-	skb->sk   = NULL;
+	skb->sk = NULL;
 
 	if (!ax25_send_frame(skb, (ax25_address *)neigh->dev->dev_addr, &neigh->callsign, neigh->digipeat, neigh->dev))
 		kfree_skb(skb, FREE_WRITE);
@@ -194,7 +194,7 @@
 	*dptr++ = 0x00;
 	*dptr++ = ROSE_RESTART_CONFIRMATION;
 
-	skb->sk   = NULL;
+	skb->sk = NULL;
 
 	if (!ax25_send_frame(skb, (ax25_address *)neigh->dev->dev_addr, &neigh->callsign, neigh->digipeat, neigh->dev))
 		kfree_skb(skb, FREE_WRITE);
@@ -224,7 +224,7 @@
 	*dptr++ = ROSE_DIAGNOSTIC;
 	*dptr++ = diag;
 
-	skb->sk   = NULL;
+	skb->sk = NULL;
 
 	if (!ax25_send_frame(skb, (ax25_address *)neigh->dev->dev_addr, &neigh->callsign, neigh->digipeat, neigh->dev))
 		kfree_skb(skb, FREE_WRITE);
@@ -256,7 +256,7 @@
 	*dptr++ = cause;
 	*dptr++ = 0x00;
 
-	skb->sk   = NULL;
+	skb->sk = NULL;
 
 	if (!ax25_send_frame(skb, (ax25_address *)neigh->dev->dev_addr, &neigh->callsign, neigh->digipeat, neigh->dev))
 		kfree_skb(skb, FREE_WRITE);
@@ -277,7 +277,7 @@
 	dptr = skb_push(skb, 1);
 	*dptr++ = AX25_P_ROSE;
 
-	skb->arp  = 1;
+	skb->arp = 1;
 
 	if (neigh->restarted) {
 		if (!ax25_send_frame(skb, (ax25_address *)neigh->dev->dev_addr, &neigh->callsign, neigh->digipeat, neigh->dev))
diff -u --recursive --new-file v2.1.15/linux/net/rose/rose_out.c linux/net/rose/rose_out.c
--- v2.1.15/linux/net/rose/rose_out.c	Thu Dec 12 19:37:32 1996
+++ linux/net/rose/rose_out.c	Sat Dec 14 13:40:34 1996
@@ -114,7 +114,7 @@
 	del_timer(&sk->timer);
 
 	start = (skb_peek(&sk->protinfo.rose->ack_queue) == NULL) ? sk->protinfo.rose->va : sk->protinfo.rose->vs;
-	end   = (sk->protinfo.rose->va + sk->window) % ROSE_MODULUS;
+	end   = (sk->protinfo.rose->va + ROSE_DEFAULT_WINDOW) % ROSE_MODULUS;
 
 	if (!(sk->protinfo.rose->condition & PEER_RX_BUSY_CONDITION) &&
 	    start != end                                  &&
diff -u --recursive --new-file v2.1.15/linux/net/rose/rose_timer.c linux/net/rose/rose_timer.c
--- v2.1.15/linux/net/rose/rose_timer.c	Thu Dec 12 17:02:48 1996
+++ linux/net/rose/rose_timer.c	Sat Dec 14 13:40:34 1996
@@ -104,7 +104,9 @@
 			 */
 			if (sk->rmem_alloc < (sk->rcvbuf / 2) && (sk->protinfo.rose->condition & OWN_RX_BUSY_CONDITION)) {
 				sk->protinfo.rose->condition &= ~OWN_RX_BUSY_CONDITION;
+				sk->protinfo.rose->condition &= ~ACK_PENDING_CONDITION;
 				sk->protinfo.rose->vl         = sk->protinfo.rose->vr;
+				sk->protinfo.rose->timer      = 0;
 				rose_write_internal(sk, ROSE_RR);
 				break;
 			}
@@ -124,10 +126,17 @@
 	}
 
 	/*
-	 * Timer has expired, it may have been T1, T2, or T3. We can tell
+	 * Timer has expired, it may have been T1, T2, T3 or HB. We can tell
 	 * by the socket state.
 	 */
 	switch (sk->protinfo.rose->state) {
+		case ROSE_STATE_3:	/* HB */
+			if (sk->protinfo.rose->condition & ACK_PENDING_CONDITION) {
+				sk->protinfo.rose->condition &= ~ACK_PENDING_CONDITION;
+				rose_enquiry_response(sk);
+			}
+			break;
+
 		case ROSE_STATE_1:	/* T1 */
 		case ROSE_STATE_4:	/* T2 */
 			rose_write_internal(sk, ROSE_CLEAR_REQUEST);
diff -u --recursive --new-file v2.1.15/linux/net/rose/sysctl_net_rose.c linux/net/rose/sysctl_net_rose.c
--- v2.1.15/linux/net/rose/sysctl_net_rose.c	Tue Nov 12 15:56:17 1996
+++ linux/net/rose/sysctl_net_rose.c	Sat Dec 14 13:40:34 1996
@@ -35,6 +35,9 @@
         {NET_ROSE_NO_ACTIVITY_TIMEOUT, "no_activity_timeout",
          &sysctl_rose_no_activity_timeout, sizeof(int), 0644, NULL,
          &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_idle, &max_idle},
+        {NET_ROSE_ACK_HOLD_BACK_TIMEOUT, "acknowledge_hold_back_timeout",
+         &sysctl_rose_ack_hold_back_timeout, sizeof(int), 0644, NULL,
+         &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_timer, &max_timer},
         {NET_ROSE_ROUTING_CONTROL, "routing_control",
          &sysctl_rose_routing_control, sizeof(int), 0644, NULL,
          &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_route, &max_route},
diff -u --recursive --new-file v2.1.15/linux/net/socket.c linux/net/socket.c
--- v2.1.15/linux/net/socket.c	Thu Dec 12 19:37:32 1996
+++ linux/net/socket.c	Wed Dec 18 12:07:56 1996
@@ -295,8 +295,7 @@
 	iput(sock->inode);
 }
 
-int
-sock_sendmsg(struct socket *sock, struct msghdr *msg, int size)
+int sock_sendmsg(struct socket *sock, struct msghdr *msg, int size)
 {
 	int err;
 	struct scm_cookie scm;
@@ -315,8 +314,7 @@
 	return err;
 }
 
-int
-sock_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags)
+int sock_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags)
 {
 	struct scm_cookie scm;
 
@@ -361,8 +359,6 @@
 
 	sock = socki_lookup(inode); 
   
-	if (size<0)
-		return -EINVAL;
 	if (size==0)		/* Match SYS5 behaviour */
 		return 0;
 	if ((err=verify_area(VERIFY_WRITE,ubuf,size))<0)
@@ -396,8 +392,6 @@
 	
 	sock = socki_lookup(inode); 
 
-	if(size<0)
-		return -EINVAL;
 	if(size==0)		/* Match SYS5 behaviour */
 		return 0;
 	
@@ -955,8 +949,6 @@
 	if (!(sock = sockfd_lookup(fd,&err)))
 		return err;
 
-	if(len<0)
-		return -EINVAL;
 	err=verify_area(VERIFY_READ,buff,len);
 	if(err)
 	  	return err;
@@ -964,17 +956,17 @@
 	iov.iov_base=buff;
 	iov.iov_len=len;
 	msg.msg_name=NULL;
-	msg.msg_namelen=0;
 	msg.msg_iov=&iov;
 	msg.msg_iovlen=1;
 	msg.msg_control=NULL;
 	msg.msg_controllen=0;
-	if (addr_len) {
+	msg.msg_namelen=addr_len;
+	if(addr)
+	{
 		err=move_addr_to_kernel(addr,addr_len,address);
 		if (err < 0)
 			return err;
 		msg.msg_name=address;
-		msg.msg_namelen=addr_len;
 	}
 	  	
 	if (current->files->fd[fd]->f_flags & O_NONBLOCK)
@@ -999,8 +991,6 @@
 	if (!(sock = sockfd_lookup(fd, &err))) 
 		return err;
 		
-	if(size<0)
-		return -EINVAL;
 	if(size==0)
 		return 0;
 	err=verify_area(VERIFY_WRITE, ubuf, size);
@@ -1036,8 +1026,6 @@
 
 	if (!(sock = sockfd_lookup(fd, &err)))
 	  	return err;
-	if (size<0)
-		return -EINVAL;
 	if (size==0)
 		return 0;
 
@@ -1053,14 +1041,16 @@
   	iov.iov_base=ubuf;
   	msg.msg_name=address;
   	msg.msg_namelen=MAX_SOCK_ADDR;
-	size=sock_recvmsg(sock, &msg, size,
+	err=sock_recvmsg(sock, &msg, size,
 			  (current->files->fd[fd]->f_flags & O_NONBLOCK) ? (flags | MSG_DONTWAIT) : flags);
 
-	if(size<0)
-	 	return size;
+	if(err<0)
+	 	return err;
+	size=err;
+	
 	if(addr!=NULL && (err=move_addr_to_user(address, msg.msg_namelen, addr, addr_len))<0)
 	  	return err;
-
+	
 	return size;
 }
 
diff -u --recursive --new-file v2.1.15/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.1.15/linux/net/unix/af_unix.c	Thu Dec 12 19:37:32 1996
+++ linux/net/unix/af_unix.c	Wed Dec 18 11:35:55 1996
@@ -855,7 +855,7 @@
 		newsk->protinfo.af_unix.inode=sk->protinfo.af_unix.inode;
 	}
 		
-	do
+	for (;;)
 	{
 		skb=skb_dequeue(&sk->receive_queue);
 		if(skb==NULL)
@@ -865,15 +865,17 @@
 			interruptible_sleep_on(sk->sleep);
 			if(current->signal & ~current->blocked)
 				return -ERESTARTSYS;
+			continue;
 		}
 		if (!(UNIXCB(skb).attr & MSG_SYN))
 		{
 			tsk=skb->sk;
 			tsk->state_change(tsk);
 			kfree_skb(skb, FREE_WRITE);
-			skb = NULL;
+			continue;
 		}
-	} while(skb==NULL);
+		break;
+	}
 
 	tsk=skb->sk;
 	sk->ack_backlog--;
diff -u --recursive --new-file v2.1.15/linux/net/x25/Makefile linux/net/x25/Makefile
--- v2.1.15/linux/net/x25/Makefile	Thu Jan  1 02:00:00 1970
+++ linux/net/x25/Makefile	Wed Dec 18 12:07:56 1996
@@ -0,0 +1,17 @@
+#
+# Makefile for the Linux X.25 Packet layer.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+O_TARGET := x25.o
+O_OBJS	 := af_x25.o sysctl_net_x25.o x25_dev.o x25_in.o x25_link.o x25_out.o x25_route.o x25_subr.o x25_timer.o
+M_OBJS   := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
+
+tar:
+		tar -cvf /dev/f1 .
diff -u --recursive --new-file v2.1.15/linux/net/x25/af_x25.c linux/net/x25/af_x25.c
--- v2.1.15/linux/net/x25/af_x25.c	Thu Jan  1 02:00:00 1970
+++ linux/net/x25/af_x25.c	Wed Dec 18 12:07:56 1996
@@ -0,0 +1,1381 @@
+/*
+ *	X.25 Packet Layer release 001
+ *
+ *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
+ *	releases, misbehave and/or generally screw up. It might even work. 
+ *
+ *	This code REQUIRES 2.1.15 or higher
+ *
+ *	This module:
+ *		This module 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.
+ *
+ *	History
+ *	X.25 001	Jonathan Naylor	Started coding.
+ */
+  
+#include <linux/config.h>
+#if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/stat.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <linux/fcntl.h>
+#include <linux/termios.h>	/* For TIOCINQ/OUTQ */
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <linux/proc_fs.h>
+#include <linux/if_arp.h>
+#include <net/x25.h>
+
+int sysctl_x25_restart_request_timeout = X25_DEFAULT_T20;
+int sysctl_x25_call_request_timeout    = X25_DEFAULT_T21;
+int sysctl_x25_reset_request_timeout   = X25_DEFAULT_T22;
+int sysctl_x25_clear_request_timeout   = X25_DEFAULT_T23;
+int sysctl_x25_ack_holdback_timeout    = X25_DEFAULT_T2;
+
+static unsigned int lci = 1;
+
+struct proto_ops x25_proto_ops;
+
+static struct sock *volatile x25_list = NULL;
+
+int x25_addr_ntoa(unsigned char *p, x25_address *called_addr, x25_address *calling_addr)
+{
+	int called_len, calling_len;
+	char *called, *calling;
+	int i;
+
+	called_len  = (*p >> 0) & 0x0F;
+	calling_len = (*p >> 4) & 0x0F;
+
+	called  = called_addr->x25_addr;
+	calling = calling_addr->x25_addr;
+	p++;
+
+	for (i = 0; i < (called_len + calling_len); i++) {
+		if (i < called_len) {
+			if (i % 2 != 0) {
+				*called++ = ((*p >> 0) & 0x0F) + '0';
+				p++;
+			} else {
+				*called++ = ((*p >> 4) & 0x0F) + '0';
+			}
+		} else {
+			if (i % 2 != 0) {
+				*calling++ = ((*p >> 0) & 0x0F) + '0';
+				p++;
+			} else {
+				*calling++ = ((*p >> 4) & 0x0F) + '0';
+			}
+		}
+	}
+
+	*called  = '\0';
+	*calling = '\0';
+
+	return 1 + (called_len + calling_len + 1) / 2;
+}
+
+int x25_addr_aton(unsigned char *p, x25_address *called_addr, x25_address *calling_addr)
+{
+	unsigned int called_len, calling_len;
+	char *called, *calling;
+	int i;
+
+	called  = called_addr->x25_addr;
+	calling = calling_addr->x25_addr;
+
+	called_len  = strlen(called);
+	calling_len = strlen(calling);
+	
+	*p++ = (calling_len << 4) | (called_len << 0);
+	
+	for (i = 0; i < (called_len + calling_len); i++) {
+		if (i < called_len) {
+			if (i % 2 != 0) {
+				*p |= (*called++ - '0') << 0;
+				p++;
+				*p = 0x00;
+			} else {
+				*p |= (*called++ - '0') << 4;
+			}
+		} else {
+			if (i % 2 != 0) {
+				*p |= (*calling++ - '0') << 0;
+				p++;
+				*p = 0x00;
+			} else {
+				*p |= (*calling++ - '0') << 4;
+			}
+		}
+	}
+	
+	return 1 + (called_len + calling_len + 1) / 2;
+}
+
+/*
+ *	Socket removal during an interrupt is now safe.
+ */
+static void x25_remove_socket(struct sock *sk)
+{
+	struct sock *s;
+	unsigned long flags;
+	
+	save_flags(flags);
+	cli();
+
+	if ((s = x25_list) == sk) {
+		x25_list = s->next;
+		restore_flags(flags);
+		return;
+	}
+
+	while (s != NULL && s->next != NULL) {
+		if (s->next == sk) {
+			s->next = sk->next;
+			restore_flags(flags);
+			return;
+		}
+
+		s = s->next;
+	}
+
+	restore_flags(flags);
+}
+
+/*
+ *	Kill all bound sockets on a dropped device.
+ */
+static void x25_kill_by_device(struct device *dev)
+{
+	struct sock *s;
+	
+	for (s = x25_list; s != NULL; s = s->next) {
+		if (s->protinfo.x25->neighbour->dev == dev) {
+			s->protinfo.x25->state  = X25_STATE_0;
+			s->state                = TCP_CLOSE;
+			s->err                  = ENETUNREACH;
+			s->shutdown            |= SEND_SHUTDOWN;
+			s->state_change(s);
+			s->dead                 = 1;
+		}
+	}
+}
+
+/*
+ *	Handle device status changes.
+ */
+static int x25_device_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+	struct device *dev = (struct device *)ptr;
+
+	if (dev->type == ARPHRD_X25 || dev->type == ARPHRD_ETHER) {
+		switch (event) {
+			case NETDEV_UP:
+				x25_link_device_up(dev);
+				break;
+			case NETDEV_DOWN:
+				x25_kill_by_device(dev);
+				x25_route_device_down(dev);
+				x25_link_device_down(dev);
+				break;
+		}
+	}
+
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Add a socket to the bound sockets list.
+ */
+static void x25_insert_socket(struct sock *sk)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+
+	sk->next = x25_list;
+	x25_list  = sk;
+
+	restore_flags(flags);
+}
+
+/*
+ *	Find a socket that wants to accept the Call Request we just
+ *	received.
+ */
+static struct sock *x25_find_listener(x25_address *addr)
+{
+	unsigned long flags;
+	struct sock *s;
+
+	save_flags(flags);
+	cli();
+
+	for (s = x25_list; s != NULL; s = s->next) {
+		if (strcmp(s->protinfo.x25->source_addr.x25_addr, addr->x25_addr) == 0 && s->state == TCP_LISTEN) {
+			restore_flags(flags);
+			return s;
+		}
+	}
+
+	restore_flags(flags);
+	return NULL;
+}
+
+/*
+ *	Find a connected X.25 socket given my LCI.
+ */
+struct sock *x25_find_socket(unsigned int lci)
+{
+	struct sock *s;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+
+	for (s = x25_list; s != NULL; s = s->next) {
+		if (s->protinfo.x25->lci == lci) {
+			restore_flags(flags);
+			return s;
+		}
+	}
+
+	restore_flags(flags);
+	return NULL;
+}
+
+/*
+ *	Find a unique LCI for a given device.
+ */
+unsigned int x25_new_lci(void)
+{
+	lci++;
+	if (lci > 4095) lci = 1;
+
+	while (x25_find_socket(lci) != NULL) {
+		lci++;
+		if (lci > 4095) lci = 1;
+	}
+
+	return lci;
+}
+
+/*
+ *	Deferred destroy.
+ */
+void x25_destroy_socket(struct sock *);
+
+/*
+ *	Handler for deferred kills.
+ */
+static void x25_destroy_timer(unsigned long data)
+{
+	x25_destroy_socket((struct sock *)data);
+}
+
+/*
+ *	This is called from user mode and the timers. Thus it protects itself against
+ *	interrupt users but doesn't worry about being called during work.
+ *	Once it is removed from the queue no interrupt or bottom half will
+ *	touch it and we are (fairly 8-) ) safe.
+ */
+void x25_destroy_socket(struct sock *sk)	/* Not static as it's used by the timer */
+{
+	struct sk_buff *skb;
+	unsigned long flags;
+	
+	save_flags(flags);
+	cli();
+	
+	del_timer(&sk->timer);
+	
+	x25_remove_socket(sk);
+	x25_clear_queues(sk);		/* Flush the queues */
+	
+	while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
+		if (skb->sk != sk) {		/* A pending connection */
+			skb->sk->dead = 1;	/* Queue the unaccepted socket for death */
+			x25_set_timer(skb->sk);
+			skb->sk->protinfo.x25->state = X25_STATE_0;
+		}
+
+		kfree_skb(skb, FREE_READ);
+	}
+	
+	if (sk->wmem_alloc || sk->rmem_alloc) { /* Defer: outstanding buffers */
+		init_timer(&sk->timer);
+		sk->timer.expires  = jiffies + 10 * HZ;
+		sk->timer.function = x25_destroy_timer;
+		sk->timer.data     = (unsigned long)sk;
+		add_timer(&sk->timer);
+	} else {
+		kfree_s(sk->protinfo.x25, sizeof(*sk->protinfo.x25));
+		sk_free(sk);
+		MOD_DEC_USE_COUNT;
+	}
+
+	restore_flags(flags);
+}
+
+/*
+ *	Handling for system calls applied via the various interfaces to a
+ *	X.25 socket object.
+ */
+ 
+static int x25_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+	return -EINVAL;
+}
+
+static int x25_setsockopt(struct socket *sock, int level, int optname,
+	char *optval, int optlen)
+{
+	struct sock *sk;
+	int err, opt;
+
+	sk = (struct sock *)sock->sk;
+	
+	if (level != SOL_X25)
+		return -EOPNOTSUPP;
+
+	if (optval == NULL)
+		return -EINVAL;
+
+	if ((err = verify_area(VERIFY_READ, optval, sizeof(int))) != 0)
+		return err;
+
+	get_user(opt, (int *)optval);
+	
+	switch (optname) {
+		case X25_QBITINCL:
+			sk->protinfo.x25->qbitincl = opt ? 1 : 0;
+			return 0;
+
+		case X25_PACKET_SIZE:
+			if (sk->state != TCP_LISTEN)
+				return -EINVAL;
+			if (opt < X25_PS16 || opt > X25_PS4096)
+				return -EINVAL;
+			sk->protinfo.x25->facilities.packet_size = opt;
+			return 0;
+
+		case X25_WINDOW_SIZE:
+			if (sk->state != TCP_LISTEN)
+				return -EINVAL;
+			if (sk->protinfo.x25->neighbour->extended) {
+				if (opt < 1 || opt > 127)
+					return -EINVAL;
+			} else {
+				if (opt < 1 || opt > 7)
+					return -EINVAL;
+			}
+			sk->protinfo.x25->facilities.window_size = opt;
+			return 0;
+
+		case X25_THROUGHPUT_SPEED:
+			if (sk->state != TCP_LISTEN)
+				return -EINVAL;
+			if (opt < 0x03 || opt > 0x2C)
+				return -EINVAL;
+			sk->protinfo.x25->facilities.throughput = opt;
+			return 0;
+
+		case X25_REVERSE_CHARGE:
+			if (sk->state != TCP_LISTEN)
+				return -EINVAL;
+			if (opt != 0 && opt != 1)
+				return -EINVAL;
+			sk->protinfo.x25->facilities.reverse = opt;
+			return 0;
+
+		default:
+			return -ENOPROTOOPT;
+	}
+}
+
+static int x25_getsockopt(struct socket *sock, int level, int optname,
+	char *optval, int *optlen)
+{
+	struct sock *sk;
+	int val = 0;
+	int err; 
+
+	sk = (struct sock *)sock->sk;
+	
+	if (level != SOL_X25)
+		return -EOPNOTSUPP;
+	
+	switch (optname) {
+		case X25_QBITINCL:
+			val = sk->protinfo.x25->qbitincl;
+			break;
+
+		case X25_PACKET_SIZE:
+			val = sk->protinfo.x25->facilities.packet_size;
+			break;
+			
+		case X25_WINDOW_SIZE:
+			val = sk->protinfo.x25->facilities.window_size;
+			break;
+
+		case X25_THROUGHPUT_SPEED:
+			val = sk->protinfo.x25->facilities.throughput;
+			break;
+
+		case X25_REVERSE_CHARGE:
+			val = sk->protinfo.x25->facilities.reverse;
+			break;
+
+		default:
+			return -ENOPROTOOPT;
+	}
+
+	if ((err = verify_area(VERIFY_WRITE, optlen, sizeof(int))) != 0)
+		return err;
+
+	put_user(sizeof(int), (unsigned long *)optlen);
+
+	if ((err = verify_area(VERIFY_WRITE, optval, sizeof(int))) != 0)
+		return err;
+
+	put_user(val, (unsigned long *)optval);
+
+	return 0;
+}
+
+static int x25_listen(struct socket *sock, int backlog)
+{
+	struct sock *sk = (struct sock *)sock->sk;
+
+	if (sk->state != TCP_LISTEN) {
+		memset(&sk->protinfo.x25->dest_addr, '\0', X25_ADDR_LEN);
+		sk->max_ack_backlog = backlog;
+		sk->state           = TCP_LISTEN;
+		return 0;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static void def_callback1(struct sock *sk)
+{
+	if (!sk->dead)
+		wake_up_interruptible(sk->sleep);
+}
+
+static void def_callback2(struct sock *sk, int len)
+{
+	if (!sk->dead)
+		wake_up_interruptible(sk->sleep);
+}
+
+static struct sock *x25_alloc_socket(void)
+{
+	struct sock *sk;
+	x25_cb *x25;
+
+	if ((sk = sk_alloc(GFP_ATOMIC)) == NULL)
+		return NULL;
+
+	if ((x25 = (x25_cb *)kmalloc(sizeof(*x25), GFP_ATOMIC)) == NULL) {
+		sk_free(sk);
+		return NULL;
+	}
+
+	x25->sk          = sk;
+	sk->protinfo.x25 = x25;
+
+	MOD_INC_USE_COUNT;
+
+	skb_queue_head_init(&sk->receive_queue);
+	skb_queue_head_init(&sk->write_queue);
+	skb_queue_head_init(&sk->back_log);
+
+	init_timer(&sk->timer);
+
+	sk->state_change = def_callback1;
+	sk->data_ready   = def_callback2;
+	sk->write_space  = def_callback1;
+	sk->error_report = def_callback1;
+
+	skb_queue_head_init(&x25->ack_queue);
+	skb_queue_head_init(&x25->fragment_queue);
+	skb_queue_head_init(&x25->interrupt_queue);
+
+	x25->condition = 0x00;
+	x25->timer     = 0;
+
+	x25->va    = 0;
+	x25->vr    = 0;
+	x25->vs    = 0;
+	x25->vl    = 0;
+
+	return sk;
+}
+
+static int x25_create(struct socket *sock, int protocol)
+{
+	struct sock *sk;
+	x25_cb *x25;
+
+	if (sock->type != SOCK_SEQPACKET || protocol != 0)
+		return -ESOCKTNOSUPPORT;
+
+	if ((sk = x25_alloc_socket()) == NULL)
+		return -ENOMEM;
+
+	x25 = sk->protinfo.x25;
+
+	sock->ops         = &x25_proto_ops;
+
+	sk->socket        = sock;
+	sk->type          = sock->type;
+	sk->protocol      = protocol;
+	sk->allocation	  = GFP_KERNEL;
+	sk->rcvbuf        = SK_RMEM_MAX;
+	sk->sndbuf        = SK_WMEM_MAX;
+	sk->state         = TCP_CLOSE;
+	sk->priority      = SOPRI_NORMAL;
+	sk->mtu           = X25_DEFAULT_PACKET_SIZE;	/* X25_PS128 */
+	sk->zapped        = 1;
+
+	if (sock != NULL) {
+		sock->sk  = sk;
+		sk->sleep = &sock->wait;
+	}
+
+	x25->lci      = 0;
+
+	x25->t21      = sysctl_x25_call_request_timeout;
+	x25->t22      = sysctl_x25_reset_request_timeout;
+	x25->t23      = sysctl_x25_clear_request_timeout;
+	x25->t2       = sysctl_x25_ack_holdback_timeout;
+
+	x25->fraglen     = 0;
+	x25->qbitincl    = 0;
+	x25->intflg      = 0;
+	x25->state       = X25_STATE_0;
+
+	x25->facilities.window_size = X25_DEFAULT_WINDOW_SIZE;
+	x25->facilities.packet_size = X25_DEFAULT_PACKET_SIZE;
+	x25->facilities.throughput  = X25_DEFAULT_THROUGHPUT;
+	x25->facilities.reverse     = X25_DEFAULT_REVERSE;
+
+	x25->neighbour   = NULL;
+
+	memset(&x25->source_addr, '\0', X25_ADDR_LEN);
+	memset(&x25->dest_addr,   '\0', X25_ADDR_LEN);
+
+	return 0;
+}
+
+static struct sock *x25_make_new(struct sock *osk)
+{
+	struct sock *sk;
+	x25_cb *x25;
+
+	if (osk->type != SOCK_SEQPACKET)
+		return NULL;
+
+	if ((sk = x25_alloc_socket()) == NULL)
+		return NULL;
+
+	x25 = sk->protinfo.x25;
+
+	sk->type        = osk->type;
+	sk->socket      = osk->socket;
+	sk->priority    = osk->priority;
+	sk->protocol    = osk->protocol;
+	sk->rcvbuf      = osk->rcvbuf;
+	sk->sndbuf      = osk->sndbuf;
+	sk->debug       = osk->debug;
+	sk->state       = TCP_ESTABLISHED;
+	sk->mtu         = osk->mtu;
+	sk->sleep       = osk->sleep;
+	sk->zapped      = osk->zapped;
+
+	x25->t21        = osk->protinfo.x25->t21;
+	x25->t22        = osk->protinfo.x25->t22;
+	x25->t23        = osk->protinfo.x25->t23;
+	x25->t2         = osk->protinfo.x25->t2;
+
+	x25->facilities = osk->protinfo.x25->facilities;
+
+	x25->qbitincl    = osk->protinfo.x25->qbitincl;
+	x25->intflg      = 0;
+	x25->fraglen     = 0;
+
+	return sk;
+}
+
+static int x25_dup(struct socket *newsock, struct socket *oldsock)
+{
+	struct sock *sk = (struct sock *)oldsock->sk;
+
+	return x25_create(newsock, sk->protocol);
+}
+
+static int x25_release(struct socket *sock, struct socket *peer)
+{
+	struct sock *sk = (struct sock *)sock->sk;
+
+	if (sk == NULL) return 0;
+
+	switch (sk->protinfo.x25->state) {
+
+		case X25_STATE_0:
+			sk->state     = TCP_CLOSE;
+			sk->shutdown |= SEND_SHUTDOWN;
+			sk->state_change(sk);
+			sk->dead      = 1;
+			x25_destroy_socket(sk);
+			break;
+
+		case X25_STATE_1:
+			sk->protinfo.x25->state = X25_STATE_0;
+			sk->state               = TCP_CLOSE;
+			sk->shutdown           |= SEND_SHUTDOWN;
+			sk->state_change(sk);
+			sk->dead                = 1;
+			x25_destroy_socket(sk);
+			break;
+
+		case X25_STATE_2:
+			sk->protinfo.x25->state = X25_STATE_0;
+			sk->state               = TCP_CLOSE;
+			sk->shutdown           |= SEND_SHUTDOWN;
+			sk->state_change(sk);
+			sk->dead                = 1;
+			x25_destroy_socket(sk);
+			break;			
+
+		case X25_STATE_3:
+		case X25_STATE_4:
+			x25_clear_queues(sk);
+			x25_write_internal(sk, X25_CLEAR_REQUEST);
+			sk->protinfo.x25->timer = sk->protinfo.x25->t23;
+			sk->protinfo.x25->state = X25_STATE_2;
+			sk->state               = TCP_CLOSE;
+			sk->shutdown           |= SEND_SHUTDOWN;
+			sk->state_change(sk);
+			sk->dead                = 1;
+			sk->destroy             = 1;
+			break;
+
+		default:
+			break;
+	}
+
+	sock->sk   = NULL;	
+	sk->socket = NULL;	/* Not used, but we should do this */
+
+	return 0;
+}
+
+static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+{
+	struct sock *sk;
+	struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
+	
+	sk = (struct sock *)sock->sk;
+
+	if (sk->zapped == 0)
+		return -EINVAL;
+		
+	if (addr_len != sizeof(struct sockaddr_x25))
+		return -EINVAL;
+
+	if (addr->sx25_family != AF_X25)
+		return -EINVAL;
+
+	sk->protinfo.x25->source_addr = addr->sx25_addr;
+
+	x25_insert_socket(sk);
+
+	sk->zapped = 0;
+
+	if (sk->debug)
+		printk(KERN_DEBUG "x25_bind: socket is bound\n");
+
+	return 0;
+}
+
+static int x25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
+{
+	struct sock *sk = (struct sock *)sock->sk;
+	struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr;
+	struct device *dev;
+	
+	if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
+		sock->state = SS_CONNECTED;
+		return 0;	/* Connect completed during a ERESTARTSYS event */
+	}
+	
+	if (sk->state == TCP_CLOSE && sock->state == SS_CONNECTING) {
+		sock->state = SS_UNCONNECTED;
+		return -ECONNREFUSED;
+	}
+	
+	if (sk->state == TCP_ESTABLISHED)
+		return -EISCONN;	/* No reconnect on a seqpacket socket */
+		
+	sk->state   = TCP_CLOSE;	
+	sock->state = SS_UNCONNECTED;
+
+	if (addr_len != sizeof(struct sockaddr_x25))
+		return -EINVAL;
+
+	if ((dev = x25_get_route(&addr->sx25_addr)) == NULL)
+		return -ENETUNREACH;
+
+	if ((sk->protinfo.x25->neighbour = x25_get_neigh(dev)) == NULL)
+		return -ENETUNREACH;
+
+	if (sk->zapped)		/* Must bind first - autobinding does not work */
+		return -EINVAL;
+
+	sk->protinfo.x25->dest_addr = addr->sx25_addr;
+	sk->protinfo.x25->lci       = x25_new_lci();
+
+	/* Move to connecting socket, start sending Connect Requests */
+	sock->state   = SS_CONNECTING;
+	sk->state     = TCP_SYN_SENT;
+
+	sk->protinfo.x25->state = X25_STATE_1;
+	sk->protinfo.x25->timer = sk->protinfo.x25->t21;
+	x25_write_internal(sk, X25_CALL_REQUEST);
+
+	x25_set_timer(sk);
+	
+	/* Now the loop */
+	if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
+		return -EINPROGRESS;
+		
+	cli();	/* To avoid races on the sleep */
+
+	/*
+	 * A Connect Ack with Choke or timeout or failed routing will go to closed.
+	 */
+	while (sk->state == TCP_SYN_SENT) {
+		interruptible_sleep_on(sk->sleep);
+		if (current->signal & ~current->blocked) {
+			sti();
+			return -ERESTARTSYS;
+		}
+	}
+
+	if (sk->state != TCP_ESTABLISHED) {
+		sti();
+		sock->state = SS_UNCONNECTED;
+		return sock_error(sk);	/* Always set at this point */
+	}
+	
+	sock->state = SS_CONNECTED;
+
+	sti();
+	
+	return 0;
+}
+	
+static int x25_socketpair(struct socket *sock1, struct socket *sock2)
+{
+	return -EOPNOTSUPP;
+}
+
+static int x25_accept(struct socket *sock, struct socket *newsock, int flags)
+{
+	struct sock *sk;
+	struct sock *newsk;
+	struct sk_buff *skb;
+
+	if (newsock->sk)
+		sk_free(newsock->sk);
+
+	newsock->sk = NULL;
+	
+	sk = (struct sock *)sock->sk;
+
+	if (sk->type != SOCK_SEQPACKET)
+		return -EOPNOTSUPP;
+	
+	if (sk->state != TCP_LISTEN)
+		return -EINVAL;
+		
+	/*
+	 *	The write queue this time is holding sockets ready to use
+	 *	hooked into the CALL INDICATION we saved
+	 */
+	do {
+		cli();
+		if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
+			if (flags & O_NONBLOCK) {
+				sti();
+				return 0;
+			}
+			interruptible_sleep_on(sk->sleep);
+			if (current->signal & ~current->blocked) {
+				sti();
+				return -ERESTARTSYS;
+			}
+		}
+	} while (skb == NULL);
+
+	newsk = skb->sk;
+	newsk->pair = NULL;
+	sti();
+
+	/* Now attach up the new socket */
+	skb->sk = NULL;
+	kfree_skb(skb, FREE_READ);
+	sk->ack_backlog--;
+	newsock->sk = newsk;
+
+	return 0;
+}
+
+static int x25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer)
+{
+	struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)uaddr;
+	struct sock *sk;
+	
+	sk = (struct sock *)sock->sk;
+	
+	if (peer != 0) {
+		if (sk->state != TCP_ESTABLISHED)
+			return -ENOTCONN;
+		sx25->sx25_addr   = sk->protinfo.x25->dest_addr;
+	} else {
+		sx25->sx25_addr   = sk->protinfo.x25->source_addr;
+	}
+
+	sx25->sx25_family = AF_X25;
+	*uaddr_len = sizeof(struct sockaddr_x25);
+
+	return 0;
+}
+ 
+int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *neigh, unsigned int lci)
+{
+	struct sock *sk;
+	struct sock *make;
+	x25_address source_addr, dest_addr;
+	struct x25_facilities facilities;
+	int len;
+
+	/*
+	 *	skb->data points to the x25 frame start
+	 */
+
+	/*
+	 *	Remove the LCI and frame type.
+	 */
+	skb_pull(skb, X25_STD_MIN_LEN);
+
+	/*
+	 *	Extract the X.25 addresses and convert them to ASCII strings.
+	 */
+	len = x25_addr_ntoa(skb->data, &source_addr, &dest_addr);
+
+	/*
+	 *	Remove address lengths and addresses.
+	 */
+	skb_pull(skb, len);
+
+	/*
+	 *	Find a listener for the particular address.
+	 */
+	sk = x25_find_listener(&source_addr);
+
+	/*
+	 *	We can't accept the Call Request.
+	 */
+	if (sk == NULL || sk->ack_backlog == sk->max_ack_backlog || (make = x25_make_new(sk)) == NULL) {
+		x25_transmit_clear_request(neigh, lci, 0x01);
+		return 0;
+	}
+
+	/*
+	 *	Parse the facilities.
+	 */
+	len = x25_parse_facilities(skb, &facilities);
+
+	/*
+	 *	Then remove them, leaving any Call User Data.
+	 */
+	skb_pull(skb, len);
+
+	skb->sk     = make;
+	make->state = TCP_ESTABLISHED;
+
+	make->protinfo.x25->lci           = lci;
+	make->protinfo.x25->dest_addr     = dest_addr;
+	make->protinfo.x25->source_addr   = source_addr;
+	make->protinfo.x25->neighbour     = neigh;
+
+	/*
+	 *	This implies that we accept all the incoming facilities
+	 *	values (if any). This needs fixing. XXX
+	 */
+	make->protinfo.x25->facilities    = facilities;
+
+	/*
+	 *	Incoming Call User Data. XXX
+	 */
+	
+	x25_write_internal(make, X25_CALL_ACCEPTED);
+
+	make->protinfo.x25->state = X25_STATE_3;
+
+	sk->ack_backlog++;
+	make->pair = sk;
+
+	x25_insert_socket(make);
+
+	skb_queue_head(&sk->receive_queue, skb);
+
+	x25_set_timer(make);
+
+	if (!sk->dead)
+		sk->data_ready(sk, skb->len);
+
+	return 1;
+}
+
+static int x25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
+{
+	struct sock *sk = (struct sock *)sock->sk;
+	struct sockaddr_x25 *usx25 = (struct sockaddr_x25 *)msg->msg_name;
+	int err;
+	struct sockaddr_x25 sx25;
+	struct sk_buff *skb;
+	unsigned char *asmptr;
+	int size, qbit = 0;
+
+	if (msg->msg_flags & ~MSG_DONTWAIT)
+		return -EINVAL;
+
+	if (sk->zapped)
+		return -EADDRNOTAVAIL;
+
+	if (sk->shutdown & SEND_SHUTDOWN) {
+		send_sig(SIGPIPE, current, 0);
+		return -EPIPE;
+	}
+
+	if (sk->protinfo.x25->neighbour == NULL)
+		return -ENETUNREACH;
+		
+	if (usx25 != NULL) {
+		if (msg->msg_namelen < sizeof(sx25))
+			return -EINVAL;
+		sx25 = *usx25;
+		if (strcmp(sk->protinfo.x25->dest_addr.x25_addr, sx25.sx25_addr.x25_addr) != 0)
+			return -EISCONN;
+		if (sx25.sx25_family != AF_X25)
+			return -EINVAL;
+	} else {
+		/*
+		 *	FIXME 1003.1g - if the socket is like this because
+		 *	it has become closed (not started closed) we ought
+		 *	to SIGPIPE, EPIPE;
+		 */
+		if (sk->state != TCP_ESTABLISHED)
+			return -ENOTCONN;
+
+		sx25.sx25_family = AF_X25;
+		sx25.sx25_addr   = sk->protinfo.x25->dest_addr;
+	}
+	
+	if (sk->debug)
+		printk(KERN_DEBUG "x25_sendmsg: sendto: Addresses built.\n");
+
+	/* Build a packet */
+	if (sk->debug)
+		printk(KERN_DEBUG "x25_sendmsg: sendto: building packet.\n");
+
+	size = len + X25_MAX_L2_LEN + X25_EXT_MIN_LEN;
+
+	if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
+		return err;
+
+	skb->sk   = sk;
+	skb->arp  = 1;
+
+	skb_reserve(skb, X25_MAX_L2_LEN + X25_EXT_MIN_LEN);
+	
+	/*
+	 *	Put the data on the end
+	 */
+	if (sk->debug)
+		printk(KERN_DEBUG "x25_sendmsg: Copying user data\n");
+
+	skb->h.raw = skb_put(skb, len);
+	asmptr = skb->h.raw;
+
+	memcpy_fromiovec(asmptr, msg->msg_iov, len);
+
+	/*
+	 *	If the Q BIT Include socket option is in force, the first
+	 *	byte of the user data is the logical value of the Q Bit.
+	 */
+	if (sk->protinfo.x25->qbitincl) {
+		qbit = skb->data[0];
+		skb_pull(skb, 1);
+	}
+
+	/*
+	 *	Push down the X.25 header
+	 */
+	if (sk->debug)
+		printk(KERN_DEBUG "x25_sendmsg: Building X.25 Header.\n");
+
+	if (sk->protinfo.x25->neighbour->extended) {
+		/* Build an Extended X.25 header */
+		asmptr    = skb_push(skb, X25_EXT_MIN_LEN);
+		*asmptr++ = ((sk->protinfo.x25->lci >> 8) & 0x0F) | X25_GFI_EXTSEQ;
+		*asmptr++ = (sk->protinfo.x25->lci >> 0) & 0xFF;
+		*asmptr++ = X25_DATA;
+		*asmptr++ = X25_DATA;
+	} else {
+		/* Build an Standard X.25 header */
+		asmptr    = skb_push(skb, X25_STD_MIN_LEN);
+		*asmptr++ = ((sk->protinfo.x25->lci >> 8) & 0x0F) | X25_GFI_STDSEQ;
+		*asmptr++ = (sk->protinfo.x25->lci >> 0) & 0xFF;
+		*asmptr++ = X25_DATA;
+	}
+
+	if (qbit)
+		skb->data[0] |= X25_Q_BIT;
+
+	if (sk->debug)
+		printk(KERN_DEBUG "x25_sendmsg: Built header.\n");
+
+	if (sk->debug)
+		printk(KERN_DEBUG "x25_sendmsg: Transmitting buffer\n");
+
+	if (sk->state != TCP_ESTABLISHED) {
+		kfree_skb(skb, FREE_WRITE);
+		return -ENOTCONN;
+	}
+
+	x25_output(sk, skb);	/* Shove it onto the queue */
+
+	return len;
+}
+
+
+static int x25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm)
+{
+	struct sock *sk = (struct sock *)sock->sk;
+	struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name;
+	int copied, qbit;
+	struct sk_buff *skb;
+	unsigned char *asmptr;
+	int er;
+
+	/*
+	 * This works for seqpacket too. The receiver has ordered the queue for
+	 * us! We do one quick check first though
+	 */
+	if (sk->state != TCP_ESTABLISHED)
+		return -ENOTCONN;
+
+	/* Now we can treat all alike */
+	if ((skb = skb_recv_datagram(sk, flags, msg->msg_flags & MSG_DONTWAIT, &er)) == NULL)
+		return er;
+
+	qbit = (skb->data[0] & X25_Q_BIT) == X25_Q_BIT;
+
+	skb_pull(skb, (sk->protinfo.x25->neighbour->extended) ? X25_EXT_MIN_LEN : X25_STD_MIN_LEN);
+	skb->h.raw = skb->data;
+
+	if (sk->protinfo.x25->qbitincl) {
+		asmptr  = skb_push(skb, 1);
+		*asmptr = qbit;
+		skb->h.raw = skb->data;
+	}
+
+	copied = skb->len;
+	
+	if (copied > size) {
+		copied = size;
+		msg->msg_flags |= MSG_TRUNC;
+	}
+
+	skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+	
+	if (sx25 != NULL) {
+		struct sockaddr_x25 addr;
+		
+		addr.sx25_family = AF_X25;
+		addr.sx25_addr   = sk->protinfo.x25->dest_addr;
+
+		*sx25 = addr;
+	}
+
+	msg->msg_namelen = sizeof(struct sockaddr_x25);
+
+	skb_free_datagram(sk, skb);
+
+	return copied;
+}
+
+static int x25_shutdown(struct socket *sk, int how)
+{
+	return -EOPNOTSUPP;
+}
+
+static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+	struct sock *sk = (struct sock *)sock->sk;
+	int err;
+	long amount = 0;
+
+	switch (cmd) {
+		case TIOCOUTQ:
+			if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned long))) != 0)
+				return err;
+			amount = sk->sndbuf - sk->wmem_alloc;
+			if (amount < 0)
+				amount = 0;
+			put_user(amount, (unsigned long *)arg);
+			return 0;
+
+		case TIOCINQ: {
+			struct sk_buff *skb;
+			/* These two are safe on a single CPU system as only user tasks fiddle here */
+			if ((skb = skb_peek(&sk->receive_queue)) != NULL)
+				amount = skb->len - 20;
+			if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned long))) != 0)
+				return err;
+			put_user(amount, (unsigned long *)arg);
+			return 0;
+		}
+
+		case SIOCGSTAMP:
+			if (sk != NULL) {
+				if (sk->stamp.tv_sec==0)
+					return -ENOENT;
+				if ((err = verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval))) != 0)
+					return err;
+				copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval));
+				return 0;
+			}
+			return -EINVAL;
+
+		case SIOCGIFADDR:
+		case SIOCSIFADDR:
+		case SIOCGIFDSTADDR:
+		case SIOCSIFDSTADDR:
+		case SIOCGIFBRDADDR:
+		case SIOCSIFBRDADDR:
+		case SIOCGIFNETMASK:
+		case SIOCSIFNETMASK:
+		case SIOCGIFMETRIC:
+		case SIOCSIFMETRIC:
+			return -EINVAL;
+
+		case SIOCADDRT:
+		case SIOCDELRT:
+			if (!suser()) return -EPERM;
+			return x25_route_ioctl(cmd, (void *)arg);
+
+		case SIOCX25SETSUBSCR:
+			if (!suser()) return -EPERM;
+			return x25_subscr_ioctl(cmd, (void *)arg);
+
+ 		default:
+			return dev_ioctl(cmd, (void *)arg);
+	}
+
+	/*NOTREACHED*/
+	return 0;
+}
+
+static int x25_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+	struct sock *s;
+	struct device *dev;
+	const char *devname;
+	int len = 0;
+	off_t pos = 0;
+	off_t begin = 0;
+  
+	cli();
+
+	len += sprintf(buffer, "dest_addr  src_addr   dev   lci st vs vr va   t  t2 t21 t22 t23 Snd-Q Rcv-Q\n");
+
+	for (s = x25_list; s != NULL; s = s->next) {
+		if (s->protinfo.x25->neighbour == NULL || (dev = s->protinfo.x25->neighbour->dev) == NULL)
+			devname = "???";
+		else
+			devname = s->protinfo.x25->neighbour->dev->name;
+
+		len += sprintf(buffer + len, "%-10s %-10s %-5s %3.3X  %d  %d  %d  %d %3d %3d %3d %3d %3d %5d %5d\n",
+			(s->protinfo.x25->dest_addr.x25_addr[0] == '\0')   ? "*" : s->protinfo.x25->dest_addr.x25_addr,
+			(s->protinfo.x25->source_addr.x25_addr[0] == '\0') ? "*" : s->protinfo.x25->source_addr.x25_addr,
+			devname,  s->protinfo.x25->lci & 0x0FFF,
+			s->protinfo.x25->state,
+			s->protinfo.x25->vs, s->protinfo.x25->vr, s->protinfo.x25->va,
+			s->protinfo.x25->timer / X25_SLOWHZ,
+			s->protinfo.x25->t2    / X25_SLOWHZ,
+			s->protinfo.x25->t21   / X25_SLOWHZ,
+			s->protinfo.x25->t22   / X25_SLOWHZ,
+			s->protinfo.x25->t23   / X25_SLOWHZ,
+			s->wmem_alloc, s->rmem_alloc);
+		
+		pos = begin + len;
+
+		if (pos < offset) {
+			len   = 0;
+			begin = pos;
+		}
+		
+		if (pos > offset + length)
+			break;
+	}
+
+	sti();
+
+	*start = buffer + (offset - begin);
+	len   -= (offset - begin);
+
+	if (len > length) len = length;
+
+	return(len);
+} 
+
+struct net_proto_family x25_family_ops = {
+	AF_X25,
+	x25_create
+};
+
+struct proto_ops x25_proto_ops = {
+	AF_X25,
+
+	x25_dup,
+	x25_release,
+	x25_bind,
+	x25_connect,
+	x25_socketpair,
+	x25_accept,
+	x25_getname,
+	datagram_select,
+	x25_ioctl,
+	x25_listen,
+	x25_shutdown,
+	x25_setsockopt,
+	x25_getsockopt,
+	x25_fcntl,
+	x25_sendmsg,
+	x25_recvmsg
+};
+
+static struct packet_type x25_packet_type =
+{
+	0,		/* MUTTER ntohs(ETH_P_X25),*/
+	0,		/* copy */
+	x25_llc_receive_frame,
+	NULL,
+	NULL,
+};
+
+struct notifier_block x25_dev_notifier = {
+	x25_device_event,
+	0
+};
+
+void x25_proto_init(struct net_proto *pro)
+{
+	sock_register(&x25_family_ops);
+
+	x25_packet_type.type = htons(ETH_P_X25);
+	dev_add_pack(&x25_packet_type);
+
+	register_netdevice_notifier(&x25_dev_notifier);
+
+	printk(KERN_INFO "X.25 for Linux. Version 0.1 for Linux 2.1.15\n");
+
+	x25_register_sysctl();
+
+#ifdef CONFIG_PROC_FS
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_X25, 3, "x25",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations, 
+		x25_get_info
+	});
+
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_X25_LINKS, 9, "x25_links",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations, 
+		x25_link_get_info
+	});
+
+	proc_net_register(&(struct proc_dir_entry) {
+		PROC_NET_X25_ROUTES, 10, "x25_routes",
+		S_IFREG | S_IRUGO, 1, 0, 0,
+		0, &proc_net_inode_operations, 
+		x25_routes_get_info
+	});
+#endif	
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+	register_symtab(NULL);
+
+	x25_proto_init(NULL);
+	
+	return 0;
+}
+
+void cleanup_module(void)
+{
+
+#ifdef CONFIG_PROC_FS
+	proc_net_unregister(PROC_NET_X25);
+	proc_net_unregister(PROC_NET_X25_LINKS);
+	proc_net_unregister(PROC_NET_X25_ROUTES);
+#endif
+
+	x25_link_free();
+	x25_route_free();
+
+	x25_unregister_sysctl();
+
+	unregister_netdevice_notifier(&x25_dev_notifier);
+
+	dev_remove_pack(&x25_packet_type);
+
+	sock_unregister(x25_proto_ops.family);
+}
+
+#endif
+
+#endif
diff -u --recursive --new-file v2.1.15/linux/net/x25/sysctl_net_x25.c linux/net/x25/sysctl_net_x25.c
--- v2.1.15/linux/net/x25/sysctl_net_x25.c	Thu Jan  1 02:00:00 1970
+++ linux/net/x25/sysctl_net_x25.c	Wed Dec 18 12:07:56 1996
@@ -0,0 +1,57 @@
+/* -*- linux-c -*-
+ * sysctl_net_x25.c: sysctl interface to net X.25 subsystem.
+ *
+ * Begun April 1, 1996, Mike Shaver.
+ * Added /proc/sys/net/x25 directory entry (empty =) ). [MS]
+ */
+
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <linux/netdevice.h>
+#include <net/x25.h>
+
+static int min_timer[] = {1   * X25_SLOWHZ};
+static int max_timer[] = {300 * X25_SLOWHZ};
+
+static struct ctl_table_header *x25_table_header;
+
+static ctl_table x25_table[] = {
+        {NET_X25_RESTART_REQUEST_TIMEOUT, "restart_request_timeout",
+         &sysctl_x25_restart_request_timeout, sizeof(int), 0644, NULL,
+         &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_timer, &max_timer},
+        {NET_X25_CALL_REQUEST_TIMEOUT, "call_request_timeout",
+         &sysctl_x25_call_request_timeout, sizeof(int), 0644, NULL,
+         &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_timer, &max_timer},
+        {NET_X25_RESET_REQUEST_TIMEOUT, "reset_request_timeout",
+         &sysctl_x25_reset_request_timeout, sizeof(int), 0644, NULL,
+         &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_timer, &max_timer},
+        {NET_X25_CLEAR_REQUEST_TIMEOUT, "clear_request_timeout",
+         &sysctl_x25_clear_request_timeout, sizeof(int), 0644, NULL,
+         &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_timer, &max_timer},
+        {NET_X25_ACK_HOLD_BACK_TIMEOUT, "acknowledgement_hold_back_timeout",
+         &sysctl_x25_ack_holdback_timeout, sizeof(int), 0644, NULL,
+         &proc_dointvec_minmax, &sysctl_intvec, NULL, &min_timer, &max_timer},
+	{0}
+};
+
+static ctl_table x25_dir_table[] = {
+	{NET_X25, "x25", NULL, 0, 0555, x25_table},
+	{0}
+};
+
+static ctl_table x25_root_table[] = {
+	{CTL_NET, "net", NULL, 0, 0555, x25_dir_table},
+	{0}
+};
+
+void x25_register_sysctl(void)
+{
+	x25_table_header = register_sysctl_table(x25_root_table, 1);
+}
+
+void x25_unregister_sysctl(void)
+{
+	unregister_sysctl_table(x25_table_header);
+}
diff -u --recursive --new-file v2.1.15/linux/net/x25/x25_dev.c linux/net/x25/x25_dev.c
--- v2.1.15/linux/net/x25/x25_dev.c	Thu Jan  1 02:00:00 1970
+++ linux/net/x25/x25_dev.c	Wed Dec 18 12:07:56 1996
@@ -0,0 +1,182 @@
+/*
+ *	X.25 Packet Layer release 001
+ *
+ *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
+ *	releases, misbehave and/or generally screw up. It might even work. 
+ *
+ *	This code REQUIRES 2.1.15 or higher
+ *
+ *	This module:
+ *		This module 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.
+ *
+ *	History
+ *	X.25 001	Jonathan Naylor	Started coding.
+ */
+  
+#include <linux/config.h>
+#if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/stat.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <linux/fcntl.h>
+#include <linux/termios.h>	/* For TIOCINQ/OUTQ */
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <linux/proc_fs.h>
+#include <linux/if_arp.h>
+#include <linux/firewall.h>
+#include <net/x25.h>
+
+static int x25_receive_data(struct sk_buff *skb, struct device *dev)
+{
+	struct x25_neigh *neigh;
+	struct sock *sk;
+	unsigned short frametype;
+	unsigned int lci;
+
+#ifdef CONFIG_FIREWALL
+	if (call_in_firewall(PF_X25, skb->dev, skb->data, NULL) != FW_ACCEPT) {
+		kfree_skb(skb, FREE_READ);
+		return 0;
+	}
+#endif
+
+	/*
+	 *	Packet received from unrecognised device, throw it away.
+	 */
+	if ((neigh = x25_get_neigh(dev)) == NULL) {
+		kfree_skb(skb, FREE_READ);
+		return 0;
+	}
+
+	frametype = skb->data[2];
+        lci = ((skb->data[0] << 8) & 0xF00) + ((skb->data[1] << 0) & 0x0FF);
+
+	/*
+	 *	LCI of zero is always for us, and its always a link control
+	 *	frame.
+	 */
+	if (lci == 0) {
+		x25_link_control(skb, neigh, frametype);
+		return 0;
+	}
+
+	/*
+	 *	Find an existing socket.
+	 */
+	if ((sk = x25_find_socket(lci)) != NULL) {
+		skb->h.raw = skb->data;
+		return x25_process_rx_frame(sk, skb);
+	}
+
+	/*
+	 *	Is is a Call Request ? if so process it.
+	 */
+	if (frametype == X25_CALL_REQUEST)
+		return x25_rx_call_request(skb, neigh, lci);
+
+	/*
+	 *	Its not a Call Request, nor is it a control frame, throw it awa
+	 */
+	x25_transmit_clear_request(neigh, lci, 0x0D);
+
+	kfree_skb(skb, FREE_READ);
+
+	return 0;
+}
+
+int x25_lapb_receive_frame(struct sk_buff *skb, struct device *dev, struct packet_type *ptype)
+{
+	skb->sk = NULL;
+	
+	switch (*skb->data) {
+		case 0x00:
+			skb_pull(skb, 1);
+			return x25_receive_data(skb, dev);
+
+		default:
+			kfree_skb(skb, FREE_READ);
+			return 0;
+	}
+}
+
+int x25_llc_receive_frame(struct sk_buff *skb, struct device *dev, struct packet_type *ptype)
+{
+	unsigned int len;
+
+	skb->sk = NULL;
+
+	memcpy(&len, skb->data, sizeof(int));
+
+	skb_pull(skb, sizeof(int));
+
+	skb_trim(skb, len);
+	
+	return x25_receive_data(skb, dev);
+}
+
+int x25_link_up(struct device *dev)
+{
+	switch (dev->type) {
+		case ARPHRD_ETHER:
+			return 1;
+		case ARPHRD_X25:
+			return 0;
+		default:
+			return 0;
+	}
+}
+
+void x25_send_frame(struct sk_buff *skb, struct device *dev)
+{
+	unsigned char *dptr;
+	unsigned int  len;
+	static char bcast_addr[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
+
+	skb->protocol = htons(ETH_P_X25);
+	skb->priority = SOPRI_NORMAL;
+	skb->dev      = dev;
+	skb->arp      = 1;
+
+	switch (dev->type) {
+		case ARPHRD_ETHER:
+			len  = skb->len;
+			dptr = skb_push(skb, sizeof(int));
+			memcpy(dptr, &len, sizeof(int));
+			dev->hard_header(skb, dev, ETH_P_X25, bcast_addr, NULL, 0);
+			break;
+
+		case ARPHRD_X25:
+			dptr  = skb_push(skb, 1);
+			*dptr = 0x00;
+			break;
+
+		default:
+			kfree_skb(skb, FREE_WRITE);
+			return;
+	}
+
+	dev_queue_xmit(skb);
+}
+
+#endif
diff -u --recursive --new-file v2.1.15/linux/net/x25/x25_in.c linux/net/x25/x25_in.c
--- v2.1.15/linux/net/x25/x25_in.c	Thu Jan  1 02:00:00 1970
+++ linux/net/x25/x25_in.c	Wed Dec 18 12:07:56 1996
@@ -0,0 +1,336 @@
+/*
+ *	X.25 Packet Layer release 001
+ *
+ *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
+ *	releases, misbehave and/or generally screw up. It might even work. 
+ *
+ *	This code REQUIRES 2.1.15 or higher
+ *
+ *	This module:
+ *		This module 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.
+ *
+ *	History
+ *	X.25 001	Jonathan Naylor	Started coding.
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/ip.h>			/* For ip_rcv */
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <net/x25.h>
+
+static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
+{
+	struct sk_buff *skbo, *skbn = skb;
+
+	if (more) {
+		sk->protinfo.x25->fraglen += skb->len;
+		skb_queue_tail(&sk->protinfo.x25->fragment_queue, skb);
+		return 0;
+	}
+	
+	if (!more && sk->protinfo.x25->fraglen > 0) {	/* End of fragment */
+		sk->protinfo.x25->fraglen += skb->len;
+		skb_queue_tail(&sk->protinfo.x25->fragment_queue, skb);
+
+		if ((skbn = alloc_skb(sk->protinfo.x25->fraglen, GFP_ATOMIC)) == NULL)
+			return 1;
+
+		skbn->arp  = 1;
+		skb_set_owner_r(skbn, sk);
+		skbn->h.raw = skbn->data;
+
+		skbo = skb_dequeue(&sk->protinfo.x25->fragment_queue);
+		memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
+		kfree_skb(skbo, FREE_READ);
+
+		while ((skbo = skb_dequeue(&sk->protinfo.x25->fragment_queue)) != NULL) {
+			skb_pull(skbo, (sk->protinfo.x25->neighbour->extended) ? X25_EXT_MIN_LEN : X25_STD_MIN_LEN);
+			memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len);
+			kfree_skb(skbo, FREE_READ);
+		}
+
+		sk->protinfo.x25->fraglen = 0;		
+	}
+
+	return sock_queue_rcv_skb(sk, skbn);
+}
+
+/*
+ * State machine for state 1, Awaiting Call Accepted State.
+ * The handling of the timer(s) is in file x25_timer.c.
+ * Handling of state 0 and connection release is in af_x25.c.
+ */
+static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype)
+{
+	switch (frametype) {
+
+		case X25_CALL_ACCEPTED:
+			sk->protinfo.x25->condition = 0x00;
+			sk->protinfo.x25->timer     = 0;
+			sk->protinfo.x25->vs        = 0;
+			sk->protinfo.x25->va        = 0;
+			sk->protinfo.x25->vr        = 0;
+			sk->protinfo.x25->vl        = 0;
+			sk->protinfo.x25->state     = X25_STATE_3;
+			sk->state                   = TCP_ESTABLISHED;
+			if (!sk->dead)
+				sk->state_change(sk);
+			break;
+
+		case X25_CLEAR_REQUEST:
+			x25_clear_queues(sk);
+			sk->protinfo.x25->state = X25_STATE_0;
+			sk->state               = TCP_CLOSE;
+			sk->err                 = ECONNREFUSED;
+			sk->shutdown           |= SEND_SHUTDOWN;
+			if (!sk->dead)
+				sk->state_change(sk);
+			sk->dead                = 1;
+			break;
+
+		default:
+			printk(KERN_WARNING "x25: unknown %02X in state 1\n", frametype);
+			break;
+	}
+
+	return 0;
+}
+
+/*
+ * State machine for state 2, Awaiting Clear Confirmation State.
+ * The handling of the timer(s) is in file x25_timer.c
+ * Handling of state 0 and connection release is in af_x25.c.
+ */
+static int x25_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype)
+{
+	switch (frametype) {
+
+		case X25_CLEAR_REQUEST:
+		case X25_CLEAR_CONFIRMATION:
+			sk->protinfo.x25->state = X25_STATE_0;
+			sk->state               = TCP_CLOSE;
+			sk->err                 = 0;
+			sk->shutdown           |= SEND_SHUTDOWN;
+			if (!sk->dead)
+				sk->state_change(sk);
+			sk->dead                = 1;
+			break;
+
+		default:
+			printk(KERN_WARNING "x25: unknown %02X in state 2\n", frametype);
+			break;
+	}
+
+	return 0;
+}
+
+/*
+ * State machine for state 3, Connected State.
+ * The handling of the timer(s) is in file x25_timer.c
+ * Handling of state 0 and connection release is in af_x25.c.
+ */
+static int x25_state3_machine(struct sock *sk, struct sk_buff *skb, int frametype, int ns, int nr, int q, int d, int m)
+{
+	int queued = 0;
+	int modulus;
+	
+	modulus = (sk->protinfo.x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
+
+	switch (frametype) {
+
+		case X25_RESET_REQUEST:
+			x25_clear_queues(sk);
+			x25_write_internal(sk, X25_RESET_CONFIRMATION);
+			sk->protinfo.x25->condition = 0x00;
+			sk->protinfo.x25->timer     = 0;
+			sk->protinfo.x25->vs        = 0;
+			sk->protinfo.x25->vr        = 0;
+			sk->protinfo.x25->va        = 0;
+			sk->protinfo.x25->vl        = 0;
+			break;
+
+		case X25_CLEAR_REQUEST:
+			x25_clear_queues(sk);
+			x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
+			sk->protinfo.x25->state = X25_STATE_0;
+			sk->state               = TCP_CLOSE;
+			sk->err                 = 0;
+			sk->shutdown           |= SEND_SHUTDOWN;
+			if (!sk->dead)
+				sk->state_change(sk);
+			sk->dead                = 1;
+			break;
+
+		case X25_RR:
+		case X25_RNR:
+			if (frametype == X25_RNR) {
+				sk->protinfo.x25->condition |= X25_COND_PEER_RX_BUSY;
+			} else {
+				sk->protinfo.x25->condition &= ~X25_COND_PEER_RX_BUSY;
+			}
+			if (!x25_validate_nr(sk, nr)) {
+				x25_clear_queues(sk);
+				x25_write_internal(sk, X25_RESET_REQUEST);
+				sk->protinfo.x25->condition = 0x00;
+				sk->protinfo.x25->vs        = 0;
+				sk->protinfo.x25->vr        = 0;
+				sk->protinfo.x25->va        = 0;
+				sk->protinfo.x25->vl        = 0;
+				sk->protinfo.x25->state     = X25_STATE_4;
+				sk->protinfo.x25->timer     = sk->protinfo.x25->t22;
+			} else {
+				if (sk->protinfo.x25->condition & X25_COND_PEER_RX_BUSY) {
+					x25_frames_acked(sk, nr);
+				} else {
+					x25_check_iframes_acked(sk, nr);
+				}
+			}
+			break;
+			
+		case X25_DATA:	/* XXX */
+			sk->protinfo.x25->condition &= ~X25_COND_PEER_RX_BUSY;
+			if (!x25_validate_nr(sk, nr)) {
+				x25_clear_queues(sk);
+				x25_write_internal(sk, X25_RESET_REQUEST);
+				sk->protinfo.x25->condition = 0x00;
+				sk->protinfo.x25->vs        = 0;
+				sk->protinfo.x25->vr        = 0;
+				sk->protinfo.x25->va        = 0;
+				sk->protinfo.x25->vl        = 0;
+				sk->protinfo.x25->state     = X25_STATE_4;
+				sk->protinfo.x25->timer     = sk->protinfo.x25->t22;
+				break;
+			}
+			if (sk->protinfo.x25->condition & X25_COND_PEER_RX_BUSY) {
+				x25_frames_acked(sk, nr);
+			} else {
+				x25_check_iframes_acked(sk, nr);
+			}
+			if (sk->protinfo.x25->condition & X25_COND_OWN_RX_BUSY)
+				break;
+			if (ns == sk->protinfo.x25->vr) {
+				if (x25_queue_rx_frame(sk, skb, m) == 0) {
+					sk->protinfo.x25->vr = (sk->protinfo.x25->vr + 1) % modulus;
+					queued = 1;
+				} else {
+					sk->protinfo.x25->condition |= X25_COND_OWN_RX_BUSY;
+				}
+			}
+			/*
+			 *	If the window is full Ack it immediately, else
+			 *	start the holdback timer.
+			 */
+			if (((sk->protinfo.x25->vl + sk->protinfo.x25->facilities.window_size) % modulus) == sk->protinfo.x25->vr) {
+				sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
+				sk->protinfo.x25->timer      = 0;
+				x25_enquiry_response(sk);
+			} else {
+				sk->protinfo.x25->condition |= X25_COND_ACK_PENDING;
+				sk->protinfo.x25->timer      = sk->protinfo.x25->t2;
+			}
+			break;
+
+		default:
+			printk(KERN_WARNING "x25: unknown %02X in state 3\n", frametype);
+			break;
+	}
+
+	return queued;
+}
+
+/*
+ * State machine for state 4, Awaiting Reset Confirmation State.
+ * The handling of the timer(s) is in file x25_timer.c
+ * Handling of state 0 and connection release is in af_x25.c.
+ */
+static int x25_state4_machine(struct sock *sk, struct sk_buff *skb, int frametype)
+{
+	switch (frametype) {
+
+		case X25_RESET_CONFIRMATION:
+		case X25_RESET_REQUEST:
+			sk->protinfo.x25->timer     = 0;
+			sk->protinfo.x25->condition = 0x00;
+			sk->protinfo.x25->va        = 0;
+			sk->protinfo.x25->vr        = 0;
+			sk->protinfo.x25->vs        = 0;
+			sk->protinfo.x25->vl        = 0;
+			sk->protinfo.x25->state     = X25_STATE_3;
+			break;
+
+		case X25_CLEAR_REQUEST:
+			x25_clear_queues(sk);
+			x25_write_internal(sk, X25_CLEAR_CONFIRMATION);
+			sk->protinfo.x25->timer = 0;
+			sk->protinfo.x25->state = X25_STATE_0;
+			sk->state               = TCP_CLOSE;
+			sk->err                 = 0;
+			sk->shutdown           |= SEND_SHUTDOWN;
+			if (!sk->dead)
+				sk->state_change(sk);
+			sk->dead                = 1;
+			break;
+
+		default:
+			printk(KERN_WARNING "x25: unknown %02X in state 4\n", frametype);
+			break;
+	}
+
+	return 0;
+}
+
+/* Higher level upcall for a LAPB frame */
+int x25_process_rx_frame(struct sock *sk, struct sk_buff *skb)
+{
+	int queued = 0, frametype, ns, nr, q, d, m;
+	
+	if (sk->protinfo.x25->state == X25_STATE_0)
+		return 0;
+
+	del_timer(&sk->timer);
+
+	frametype = x25_decode(sk, skb, &ns, &nr, &q, &d, &m);
+
+	switch (sk->protinfo.x25->state) {
+		case X25_STATE_1:
+			queued = x25_state1_machine(sk, skb, frametype);
+			break;
+		case X25_STATE_2:
+			queued = x25_state2_machine(sk, skb, frametype);
+			break;
+		case X25_STATE_3:
+			queued = x25_state3_machine(sk, skb, frametype, ns, nr, q, d, m);
+			break;
+		case X25_STATE_4:
+			queued = x25_state4_machine(sk, skb, frametype);
+			break;
+	}
+
+	x25_set_timer(sk);
+
+	return queued;
+}
+
+#endif
diff -u --recursive --new-file v2.1.15/linux/net/x25/x25_link.c linux/net/x25/x25_link.c
--- v2.1.15/linux/net/x25/x25_link.c	Thu Jan  1 02:00:00 1970
+++ linux/net/x25/x25_link.c	Wed Dec 18 12:07:56 1996
@@ -0,0 +1,465 @@
+/*
+ *	X.25 Packet Layer release 001
+ *
+ *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
+ *	releases, misbehave and/or generally screw up. It might even work. 
+ *
+ *	This code REQUIRES 2.1.15 or higher
+ *
+ *	This module:
+ *		This module 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.
+ *
+ *	History
+ *	X.25 001	Jonathan Naylor	Started coding.
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/firewall.h>
+#include <net/x25.h>
+
+static struct x25_neigh *x25_neigh_list = NULL;
+
+static void x25_link_timer(unsigned long);
+
+/*
+ *	Linux set/reset timer routines
+ */
+static void x25_link_set_timer(struct x25_neigh *neigh)
+{
+	unsigned long flags;
+	
+	save_flags(flags);
+	cli();
+	del_timer(&neigh->timer);
+	restore_flags(flags);
+
+	neigh->timer.next     = neigh->timer.prev = NULL;	
+	neigh->timer.data     = (unsigned long)neigh;
+	neigh->timer.function = &x25_link_timer;
+
+	neigh->timer.expires  = jiffies + 100;
+	add_timer(&neigh->timer);
+}
+
+static void x25_link_reset_timer(struct x25_neigh *neigh)
+{
+	unsigned long flags;
+	
+	save_flags(flags);
+	cli();
+	del_timer(&neigh->timer);
+	restore_flags(flags);
+
+	neigh->timer.data     = (unsigned long)neigh;
+	neigh->timer.function = &x25_link_timer;
+	neigh->timer.expires  = jiffies + 100;
+	add_timer(&neigh->timer);
+}
+
+/*
+ *	X.25 Link TIMER 
+ *
+ *	This routine is called every second. Decrement timer by this
+ *	amount - if expired then process the event.
+ */
+static void x25_link_timer(unsigned long param)
+{
+	struct x25_neigh *neigh = (struct x25_neigh *)param;
+
+	if (neigh->t20timer == 0 || --neigh->t20timer > 0) {
+		x25_link_reset_timer(neigh);
+		return;
+	}
+
+	/*
+	 * T20 for a link has expired.
+	 */
+	x25_transmit_restart_request(neigh);
+
+	neigh->t20timer = neigh->t20;
+
+	x25_link_set_timer(neigh);
+}
+
+/*
+ *	This handles all restart and diagnostic frames.
+ */
+void x25_link_control(struct sk_buff *skb, struct x25_neigh *neigh, unsigned short frametype)
+{
+	struct sk_buff *skbn;
+
+	switch (frametype) {
+		case X25_RESTART_REQUEST:
+			neigh->t20timer = 0;
+			neigh->state    = 1;
+			del_timer(&neigh->timer);
+			x25_transmit_restart_confirmation(neigh);
+			break;
+
+		case X25_RESTART_CONFIRMATION:
+			neigh->t20timer = 0;
+			neigh->state    = 1;
+			del_timer(&neigh->timer);
+			break;
+
+		case X25_DIAGNOSTIC:
+			printk(KERN_WARNING "x25: diagnostic #%d\n", skb->data[3]);
+			break;
+			
+		default:
+			printk(KERN_WARNING "x25: received unknown %02X with LCI 000\n", frametype);
+			break;
+	}
+
+	if (neigh->state == 1) {
+		while ((skbn = skb_dequeue(&neigh->queue)) != NULL)
+			x25_send_frame(skbn, neigh->dev);
+	}
+}
+
+/*
+ *	This routine is called when a Restart Request is needed
+ */
+void x25_transmit_restart_request(struct x25_neigh *neigh)
+{
+	struct sk_buff *skb;
+	unsigned char *dptr;
+	int len;
+
+	len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2;
+
+	if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
+		return;
+
+	skb_reserve(skb, X25_MAX_L2_LEN);
+
+	dptr = skb_put(skb, X25_STD_MIN_LEN + 2);
+
+	*dptr++ = (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
+	*dptr++ = 0x00;
+	*dptr++ = X25_RESTART_REQUEST;
+	*dptr++ = 0x00;
+	*dptr++ = 0;
+
+	skb->sk = NULL;
+
+	x25_send_frame(skb, neigh->dev);
+}
+
+/*
+ * This routine is called when a Restart Confirmation is needed
+ */
+void x25_transmit_restart_confirmation(struct x25_neigh *neigh)
+{
+	struct sk_buff *skb;
+	unsigned char *dptr;
+	int len;
+
+	len = X25_MAX_L2_LEN + X25_STD_MIN_LEN;
+
+	if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
+		return;
+
+	skb_reserve(skb, X25_MAX_L2_LEN);
+
+	dptr = skb_put(skb, X25_STD_MIN_LEN);
+
+	*dptr++ = (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
+	*dptr++ = 0x00;
+	*dptr++ = X25_RESTART_CONFIRMATION;
+
+	skb->sk = NULL;
+
+	x25_send_frame(skb, neigh->dev);
+}
+
+/*
+ * This routine is called when a Diagnostic is required.
+ */
+void x25_transmit_diagnostic(struct x25_neigh *neigh, unsigned char diag)
+{
+	struct sk_buff *skb;
+	unsigned char *dptr;
+	int len;
+
+	len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 1;
+
+	if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
+		return;
+
+	skb_reserve(skb, X25_MAX_L2_LEN);
+
+	dptr = skb_put(skb, X25_STD_MIN_LEN + 1);
+
+	*dptr++ = (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
+	*dptr++ = 0x00;
+	*dptr++ = X25_DIAGNOSTIC;
+	*dptr++ = diag;
+
+	skb->sk = NULL;
+
+	x25_send_frame(skb, neigh->dev);
+}
+
+/*
+ *	This routine is called when a Clear Request is needed outside of the context
+ *	of a connected socket.
+ */
+void x25_transmit_clear_request(struct x25_neigh *neigh, unsigned int lci, unsigned char cause)
+{
+	struct sk_buff *skb;
+	unsigned char *dptr;
+	int len;
+
+	len = X25_MAX_L2_LEN + X25_STD_MIN_LEN + 2;
+
+	if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
+		return;
+
+	skb_reserve(skb, X25_MAX_L2_LEN);
+
+	dptr = skb_put(skb, X25_STD_MIN_LEN + 2);
+
+	*dptr++ = ((lci >> 8) & 0x0F) | (neigh->extended) ? X25_GFI_EXTSEQ : X25_GFI_STDSEQ;
+	*dptr++ = ((lci >> 0) & 0xFF);
+	*dptr++ = X25_CLEAR_REQUEST;
+	*dptr++ = cause;
+	*dptr++ = 0x00;
+
+	skb->sk = NULL;
+
+	x25_send_frame(skb, neigh->dev);
+}
+
+void x25_transmit_link(struct sk_buff *skb, struct x25_neigh *neigh)
+{
+#ifdef CONFIG_FIREWALL
+	if (call_fw_firewall(PF_X25, skb->dev, skb->data, NULL) != FW_ACCEPT)
+		return;
+#endif
+
+	if (!x25_link_up(neigh->dev))
+		neigh->state = 0;
+
+	skb->arp  = 1;
+
+	if (neigh->state == 1) {
+		x25_send_frame(skb, neigh->dev);
+	} else {
+		skb_queue_tail(&neigh->queue, skb);
+		
+		if (neigh->t20timer == 0) {
+			x25_transmit_restart_request(neigh);
+			neigh->t20timer = neigh->t20;
+			x25_link_set_timer(neigh);
+		}
+	}
+}
+
+/*
+ *	Add a new device.
+ */
+void x25_link_device_up(struct device *dev)
+{
+	struct x25_neigh *x25_neigh;
+	unsigned long flags;
+
+	if ((x25_neigh = (struct x25_neigh *)kmalloc(sizeof(*x25_neigh), GFP_ATOMIC)) == NULL)
+		return;
+
+	skb_queue_head_init(&x25_neigh->queue);
+	init_timer(&x25_neigh->timer);
+
+	x25_neigh->dev      = dev;
+	x25_neigh->state    = 0;
+	x25_neigh->extended = 0;
+	x25_neigh->t20timer = 0;
+	x25_neigh->t20      = sysctl_x25_restart_request_timeout;
+
+	save_flags(flags); cli();
+	x25_neigh->next = x25_neigh_list;
+	x25_neigh_list  = x25_neigh;
+	restore_flags(flags);
+}
+
+static void x25_remove_neigh(struct x25_neigh *x25_neigh)
+{
+	struct x25_neigh *s;
+	unsigned long flags;
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&x25_neigh->queue)) != NULL)
+		kfree_skb(skb, FREE_WRITE);
+	
+	del_timer(&x25_neigh->timer);
+
+	save_flags(flags);
+	cli();
+
+	if ((s = x25_neigh_list) == x25_neigh) {
+		x25_neigh_list = x25_neigh->next;
+		restore_flags(flags);
+		kfree_s(x25_neigh, sizeof(struct x25_neigh));
+		return;
+	}
+
+	while (s != NULL && s->next != NULL) {
+		if (s->next == x25_neigh) {
+			s->next = x25_neigh->next;
+			restore_flags(flags);
+			kfree_s(x25_neigh, sizeof(struct x25_neigh));
+			return;
+		}
+
+		s = s->next;
+	}
+
+	restore_flags(flags);
+}
+
+/*
+ *	A device has been removed, remove its links.
+ */
+void x25_link_device_down(struct device *dev)
+{
+	struct x25_neigh *neigh, *x25_neigh = x25_neigh_list;
+
+	while (x25_neigh != NULL) {
+		neigh     = x25_neigh;
+		x25_neigh = x25_neigh->next;
+		
+		if (neigh->dev == dev)
+			x25_remove_neigh(neigh);
+	}
+}
+
+/*
+ *	Given a device, return the neighbour address.
+ */
+struct x25_neigh *x25_get_neigh(struct device *dev)
+{
+	struct x25_neigh *x25_neigh;
+
+	for (x25_neigh = x25_neigh_list; x25_neigh != NULL; x25_neigh = x25_neigh->next)
+		if (x25_neigh->dev == dev)
+			return x25_neigh;
+
+	return NULL;
+}
+
+/*
+ *	Handle the ioctls that control the subscription functions.
+ */
+int x25_subscr_ioctl(unsigned int cmd, void *arg)
+{
+	struct x25_subscrip_struct x25_subscr;
+	struct x25_neigh *x25_neigh;
+	struct device *dev;
+	int err;
+
+	switch (cmd) {
+
+		case SIOCX25SETSUBSCR:
+			if ((err = verify_area(VERIFY_READ, arg, sizeof(struct x25_subscrip_struct))) != 0)
+				return err;
+			copy_from_user(&x25_subscr, arg, sizeof(struct x25_subscrip_struct));
+			if ((dev = x25_dev_get(x25_subscr.device)) == NULL)
+				return -EINVAL;
+			if ((x25_neigh = x25_get_neigh(dev)) == NULL)
+				return -EINVAL;
+			if (x25_subscr.extended != 0 && x25_subscr.extended != 1)
+				return -EINVAL;
+			x25_neigh->extended = x25_subscr.extended;
+			break;
+
+		default:
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+int x25_link_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+	struct x25_neigh *x25_neigh;
+	int len     = 0;
+	off_t pos   = 0;
+	off_t begin = 0;
+
+	cli();
+
+	len += sprintf(buffer, "device           st    t20    ext\n");
+
+	for (x25_neigh = x25_neigh_list; x25_neigh != NULL; x25_neigh = x25_neigh->next) {
+		len += sprintf(buffer + len, "%-15s  %2d %3d/%03d  %d\n",
+			x25_neigh->dev->name,
+			x25_neigh->state,
+			x25_neigh->t20timer / X25_SLOWHZ,
+			x25_neigh->t20      / X25_SLOWHZ,
+			x25_neigh->extended);
+
+		pos = begin + len;
+
+		if (pos < offset) {
+			len   = 0;
+			begin = pos;
+		}
+		
+		if (pos > offset + length)
+			break;
+	}
+
+	sti();
+
+	*start = buffer + (offset - begin);
+	len   -= (offset - begin);
+
+	if (len > length) len = length;
+
+	return len;
+} 
+
+#ifdef MODULE
+
+/*
+ *	Release all memory associated with X.25 neighbour structures.
+ */
+void x25_link_free(void)
+{
+	struct x25_neigh *neigh, *x25_neigh = x25_neigh_list;
+
+	while (x25_neigh != NULL) {
+		neigh     = x25_neigh;
+		x25_neigh = x25_neigh->next;
+		
+		x25_remove_neigh(neigh);
+	}
+}
+
+#endif
+
+#endif
diff -u --recursive --new-file v2.1.15/linux/net/x25/x25_out.c linux/net/x25/x25_out.c
--- v2.1.15/linux/net/x25/x25_out.c	Thu Jan  1 02:00:00 1970
+++ linux/net/x25/x25_out.c	Wed Dec 18 12:07:56 1996
@@ -0,0 +1,207 @@
+/*
+ *	X.25 Packet Layer release 001
+ *
+ *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
+ *	releases, misbehave and/or generally screw up. It might even work. 
+ *
+ *	This code REQUIRES 2.1.15 or higher
+ *
+ *	This module:
+ *		This module 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.
+ *
+ *	History
+ *	X.25 001	Jonathan Naylor	Started coding.
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <net/x25.h>
+
+/*
+ *	This is where all X.25 information frames pass;
+ */
+void x25_output(struct sock *sk, struct sk_buff *skb)
+{
+	struct sk_buff *skbn;
+	unsigned char header[X25_EXT_MIN_LEN];
+	int err, frontlen, len, min_len;
+	
+	min_len  = (sk->protinfo.x25->neighbour->extended) ? X25_EXT_MIN_LEN : X25_STD_MIN_LEN;
+
+	if (skb->len - min_len > 128) {		/* XXX */
+		/* Save a copy of the Header */
+		memcpy(header, skb->data, min_len);
+		skb_pull(skb, min_len);
+
+		frontlen = skb_headroom(skb);
+
+		while (skb->len > 0) {
+			if ((skbn = sock_alloc_send_skb(sk, frontlen + 128, 0, 0, &err)) == NULL)	/* XXX */
+				return;
+
+			skbn->sk   = sk;
+			skbn->arp  = 1;
+
+			skb_reserve(skbn, frontlen);
+
+			len = (128 > skb->len) ? skb->len : 128;	/* XXX */
+
+			/* Copy the user data */
+			memcpy(skb_put(skbn, len), skb->data, len);
+			skb_pull(skb, len);
+
+			/* Duplicate the Header */
+			skb_push(skbn, min_len);
+			memcpy(skbn->data, header, min_len);
+
+			if (skb->len > 0) {
+				if (sk->protinfo.x25->neighbour->extended)
+					skbn->data[3] |= X25_EXT_M_BIT;
+				else
+					skbn->data[2] |= X25_STD_M_BIT;
+			}
+		
+			skb_queue_tail(&sk->write_queue, skbn); /* Throw it on the queue */
+		}
+		
+		kfree_skb(skb, FREE_WRITE);
+	} else {
+		skb_queue_tail(&sk->write_queue, skb);		/* Throw it on the queue */
+	}
+
+	if (sk->protinfo.x25->state == X25_STATE_3)
+		x25_kick(sk);
+}
+
+/* 
+ *	This procedure is passed a buffer descriptor for an iframe. It builds
+ *	the rest of the control part of the frame and then writes it out.
+ */
+static void x25_send_iframe(struct sock *sk, struct sk_buff *skb)
+{
+	if (skb == NULL)
+		return;
+
+	if (sk->protinfo.x25->neighbour->extended) {
+		skb->data[2] |= (sk->protinfo.x25->vs << 1) & 0xFE;
+		skb->data[3] |= (sk->protinfo.x25->vr << 1) & 0xFE;
+	} else {
+		skb->data[2] |= (sk->protinfo.x25->vs << 1) & 0x0E;
+		skb->data[2] |= (sk->protinfo.x25->vr << 5) & 0xE0;
+	}
+
+	x25_transmit_link(skb, sk->protinfo.x25->neighbour);	
+}
+
+void x25_kick(struct sock *sk)
+{
+	struct sk_buff *skb, *skbn;
+	int last = 1;
+	unsigned short start, end, next;
+	int modulus;
+	
+	modulus = (sk->protinfo.x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
+
+	del_timer(&sk->timer);
+
+	start = (skb_peek(&sk->protinfo.x25->ack_queue) == NULL) ? sk->protinfo.x25->va : sk->protinfo.x25->vs;
+	end   = (sk->protinfo.x25->va + sk->protinfo.x25->facilities.window_size) % modulus;
+
+	if (!(sk->protinfo.x25->condition & X25_COND_PEER_RX_BUSY) &&
+	    start != end                                           &&
+	    skb_peek(&sk->write_queue) != NULL) {
+
+		sk->protinfo.x25->vs = start;
+
+		/*
+		 * Transmit data until either we're out of data to send or
+		 * the window is full.
+		 */
+
+		/*
+		 * Dequeue the frame and copy it.
+		 */
+		skb  = skb_dequeue(&sk->write_queue);
+
+		do {
+			if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) {
+				skb_queue_head(&sk->write_queue, skb);
+				break;
+			}
+
+			next = (sk->protinfo.x25->vs + 1) % modulus;
+			last = (next == end);
+
+			/*
+			 * Transmit the frame copy.
+			 */
+			x25_send_iframe(sk, skbn);
+
+			sk->protinfo.x25->vs = next;
+
+			/*
+			 * Requeue the original data frame.
+			 */
+			skb_queue_tail(&sk->protinfo.x25->ack_queue, skb);
+
+		} while (!last && (skb = skb_dequeue(&sk->write_queue)) != NULL);
+
+		sk->protinfo.x25->vl         = sk->protinfo.x25->vr;
+		sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
+		sk->protinfo.x25->timer      = 0;
+	}
+
+	x25_set_timer(sk);
+}
+
+/*
+ * The following routines are taken from page 170 of the 7th ARRL Computer
+ * Networking Conference paper, as is the whole state machine.
+ */
+
+void x25_enquiry_response(struct sock *sk)
+{
+	if (sk->protinfo.x25->condition & X25_COND_OWN_RX_BUSY)
+		x25_write_internal(sk, X25_RNR);
+	else
+		x25_write_internal(sk, X25_RR);
+
+	sk->protinfo.x25->vl         = sk->protinfo.x25->vr;
+	sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
+	sk->protinfo.x25->timer      = 0;
+}
+
+void x25_check_iframes_acked(struct sock *sk, unsigned short nr)
+{
+	if (sk->protinfo.x25->vs == nr) {
+		x25_frames_acked(sk, nr);
+	} else {
+		if (sk->protinfo.x25->va != nr) {
+			x25_frames_acked(sk, nr);
+		}
+	}
+}
+
+#endif
diff -u --recursive --new-file v2.1.15/linux/net/x25/x25_route.c linux/net/x25/x25_route.c
--- v2.1.15/linux/net/x25/x25_route.c	Thu Jan  1 02:00:00 1970
+++ linux/net/x25/x25_route.c	Wed Dec 18 12:07:56 1996
@@ -0,0 +1,267 @@
+/*
+ *	X.25 Packet Layer release 001
+ *
+ *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
+ *	releases, misbehave and/or generally screw up. It might even work. 
+ *
+ *	This code REQUIRES 2.1.15 or higher
+ *
+ *	This module:
+ *		This module 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.
+ *
+ *	History
+ *	X.25 001	Jonathan Naylor	Started coding.
+ */
+ 
+#include <linux/config.h>
+#if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <net/arp.h>
+#include <linux/if_arp.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <linux/fcntl.h>
+#include <linux/termios.h>	/* For TIOCINQ/OUTQ */
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <linux/firewall.h>
+#include <net/x25.h>
+
+static struct x25_route *x25_route_list = NULL;
+
+/*
+ *	Add a new route.
+ */
+static int x25_add_route(x25_address *address, unsigned int sigdigits, struct device *dev)
+{
+	struct x25_route *x25_route;
+	unsigned long flags;
+
+	for (x25_route = x25_route_list; x25_route != NULL; x25_route = x25_route->next)
+		if (memcmp(&x25_route->address, address, sigdigits) == 0 && x25_route->sigdigits == sigdigits)
+			return -EINVAL;
+
+	if ((x25_route = (struct x25_route *)kmalloc(sizeof(*x25_route), GFP_ATOMIC)) == NULL)
+		return -ENOMEM;
+
+	x25_route->address   = *address;
+	x25_route->sigdigits = sigdigits;
+	x25_route->dev       = dev;
+
+	save_flags(flags); cli();
+	x25_route->next = x25_route_list;
+	x25_route_list  = x25_route;
+	restore_flags(flags);
+		
+	return 0;
+}
+
+static void x25_remove_route(struct x25_route *x25_route)
+{
+	struct x25_route *s;
+	unsigned long flags;
+	
+	save_flags(flags);
+	cli();
+
+	if ((s = x25_route_list) == x25_route) {
+		x25_route_list = x25_route->next;
+		restore_flags(flags);
+		kfree_s(x25_route, sizeof(struct x25_route));
+		return;
+	}
+
+	while (s != NULL && s->next != NULL) {
+		if (s->next == x25_route) {
+			s->next = x25_route->next;
+			restore_flags(flags);
+			kfree_s(x25_route, sizeof(struct x25_route));
+			return;
+		}
+
+		s = s->next;
+	}
+
+	restore_flags(flags);
+}
+
+static int x25_del_route(x25_address *address, unsigned int sigdigits, struct device *dev)
+{
+	struct x25_route *x25_route;
+	
+	for (x25_route = x25_route_list; x25_route != NULL; x25_route = x25_route->next) {
+		if (memcmp(&x25_route->address, address, sigdigits) == 0 && x25_route->sigdigits == sigdigits && x25_route->dev == dev) {
+			x25_remove_route(x25_route);
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+/*
+ *	A device has been removed, remove its routes.
+ */
+void x25_route_device_down(struct device *dev)
+{
+	struct x25_route *route, *x25_route = x25_route_list;
+
+	while (x25_route != NULL) {
+		route     = x25_route;
+		x25_route = x25_route->next;
+		
+		if (route->dev == dev)
+			x25_remove_route(route);
+	}
+}
+
+/*
+ *	Check that the device given is a valid X.25 interface that is "up".
+ */
+struct device *x25_dev_get(char *devname)
+{
+	struct device *dev;
+
+	if ((dev = dev_get(devname)) == NULL)
+		return NULL;
+
+	if ((dev->flags & IFF_UP) && (dev->type == ARPHRD_X25 || dev->type == ARPHRD_ETHER))
+		return dev;
+
+	return NULL;
+}
+
+/*
+ *	Find a device given an X.25 address.
+ */
+struct device *x25_get_route(x25_address *addr)
+{
+	struct x25_route *route, *use = NULL;
+	
+	for (route = x25_route_list; route != NULL; route = route->next) {
+		if (memcmp(&route->address, addr, route->sigdigits) == 0) {
+			if (use == NULL) {
+				use = route;
+			} else {
+				if (route->sigdigits > use->sigdigits)
+					use = route;
+			}
+		}
+	}
+
+	return (use != NULL) ? use->dev : NULL;
+}
+
+/*
+ *	Handle the ioctls that control the routing functions.
+ */
+int x25_route_ioctl(unsigned int cmd, void *arg)
+{
+	struct x25_route_struct x25_route;
+	struct device *dev;
+	int err;
+
+	switch (cmd) {
+
+		case SIOCADDRT:
+			if ((err = verify_area(VERIFY_READ, arg, sizeof(struct x25_route_struct))) != 0)
+				return err;
+			copy_from_user(&x25_route, arg, sizeof(struct x25_route_struct));
+			if (x25_route.sigdigits < 0 || x25_route.sigdigits > 15)
+				return -EINVAL;
+			if ((dev = x25_dev_get(x25_route.device)) == NULL)
+				return -EINVAL;
+			return x25_add_route(&x25_route.address, x25_route.sigdigits, dev);
+
+		case SIOCDELRT:
+			if ((err = verify_area(VERIFY_READ, arg, sizeof(struct x25_route_struct))) != 0)
+				return err;
+			copy_from_user(&x25_route, arg, sizeof(struct x25_route_struct));
+			if (x25_route.sigdigits < 0 || x25_route.sigdigits > 15)
+				return -EINVAL;
+			if ((dev = x25_dev_get(x25_route.device)) == NULL)
+				return -EINVAL;
+			return x25_del_route(&x25_route.address, x25_route.sigdigits, dev);
+
+		default:
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+int x25_routes_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+{
+	struct x25_route *x25_route;
+	int len     = 0;
+	off_t pos   = 0;
+	off_t begin = 0;
+
+	cli();
+
+	len += sprintf(buffer, "address         digits  device\n");
+
+	for (x25_route = x25_route_list; x25_route != NULL; x25_route = x25_route->next) {
+		len += sprintf(buffer + len, "%-15s %2d %-4s\n",
+			x25_route->address.x25_addr, x25_route->sigdigits,
+			(x25_route->dev != NULL) ? x25_route->dev->name : "???");
+
+		pos = begin + len;
+
+		if (pos < offset) {
+			len   = 0;
+			begin = pos;
+		}
+		
+		if (pos > offset + length)
+			break;
+	}
+
+	sti();
+
+	*start = buffer + (offset - begin);
+	len   -= (offset - begin);
+
+	if (len > length) len = length;
+
+	return len;
+} 
+
+#ifdef MODULE
+
+/*
+ *	Release all memory associated with X.25 routing structures.
+ */
+void x25_route_free(void)
+{
+	struct x25_route *route, *x25_route = x25_route_list;
+
+	while (x25_route != NULL) {
+		route     = x25_route;
+		x25_route = x25_route->next;
+		
+		x25_remove_route(route);
+	}
+}
+
+#endif
+
+#endif
diff -u --recursive --new-file v2.1.15/linux/net/x25/x25_subr.c linux/net/x25/x25_subr.c
--- v2.1.15/linux/net/x25/x25_subr.c	Thu Jan  1 02:00:00 1970
+++ linux/net/x25/x25_subr.c	Wed Dec 18 12:07:56 1996
@@ -0,0 +1,432 @@
+/*
+ *	X.25 Packet Layer release 001
+ *
+ *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
+ *	releases, misbehave and/or generally screw up. It might even work. 
+ *
+ *	This code REQUIRES 2.1.15 or higher
+ *
+ *	This module:
+ *		This module 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.
+ *
+ *	History
+ *	X.25 001	Jonathan Naylor	Started coding.
+ */
+ 
+#include <linux/config.h>
+#if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <net/x25.h>
+
+/*
+ *	This routine purges all of the queues of frames.
+ */
+void x25_clear_queues(struct sock *sk)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&sk->write_queue)) != NULL) {
+		skb->sk = sk;
+		kfree_skb(skb, FREE_WRITE);
+	}
+
+	while ((skb = skb_dequeue(&sk->protinfo.x25->ack_queue)) != NULL) {
+		skb->sk = sk;
+		kfree_skb(skb, FREE_WRITE);
+	}
+
+	while ((skb = skb_dequeue(&sk->protinfo.x25->interrupt_queue)) != NULL) {
+		skb->sk = sk;
+		kfree_skb(skb, FREE_WRITE);
+	}
+
+	while ((skb = skb_dequeue(&sk->protinfo.x25->fragment_queue)) != NULL) {
+		skb->sk = sk;
+		kfree_skb(skb, FREE_READ);
+	}
+}
+
+/*
+ * This routine purges the input queue of those frames that have been
+ * acknowledged. This replaces the boxes labelled "V(a) <- N(r)" on the
+ * SDL diagram.
+ */
+void x25_frames_acked(struct sock *sk, unsigned short nr)
+{
+	struct sk_buff *skb;
+	int modulus;
+	
+	modulus = (sk->protinfo.x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
+
+	/*
+	 * Remove all the ack-ed frames from the ack queue.
+	 */
+	if (sk->protinfo.x25->va != nr) {
+		while (skb_peek(&sk->protinfo.x25->ack_queue) != NULL && sk->protinfo.x25->va != nr) {
+		        skb     = skb_dequeue(&sk->protinfo.x25->ack_queue);
+		        skb->sk = sk;
+			kfree_skb(skb, FREE_WRITE);
+			sk->protinfo.x25->va = (sk->protinfo.x25->va + 1) % modulus;
+		}
+	}
+}
+
+/*
+ * Requeue all the un-ack-ed frames on the output queue to be picked
+ * up by x25_kick called from the timer. This arrangement handles the
+ * possibility of an empty output queue.
+ */
+void x25_requeue_frames(struct sock *sk)
+{
+	struct sk_buff *skb, *skb_prev = NULL;
+
+	while ((skb = skb_dequeue(&sk->protinfo.x25->ack_queue)) != NULL) {
+		if (skb_prev == NULL)
+			skb_queue_head(&sk->write_queue, skb);
+		else
+			skb_append(skb_prev, skb);
+		skb_prev = skb;
+	}
+}
+
+/*
+ *	Validate that the value of nr is between va and vs. Return true or
+ *	false for testing.
+ */
+int x25_validate_nr(struct sock *sk, unsigned short nr)
+{
+	unsigned short vc = sk->protinfo.x25->va;
+	int modulus;
+
+	modulus = (sk->protinfo.x25->neighbour->extended) ? X25_EMODULUS : X25_SMODULUS;
+
+	while (vc != sk->protinfo.x25->vs) {
+		if (nr == vc) return 1;
+		vc = (vc + 1) % modulus;
+	}
+	
+	if (nr == sk->protinfo.x25->vs) return 1;
+
+	return 0;
+}
+
+/* 
+ *  This routine is called when the packet layer internally generates a
+ *  control frame.
+ */
+void x25_write_internal(struct sock *sk, int frametype)
+{
+	struct sk_buff *skb;
+	unsigned char  *dptr;
+	unsigned char  facilities[X25_MAX_FAC_LEN];
+	unsigned char  addresses[1 + X25_ADDR_LEN];
+	unsigned char  lci1, lci2;
+	int len;
+
+	/*
+	 *	Default safe frame size.
+	 */
+	len = X25_MAX_L2_LEN + X25_EXT_MIN_LEN;
+
+	/*
+	 *	Adjust frame size.
+	 */	
+	switch (frametype) {
+		case X25_CALL_REQUEST:
+			len += 1 + X25_ADDR_LEN + X25_MAX_FAC_LEN;
+			break;
+		case X25_CALL_ACCEPTED:
+			len += 1 + X25_MAX_FAC_LEN;
+			break;
+		case X25_CLEAR_REQUEST:
+		case X25_RESET_REQUEST:
+			len += 2;
+			break;
+		case X25_RR:
+		case X25_RNR:
+		case X25_REJ:
+		case X25_CLEAR_CONFIRMATION:
+		case X25_INTERRUPT_CONFIRMATION:
+		case X25_RESET_CONFIRMATION:
+			break;
+		default:
+			printk(KERN_ERR "X.25: invalid frame type %02X\n", frametype);
+			return;
+	}
+	
+	if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
+		return;
+
+	/*
+	 *	Space for Ethernet and 802.2 LLC headers.
+	 */
+	skb_reserve(skb, X25_MAX_L2_LEN);
+	
+	/*
+	 *	Make space for the GFI and LCI, and fill them in.
+	 */
+	dptr = skb_put(skb, 2);
+
+	lci1 = (sk->protinfo.x25->lci >> 8) & 0x0F;
+	lci2 = (sk->protinfo.x25->lci >> 0) & 0xFF;
+
+	if (sk->protinfo.x25->neighbour->extended) {
+		*dptr++ = lci1 | X25_GFI_EXTSEQ;
+		*dptr++ = lci2;
+	} else {
+		*dptr++ = lci1 | X25_GFI_STDSEQ;
+		*dptr++ = lci2;
+	}
+
+	/*
+	 *	Now fill in the frame type specific information.
+	 */
+	switch (frametype) {
+	
+		case X25_CALL_REQUEST:
+			dptr    = skb_put(skb, 1);
+			*dptr++ = X25_CALL_REQUEST;
+			len     = x25_addr_aton(addresses, &sk->protinfo.x25->dest_addr, &sk->protinfo.x25->source_addr);
+			dptr    = skb_put(skb, len);
+			memcpy(dptr, addresses, len);
+			len     = x25_create_facilities(facilities, &sk->protinfo.x25->facilities);
+			dptr    = skb_put(skb, len);
+			memcpy(dptr, facilities, len);
+			break;
+
+		case X25_CALL_ACCEPTED:
+			dptr    = skb_put(skb, 2);
+			*dptr++ = X25_CALL_ACCEPTED;
+			*dptr++ = 0x00;		/* Address lengths */
+			len     = x25_create_facilities(facilities, &sk->protinfo.x25->facilities);
+			dptr    = skb_put(skb, len);
+			memcpy(dptr, facilities, len);
+			break;
+
+		case X25_CLEAR_REQUEST:
+		case X25_RESET_REQUEST:
+			dptr    = skb_put(skb, 3);
+			*dptr++ = frametype;
+			*dptr++ = 0x00;		/* XXX */
+			*dptr++ = 0x00;		/* XXX */
+			break;
+
+		case X25_RR:
+		case X25_RNR:
+		case X25_REJ:
+			if (sk->protinfo.x25->neighbour->extended) {
+				dptr     = skb_put(skb, 2);
+				*dptr++  = frametype;
+				*dptr++  = (sk->protinfo.x25->vr << 1) & 0xFE;
+			} else {
+				dptr     = skb_put(skb, 1);
+				*dptr    = frametype;
+				*dptr++ |= (sk->protinfo.x25->vr << 5) & 0xE0;
+			}
+			break;
+		
+		case X25_CLEAR_CONFIRMATION:
+		case X25_INTERRUPT_CONFIRMATION:
+		case X25_RESET_CONFIRMATION:
+			dptr  = skb_put(skb, 1);
+			*dptr = frametype;
+			break;
+	}
+
+	x25_transmit_link(skb, sk->protinfo.x25->neighbour);
+}
+
+/*
+ *	Unpick the contents of the passed X.25 Packet Layer frame.
+ */
+int x25_decode(struct sock *sk, struct sk_buff *skb, int *ns, int *nr, int *q, int *d, int *m)
+{
+	unsigned char *frame;
+	
+	frame = skb->data;
+	
+	*ns = *nr = *q = *d = *m = 0;
+
+	switch (frame[2]) {
+		case X25_CALL_REQUEST:
+		case X25_CALL_ACCEPTED:
+		case X25_CLEAR_REQUEST:
+		case X25_CLEAR_CONFIRMATION:
+		case X25_INTERRUPT:
+		case X25_INTERRUPT_CONFIRMATION:
+		case X25_RESET_REQUEST:
+		case X25_RESET_CONFIRMATION:
+		case X25_RESTART_REQUEST:
+		case X25_RESTART_CONFIRMATION:
+		case X25_REGISTRATION_REQUEST:
+		case X25_REGISTRATION_CONFIRMATION:
+		case X25_DIAGNOSTIC:
+			return frame[2];
+	}
+
+	if (sk->protinfo.x25->neighbour->extended) {
+		if (frame[2] == X25_RR  ||
+		    frame[2] == X25_RNR ||
+		    frame[2] == X25_REJ) {
+			*nr = (frame[3] >> 1) & 0x7F;
+			return frame[2];
+		}
+	} else {
+		if ((frame[2] & 0x1F) == X25_RR  ||
+		    (frame[2] & 0x1F) == X25_RNR ||
+		    (frame[2] & 0x1F) == X25_REJ) {
+			*nr = (frame[2] >> 5) & 0x07;
+			return frame[2] & 0x1F;
+		}
+	}
+
+	if (sk->protinfo.x25->neighbour->extended) {
+		if ((frame[2] & 0x01) == X25_DATA) {
+			*q  = (frame[0] & X25_Q_BIT) == X25_Q_BIT;
+			*d  = (frame[0] & X25_D_BIT) == X25_D_BIT;
+			*m  = (frame[3] & X25_EXT_M_BIT) == X25_EXT_M_BIT;
+			*nr = (frame[3] >> 1) & 0x7F;
+			*ns = (frame[2] >> 1) & 0x7F;
+			return X25_DATA;
+		}
+	} else {
+		if ((frame[2] & 0x01) == X25_DATA) {
+			*q  = (frame[0] & X25_Q_BIT) == X25_Q_BIT;
+			*d  = (frame[0] & X25_D_BIT) == X25_D_BIT;
+			*m  = (frame[2] & X25_STD_M_BIT) == X25_STD_M_BIT;
+			*nr = (frame[2] >> 5) & 0x07;
+			*ns = (frame[2] >> 1) & 0x07;
+			return X25_DATA;
+		}
+	}
+
+	printk(KERN_DEBUG "X.25: invalid PLP frame %02X %02X %02X\n", frame[0], frame[1], frame[2]);
+	
+	return X25_ILLEGAL;
+}
+
+/*
+ *	Parse a set of facilities into the facilities structure. Unrecognised
+ *	facilities are written to the debug log file.
+ */
+int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities)
+{
+	unsigned int len;
+	unsigned char *p = skb->data;
+
+	facilities->window_size = -1;
+	facilities->packet_size = -1;
+	facilities->throughput  = -1;
+	facilities->reverse     = -1;
+
+	len = *p++;
+
+	while (len > 0) {
+		switch (*p & X25_FAC_CLASS_MASK) {
+			case X25_FAC_CLASS_A:
+				switch (*p) {
+					case X25_FAC_REVERSE:
+						facilities->reverse = (p[1] & 0x01);
+						break;
+					case X25_FAC_THROUGHPUT:
+						facilities->throughput = p[1];
+						break;
+					default:
+						printk(KERN_DEBUG "X.25: unknown facility %02X, value %02X\n", p[0], p[1]);
+						break;
+				}
+				p   += 2;
+				len -= 2;
+				break;
+				
+			case X25_FAC_CLASS_B:
+				switch (*p) {
+					case X25_FAC_PACKET_SIZE:
+						facilities->packet_size = p[1];
+						break;
+					case X25_FAC_WINDOW_SIZE:
+						facilities->window_size = p[1];
+						break;
+					default:
+						printk(KERN_DEBUG "X.25: unknown facility %02X, values %02X, %02X\n", p[0], p[1], p[2]);
+						break;
+				}
+				p   += 3;
+				len -= 3;
+				break;
+
+			case X25_FAC_CLASS_C:
+				printk(KERN_DEBUG "X.25: unknown facility %02X, values %02X, %02X, %02X\n", p[0], p[1], p[2], p[3]);
+				p   += 4;
+				len -= 4;
+				break;
+				
+			case X25_FAC_CLASS_D:
+				printk(KERN_DEBUG "X.25: unknown facility %02X, length %d, values %02X, %02X, %02X, %02X\n", p[0], p[1], p[2], p[3], p[4], p[5]);
+				p   += p[1] + 2;
+				len -= p[1] + 2;
+				break;
+		}
+	}
+
+	return p - skb->data;
+}
+
+/*
+ *	Create a set of facilities.
+ */
+int x25_create_facilities(unsigned char *buffer, struct x25_facilities *facilities)
+{
+	unsigned char *p = buffer + 1;
+	int len;
+
+	if (facilities->reverse != -1) {
+		*p++ = X25_FAC_REVERSE;
+		*p++ = (facilities->reverse) ? 0x01 : 0x00;
+	}
+
+	if (facilities->throughput != -1) {
+		*p++ = X25_FAC_THROUGHPUT;
+		*p++ = facilities->throughput;
+	}
+
+	if (facilities->packet_size != -1) {
+		*p++ = X25_FAC_PACKET_SIZE;
+		*p++ = facilities->packet_size;
+		*p++ = facilities->packet_size;
+	}
+
+	if (facilities->window_size != -1) {
+		*p++ = X25_FAC_WINDOW_SIZE;
+		*p++ = facilities->window_size;
+		*p++ = facilities->window_size;
+	}
+
+	len       = p - buffer;
+	buffer[0] = len - 1;
+	
+	return len;
+}
+
+#endif
diff -u --recursive --new-file v2.1.15/linux/net/x25/x25_timer.c linux/net/x25/x25_timer.c
--- v2.1.15/linux/net/x25/x25_timer.c	Thu Jan  1 02:00:00 1970
+++ linux/net/x25/x25_timer.c	Wed Dec 18 12:07:56 1996
@@ -0,0 +1,166 @@
+/*
+ *	X.25 Packet Layer release 001
+ *
+ *	This is ALPHA test software. This code may break your machine, randomly fail to work with new 
+ *	releases, misbehave and/or generally screw up. It might even work. 
+ *
+ *	This code REQUIRES 2.1.15 or higher
+ *
+ *	This module:
+ *		This module 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.
+ *
+ *	History
+ *	X.25 001	Jonathan Naylor	Started coding.
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_X25) || defined(CONFIG_X25_MODULE)
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/sockios.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <net/x25.h>
+
+static void x25_timer(unsigned long);
+
+/*
+ *	Linux set/reset timer routines
+ */
+void x25_set_timer(struct sock *sk)
+{
+	unsigned long flags;
+	
+	save_flags(flags);
+	cli();
+
+	del_timer(&sk->timer);
+
+	restore_flags(flags);
+
+	sk->timer.next     = sk->timer.prev = NULL;	
+	sk->timer.data     = (unsigned long)sk;
+	sk->timer.function = &x25_timer;
+	sk->timer.expires  = jiffies + 100;
+
+	add_timer(&sk->timer);
+}
+
+static void x25_reset_timer(struct sock *sk)
+{
+	unsigned long flags;
+	
+	save_flags(flags);
+	cli();
+
+	del_timer(&sk->timer);
+
+	restore_flags(flags);
+
+	sk->timer.data     = (unsigned long)sk;
+	sk->timer.function = &x25_timer;
+	sk->timer.expires  = jiffies + 100;
+
+	add_timer(&sk->timer);
+}
+
+/*
+ *	X.25 TIMER 
+ *
+ *	This routine is called every second. Decrement timer by this
+ *	amount - if expired then process the event.
+ */
+static void x25_timer(unsigned long param)
+{
+	struct sock *sk = (struct sock *)param;
+
+	switch (sk->protinfo.x25->state) {
+		case X25_STATE_0:
+			/* Magic here: If we listen() and a new link dies before it
+			   is accepted() it isn't 'dead' so doesn't get removed. */
+			if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) {
+				del_timer(&sk->timer);
+				x25_destroy_socket(sk);
+				return;
+			}
+			break;
+
+		case X25_STATE_3:
+			/*
+			 * Check for the state of the receive buffer.
+			 */
+			if (sk->rmem_alloc < (sk->rcvbuf / 2) && (sk->protinfo.x25->condition & X25_COND_OWN_RX_BUSY)) {
+				sk->protinfo.x25->condition &= ~X25_COND_OWN_RX_BUSY;
+				sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
+				sk->protinfo.x25->vl         = sk->protinfo.x25->vr;
+				sk->protinfo.x25->timer      = 0;
+				x25_write_internal(sk, X25_RR);
+				break;
+			}
+			/*
+			 * Check for frames to transmit.
+			 */
+			x25_kick(sk);
+			break;
+
+		default:
+			break;
+	}
+
+	if (sk->protinfo.x25->timer == 0 || --sk->protinfo.x25->timer > 0) {
+		x25_reset_timer(sk);
+		return;
+	}
+
+	/*
+	 * Timer has expired, it may have been T2, T21, T22, or T23. We can tell
+	 * by the state machine state.
+	 */
+	switch (sk->protinfo.x25->state) {
+		case X25_STATE_3:	/* T2 */
+			if (sk->protinfo.x25->condition & X25_COND_ACK_PENDING) {
+				sk->protinfo.x25->condition &= ~X25_COND_ACK_PENDING;
+				x25_enquiry_response(sk);
+			}
+			break;
+
+		case X25_STATE_1:	/* T21 */
+		case X25_STATE_4:	/* T22 */
+			x25_write_internal(sk, X25_CLEAR_REQUEST);
+			sk->protinfo.x25->state = X25_STATE_2;
+			sk->protinfo.x25->timer = sk->protinfo.x25->t23;
+			break;
+
+		case X25_STATE_2:	/* T23 */
+			x25_clear_queues(sk);
+			sk->protinfo.x25->state = X25_STATE_0;
+			sk->state               = TCP_CLOSE;
+			sk->err                 = ETIMEDOUT;
+			sk->shutdown           |= SEND_SHUTDOWN;
+			if (!sk->dead)
+				sk->state_change(sk);
+			sk->dead                = 1;
+			break;
+	}
+
+	x25_set_timer(sk);
+}
+
+#endif
