diff -u --recursive --new-file v2.1.50/linux/CREDITS linux/CREDITS
--- v2.1.50/linux/CREDITS	Mon Aug 11 14:47:04 1997
+++ linux/CREDITS	Sat Aug 16 09:51:46 1997
@@ -586,11 +586,9 @@
 S: Germany
 
 N: Richard Henderson
-E: rth@tamu.edu
+E: richard@gnu.ai.mit.edu
+E: rth@cygnus.com
 D: Alpha/ELF, gcc, binutils, and glibc
-S: 304 E. North Ave.
-S: Bryan, Texas  77801-3431
-S: USA
 
 N: Sebastian Hetze
 E: she@lunetix.de
@@ -929,6 +927,13 @@
 S: Canberra  ACT  0200
 S: AUSTRALIA
 
+N: Pavel Machek
+E: pavel@atrey.karlin.mff.cuni.cz
+D: Softcursor for vga, hypertech cdrom support, vcsa bugfix
+S: Volkova 1131
+S: 198 00 Praha 9
+S: Czech Republic
+
 N: James B. MacLean
 E: macleajb@ednet.ns.ca
 W: http://www.ednet.ns.ca/~macleajb/dosemu.html
@@ -1156,7 +1161,7 @@
 D: improved memory detection code.
 
 N: Avery Pennarun
-E: apenwarr@foxnet.net
+E: apenwarr@bond.net
 D: ARCnet driver
 D: "make xconfig" improvements
 D: Various minor hacking
@@ -1654,6 +1659,14 @@
 S: Oosterstraat 23
 S: 2611 TT Delft
 S: The Netherlands
+
+N: David Woodhouse
+E: dwmw2@cam.ac.uk
+D: Extensive ARCnet rewrite
+D: ARCnet COM20020, COM90xx IO-MAP drivers
+S: Robinson College, Grange Road
+S: Cambridge. CB3 9AN
+S: England
 
 N: Frank Xia
 E: qx@math.columbia.edu
diff -u --recursive --new-file v2.1.50/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.50/linux/Documentation/Configure.help	Thu Aug 14 20:49:16 1997
+++ linux/Documentation/Configure.help	Mon Aug 18 15:21:39 1997
@@ -14,11 +14,17 @@
 # has a French translation of the whole kernel, including
 # Configure.help. This is maintained by David Bourgin
 # (dbourgin@wsc.com). 
+#   - ftp://ftp-pavia1.linux.it/pub/linux/Configure.help
+# is a work-in-progress effort of the Italian translation team,
+# currently only for the 2.0 version of this file, maintained 
+# by rubini@linux.it.
 #
 # 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
 # via ftp (user: anonymous) from sunsite.unc.edu in the directory
-# /pub/Linux/docs/HOWTO. 
+# /pub/Linux/docs/HOWTO. Before you start compiling, make sure that
+# you have the necessary versions of all programs; they are listed
+# in Documentation/Changes.
 #
 # Format of this file: description<nl>variable<nl>helptext<nl><nl>.
 # If the question being documented is of type "choice", we list only
@@ -143,17 +149,18 @@
   from the machine to itself.  Most users will answer N here.
 
 Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support
-CONFIG_BLK_DEV_IDE 
+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
-  disk/cdrom/tape/floppy drives.  Useful information about large
-  (>540MB) IDE disks, soundcard IDE ports, module support, and other
-  topics, is all contained in Documentation/ide.txt.  If you have one
-  or more IDE drives, say Y here.  If your system has no IDE drives, or
-  if memory requirements are really tight, you could say N here, and
-  select the Old harddisk driver instead to save about 13kB of memory
-  in the kernel.  To fine-tune IDE drive/interface parameters for
-  improved performance, look for the hdparm package at
+  interfaces, each being able to serve a "master" and a "slave"
+  device, for a combination of up to eight IDE disk/cdrom/tape/floppy
+  drives.  Useful information about large (>540MB) IDE disks,
+  soundcard IDE ports, module support, and other topics, is all
+  contained in Documentation/ide.txt.  If you have one or more IDE
+  drives, say Y here.  If your system has no IDE drives, or if memory
+  requirements are really tight, you could say N here, and select the
+  Old harddisk driver instead to save about 13kB of memory in the
+  kernel.  To fine-tune IDE drive/interface parameters for improved
+  performance, look for the hdparm package at
   sunsite.unc.edu:/pub/Linux/kernel/patches/diskdrives/
 
 Old harddisk (MFM/RLL/IDE) driver
@@ -326,12 +333,15 @@
   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)
+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.
+  This driver provides support for the secondary IDE interface and
+  cache of Promise IDE chipsets, e.g. DC4030 and DC5030.  This driver
+  is known to incur timeouts/retries during heavy I/O to drives
+  attached to the secondary interface.  CDROM and TAPE devices are not
+  supported yet.  This driver is enabled at runtime using the
+  "ide0=dc4030" kernel boot parameter.  See the Documentation/ide.txt
+  and drivers/block/promise.c files for more info.
 
 OPTi 82C621     support (EXPERIMENTAL)
 CONFIG_BLK_DEV_OPTI621
@@ -359,16 +369,6 @@
   I/O speeds to be set as well.  See the Documentation/ide.txt and
   ali14xx.c files for more info.
 
-PROMISE DC4030 support (EXPERIMENTAL)
-CONFIG_BLK_DEV_PROMISE
-  This driver is enabled at runtime using the "ide0=dc4030" kernel
-  boot parameter.  It enables support for the secondary IDE interface
-  of the chipset, and takes advantage of the caching features of the
-  card.  This driver is known to incur timeouts/retries during heavy
-  I/O to drives attached to the secondary interface.  CDROM and TAPE
-  devices are not supported yet.  See the Documentation/ide.txt and
-  promise.c files for more info.
-
 XT harddisk support
 CONFIG_BLK_DEV_XD
   Very old 8 bit hard disk controllers used in the IBM XT computer. To
@@ -384,9 +384,9 @@
   removable media devices you can use this driver.  Answer Y to build
   the driver into the kernel, or M if you would like to build it as a
   loadable module. The module will be called ez.o.  Read the file
-  linux/Documentation/ez.txt.  If you have several different devices
-  that will share a common parallel port you should build them all as
-  modules.
+  linux/Documentation/ez.txt.  It is possible to use several devices
+  with a single common parallel port (e.g. printer and EZ135); it is
+  safe to compile both drivers into the kernel.
 
 Multiple devices driver support
 CONFIG_BLK_DEV_MD
@@ -425,8 +425,8 @@
   kernel that runs on these, say Y here. For details about Linux
   on the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
   http://lena.fnet.fr/ (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).
+  have access to a machine on the Internet that has a program like
+  lynx or netscape).
 
 Support for Mips Magnum 3000 
 CONFIG_MIPS_MAGNUM_3000
@@ -434,25 +434,23 @@
   details about Linux on the MIPS architecture, check out the
   Linux/MIPS FAQ on the WWW at http://lena.fnet.fr/ (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).
+  a program like lynx or netscape).
 
 Support for Mips Magnum 4000
 CONFIG_MIPS_MAGNUM_4000
   This is a machine with a R4000 100 MHz CPU. To compile a Linux
-  kernel that runs on these, say Y here. For details about Linux
-  on the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
-  http://lena.fnet.fr/ (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).
+  kernel that runs on these, say Y here. For details about Linux on
+  the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
+  http://lena.fnet.fr/ (To browse the WWW, you need to have access to
+  a machine on the Internet that has a program like lynx or netscape).
 
 Support for Olivetti M700
 CONFIG_OLIVETTI_M700
   This is a machine with a R4000 100 MHz CPU. To compile a Linux
-  kernel that runs on these, say Y here. For details about Linux
-  on the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
-  http://lena.fnet.fr/ (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).
+  kernel that runs on these, say Y here. For details about Linux on
+  the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
+  http://lena.fnet.fr/ (To browse the WWW, you need to have access to
+  a machine on the Internet that has a program like lynx or netscape).
 
 Support for Deskstation Tyne
 CONFIG_DESKSTATION_TYNE
@@ -461,27 +459,26 @@
   problems. For details about Linux on the MIPS architecture, check
   out the Linux/MIPS FAQ on the WWW at http://lena.fnet.fr/ (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).
+  has a program like lynx or netscape).
 
 Support for Acer PICA 1 chipset
 CONFIG_ACER_PICA_61
   This is a machine with a R4400 134/150 MHz CPU. To compile a Linux
-  kernel that runs on these, say Y here. For details about
-  Linux on the MIPS architecture, check out the Linux/MIPS FAQ on the
-  WWW at http://lena.fnet.fr/ (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).
+  kernel that runs on these, say Y here. For details about Linux on
+  the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
+  http://lena.fnet.fr/ (To browse the WWW, you need to have access to
+  a machine on the Internet that has a program like lynx or
+  netscape).
 
 Support for DECstation
 CONFIG_DECSTATION
   The DECStation 3100 (with a MIPS R2000 series CPU) and DECStation
   5000/xxx (MIPS R3000 series CPU) are also sometimes labeled
   PMAX. They often run the Ultrix operating system. To compile a Linux
-  kernel that runs on these, say Y here. For details about Linux
-  on the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
-  http://lena.fnet.fr/ (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).
+  kernel that runs on these, say Y here. For details about Linux on
+  the MIPS architecture, check out the Linux/MIPS FAQ on the WWW at
+  http://lena.fnet.fr/ (To browse the WWW, you need to have access to
+  a machine on the Internet that has a program like lynx or netscape).
 
 CPU type
 CONFIG_CPU_R3000
@@ -538,28 +535,35 @@
 
 SYN flood protection
 CONFIG_SYN_COOKIES
-  Normal TCP/IP networking is open to an attack known as SYN flooding.
-  This attack prevents legitimate users from being able to connect to
-  your computer and requires very little work for the attacker.
+  Normal TCP/IP networking is open to an attack known as "SYN flooding".
+  This denial-of-service attack prevents legitimate remote users from
+  being able to connect to your computer and requires very little work
+  from the attacker, who can operate from anywhere on the internet.
   SYN cookies provide protection against this type of attack. With
-  this option turned on the TCP/IP stack will use a cryptographic
+  this option turned on, the TCP/IP stack will use a cryptographic
   challenge protocol known as SYN cookies to enable legitimate users
   to continue to connect, even when your machine is under attack.
-  Note that SYN cookies aren't enabled per default, you need to add
-  echo 1 >/proc/sys/net/ipv4/tcp_syncookies to one of your startup scripts
-  (e.g. /etc/rc.local or /etc/rc.d/rc.local).	
+  There is no need for the legitimate users to change their TCP/IP
+  software; SYN cookies work transparently to them.  For technical
+  information about syn cookies, check out
+  ftp://koobera.math.uic.edu/pub/docs/syncookies-archive.
+  If you say Y here, note that SYN cookies aren't enabled by default:
+  you need to add the command
+    echo 1 >/proc/sys/net/ipv4/tcp_syncookies 
+  to one of your startup scripts (e.g. /etc/rc.local or 
+  /etc/rc.d/rc.local) in addition.
+  If unsure, say Y.
 
 Socket Security API Support (EXPERIMENTAL)
 CONFIG_NET_SECURITY
-  Enable use of the socket security API. Note that Linux does not include
-  any security protocols currently and that this option only really supports
-  security on IPv4 links at the moment.
-
-Socket Security API Support (EXPERIMENTAL)
-CONFIG_NET_SECURITY
-  Enable use of the socket security API. Note that Linux does not include
-  any security protocols currently and that this option only really supports
-  security on IPv4 links at the moment.
+  Enable use of the socket security API. This option only really
+  supports security (via encryption of all traffic) over IPv4 links,
+  and then only if you add a security protocol which is also supported
+  at the other end of the link; Linux itself does not include any
+  security protocols, but you can use the enskip package at
+  ftp.tik.ee.ethz.ch/pub/packages/skip/. That package also contains
+  documentation of the API to be used for secure sockets. If unsure,
+  say N.
 
 Sun floppy controller support
 CONFIG_BLK_DEV_SUNFD
@@ -571,14 +575,16 @@
   Find out what type of Alpha motherboard you have. You will probably
   want to read the Linux/Alpha homepage on the WWW at
   http://www.azstarnet.com/~axplinux/ (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). For this question, it suffices
-  to give a unique prefix of the option you want to choose. The
-  choices:
+  have access to a machine on the Internet that has a program like
+  lynx or netscape). For this question, it suffices to give a unique
+  prefix of the option you want to choose. The choices:
   ** Avanti: This is for Mustang (AS200), M3 (AS250), Avanti (AS400)
-     and XL (a.k.a. "Windows NT Dream Machine" :-) AlphaStations.
-     These usually come with a TGA graphics adapter, so you'll want to
-     say Y to "TGA Console support", below, if you have one of these.
+     AlphaStations.  These usually come with a TGA graphics adapter,
+     so you'll want to say Y to "TGA Console support", below, if you
+     have one of these.
+  ** Alpha-XL: A.k.a. "Windows NT Dream Machine" :-) These usually 
+     come with a TGA graphics adapter, so you'll want to say Y to "TGA
+     Console support", below, if you have one of these.
   ** Jensen: a.k.a. DEC 2000 a.k.a. DECpc AXP 150, the oldest Alpha
      PC; it sports an EISA bus. The boot process on Jensen machines is
      difficult (no booting from floppies, MILO doesn't work). You need
@@ -593,15 +599,9 @@
   ** EB66: "Evaluation Board"
   ** EB66+: "Evaluation Board"
 ###
-### Add info about Platform2000, EB164
+### Add info about Platform2000, EB164, etc.
 ###
 
-Is it really a true XL
-CONFIG_ALPHA_XL
-  If your Avanti Machine is of type XL (a.k.a. "Windows NT Dream
-  Machine") (as opposed to Mustang (AS200), M3 (AS250) or Avanti
-  (AS400)), say Y, otherwise N.
-
 Using SRM as bootloader
 CONFIG_ALPHA_SRM
   There are two different types of booting firmware on Alphas: SRM,
@@ -619,8 +619,8 @@
   N. Details about the Linux/Alpha booting process are contained in
   the Linux/Alpha FAQ, accessible on the WWW from
   http://www.azstarnet.com/~axplinux/ (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).
+  have access to a machine on the Internet that has a program like
+  lynx or netscape).
 
 Non-standard serial port support
 CONFIG_SERIAL_NONSTANDARD
@@ -635,7 +635,7 @@
   can say N here.
 
 Extended dumb serial driver options
-CONFIG_SERIAL_EXTENDED  
+CONFIG_SERIAL_EXTENDED
   If you wish to use any non-standard features of the standard "dumb"
   driver, say Y here.  This includes HUB6 support, shared serial
   interrupts, special multiport support, support for more than the
@@ -750,15 +750,15 @@
   executables are distributed solely in ELF format. You definitely
   want to say Y here. Information about ELF is on the WWW at
   http://www.sjc.ox.ac.uk/users/barlow/elf-howto.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 find that
-  after upgrading to Linux kernel 1.3 and saying Y here, you still
-  can't run any ELF binaries (they just crash), then you'll have to
-  install the newest ELF runtime libraries, including ld.so (check the
-  file Documentation/Changes for location and latest version). 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. The module will be called
+  WWW, you need to have access to a machine on the Internet that has a
+  programs like lynx or netscape).  If you find that after upgrading
+  to Linux kernel 1.3 and saying Y here, you still can't run any ELF
+  binaries (they just crash), then you'll have to install the newest
+  ELF runtime libraries, including ld.so (check the file
+  Documentation/Changes for location and latest version). 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. The module will be called
   binfmt_elf.o. Saying M or N here is dangerous because some crucial
   programs on your system might be in ELF format.
 
@@ -810,18 +810,32 @@
   will be called binfmt_java.o. If you don't know what to answer at
   this point then answer Y.
 
+Kernel support for Linux/Intel ELF binaries
+CONFIG_BINFMT_EM86
+  Say Y here if you want to be able to execute Linux/Intel ELF
+  binaries just like native Alpha binaries on your machine. For this
+  to work, you need to have the emulator /usr/bin/em86 in place.  You
+  may answer M to compile the emulation support as a module and later
+  load the module when you want to use a Linux/Intel binary. The
+  module will be called binfmt_em86.o.  If unsure, say Y.
+
 Kernel support for MISC binaries
 CONFIG_BINFMT_MISC
   This enables the possibility to plug wrapper-driven binary formats
   into the kernel. You will like this especially when you use programs
-  that need an interpreter to run like Java, Python or Emacs-Lisp. And
-  you don't need CONFIG_BINFMT_JAVA or CONFIG_BINFMT_EM86, as this is
-  a more general feature.
-  You can do other nice things, too. Read Documentation/binfmt_misc.txt
-  to learn how to use this feature.
-  You must enable CONFIG_PROC_FS to use this part of the kernel.
+  that need an interpreter to run like Java, Python or
+  Emacs-Lisp. Once you have registered such a binary class with the
+  kernel, you can start such a program simply by typing in its name;
+  Linux will feed it to the correct interpreter. If you say Y here,
+  you won't need "Kernel support for JAVA binaries"
+  (CONFIG_BINFMT_JAVA) or "Kernel support for Linux/Intel ELF
+  binaries" (CONFIG_BINFMT_EM86), as this is a more general solution.
+  You can do other nice things, too. Read
+  Documentation/binfmt_misc.txt to learn how to use this feature.
+  You must enable the "proc filesystem support" (CONFIG_PROC_FS) to
+  use this part of the kernel.
   You may answer M for module support and later load the module when
-  you have use for it.
+  you have use for it.  
   If you don't know what to answer at this point, say Y.
 
 Processor type
@@ -850,6 +864,29 @@
   for more information about the Video mode selection support. If
   unsure, say N.
 
+Parallel-port support
+CONFIG_PARPORT
+  If you want to use devices connected to your parallel port (the
+  connector at the computers with 25 holes), e.g. printer, Zip drive,
+  PLIP link etc., then you need to enable this option; please read
+  Documentation/parport.txt and drivers/misc/BUGS-parport.  It
+  is possible to share a single parallel port among several devices
+  and it is safe to compile all the corresponding drivers into the
+  kernel. If you want to compile parallel port 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. The module will be called parport.o.  If
+  you have more than one parallel port and want to specify which port
+  and IRQ to use by this driver at module load time, read
+  Documentation/networking/net-modules.txt.
+
+PC-style hardware 
+CONFIG_PARPORT_PC
+  You should enable this option if you have a PC-style parallel
+  port. All IBM PC compatible computers and some Alphas have PC-style
+  parallel ports.  This driver is also available as a module which
+  will be called parport_pc.o.
+
 Compile the kernel into the ELF object format 
 CONFIG_ELF_KERNEL
   ELF (Executable and Linkable Format) is a format for libraries and
@@ -876,14 +913,8 @@
   Plug and Play support allows the kernel to automatically configure some
   peripheral devices.  Say Y to enable PnP.
 
-Parallel-port support
+Auto-probe for parallel devices
 CONFIG_PNP_PARPORT
-  If you want to use devices connected to your parallel port (printer,
-  Zip driver, PLIP link, ...) then you should enable this option and
-  read Documentation/parport.txt.
-
-Autoprobe for parallel device IDs
-CONFIG_PNP_PARPORT_AUTOPROBE
   Some IEEE-1284 conformant parallel-port devices can identify themselves
   when requested.  If this option is enabled the kernel will probe to see
   what devices are connected at boot time.
@@ -942,9 +973,10 @@
   here, the kernel's internal ARP cache will never grow to more than
   256 entries (the oldest entries are expired in a LIFO manner) and
   communication will be attempted with an external ARP daemon, arpd.
-  This code is still experimental.  If you do say Y here, you
-  should obtain a copy of arpd from
-  http://www.loran.com/~layes/arpd/index.html.  If unsure, say N.
+  This code is still experimental.  If you do say Y here, you should
+  obtain a copy of arpd from http://www.loran.com/~layes/arpd/index.html, 
+  and you should say Y to "Kernel/User network link driver", below.
+  If unsure, say N.
 
 TCP/IP networking
 CONFIG_INET
@@ -957,9 +989,8 @@
   necessary if you want to use the full power of term (term is a
   program which gives you almost full Internet connectivity if you
   have a regular dial up shell account on some Internet connected Unix
-  computer. Read the Term-HOWTO, available via ftp (user: anonymous)
-  on sunsite.unc.edu:/pub/Linux/docs/HOWTO).  Short answer:
-  say Y.
+  computer. Read http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html).
+  Short answer: say Y.
 
 IP: multicasting
 CONFIG_IP_MULTICAST
@@ -971,9 +1002,9 @@
   of the internet which carries audio and video broadcasts. More
   information about the MBONE is on the WWW at
   http://www.best.com/~prince/techinfo/mbone.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). Information about the
-  multicast capabilities of the various network cards is contained in
+  you need to have access to a machine on the Internet that has a
+  program like lynx or netscape). Information about the multicast
+  capabilities of the various network cards is contained in
   drivers/net/README.multicast. For most people, it's safe to say N.
 
 IP: optimize as router not host
@@ -983,6 +1014,11 @@
   packets to another host this is however a loss. This parameter turns
   off copy and checksum from devices. It may make other changes in the
   future.
+  Note that your box can only act as a router if you say Y to "/proc
+  filesystem support" below and you enable IP forwarding in your
+  kernel; you can do this from within a boot-time script like so:
+    echo "1" > /proc/sys/net/ipv4/ip_forwarding
+  after the /proc filesystem has been mounted.  If unsure, say N here.
 
 IP: firewalling
 CONFIG_IP_FIREWALL
@@ -993,8 +1029,13 @@
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also, you will need the
   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
-  say Y to "IP firewalling" in order to be able to use IP masquerading
+  internet traffic based on type, origin and destination.  The
+  firewalling code will only work if you say Y to "/proc filesystem
+  support" below and IP forwarding is enabled in your kernel; do this
+  from within a boot-time script like so: 
+    echo "1" > /proc/sys/net/ipv4/ip_forwarding
+  after the /proc filesystem has been mounted.  You need to say Y to
+  "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
@@ -1089,7 +1130,7 @@
   read Documentation/modules.txt for details.
 
 IP: always defragment 
-CONFIG_IP_ALWAYS_DEFRAG 
+CONFIG_IP_ALWAYS_DEFRAG
   This option means that all incoming fragments (= parts of IP packets
   that arose when some host between origin and destination decided
   that the IP packets were too large and cut them in pieces) will be
@@ -1116,13 +1157,13 @@
   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
-  there are two logical networks living on your local ethernet and you
-  want to access them both with the same ethernet card. The
-  configuration of these alias addresses is done with a special name
-  syntax explained in Documentation/networking/alias.txt. If you want
-  this, say Y. Most people don't need it and say N.
+  need to have access to a machine on the Internet that has a program
+  like lynx or netscape). Another scenario would be that there are two
+  logical networks living on your local ethernet and you want to
+  access them both with the same ethernet card. The configuration of
+  these alias addresses is done with a special name syntax explained
+  in Documentation/networking/alias.txt. If you want this, say Y. Most
+  people don't need it and say N.
 
 IP: multicast routing
 CONFIG_IP_MROUTE
@@ -1180,11 +1221,13 @@
   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
-  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 Documentation/networking/ncsa-telnet for the location
-  of fixed NCSA telnet clients. If in doubt, say N.
+  we adjust to a smaller size. This is good, so most people say N
+  here, thereby not disabling it. However, some DOS software (versions
+  of DOS NCSA telnet and Trumpet Winsock in PPP mode) is broken and
+  won't be able to connect to your Linux machine correctly in all
+  cases (especially through a terminal server) unless you say Y
+  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
@@ -1244,11 +1287,12 @@
   http://playground.sun.com/pub/ipng/html/ipng-main.html; for specific
   information about IPv6 under Linux read the HOWTO at
   http://www.terra.net/ipv6/ 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). The module will be called ipv6.o. 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.
+  kernel source. If you want to use IPv6, please upgrade to the newest
+  net-tools as given in Documentation/Changes. The IPv6 support is
+  also available as a module ( = code which can be inserted in and
+  removed from the running kernel whenever you want). The module will
+  be called ipv6.o. 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
@@ -1311,27 +1355,28 @@
 Appletalk DDP
 CONFIG_ATALK
   Appletalk is the way Apple computers speak to each other on a
-  network. EtherTalk is the name used for appletalk over ethernet and
-  Localtalk is appletalk over the apple serial links. If your linux
-  box is connected to such a network and you want to join the
-  conversation, say Y. You will need to use the netatalk package so
-  that your Linux box can act as a print and file server for macs as
-  well as access appletalk printers. Check out
+  network. If your linux box is connected to such a network and you
+  want to join the conversation, say Y. You will need to use the
+  netatalk package so that your Linux box can act as a print and file
+  server for macs as well as access appletalk printers. Check out
   http://artoo.hitchcock.org/~flowerpt/projects/linux-netatalk/ on the
   WWW for details (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). The NET-2-HOWTO, available via ftp (user: anonymous) in
+  machine on the Internet that has a program like lynx or
+  netscape). EtherTalk is the name used for appletalk over ethernet
+  and the cheaper and slower LocalTalk is appletalk over a proprietary
+  apple network using serial links. Ethertalk is fully supported by
+  Linux, however the localtalk drivers are not yet ready to ship. The
+  kernel however supports localtalk and when such drivers become
+  available all you will need to do is download and install the
+  localtalk driver in order to join a Localtalk network. The
+  NET-2-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO contains valuable information
   as well. This driver is also available as a module ( = code which
   can be inserted in and removed from the running kernel whenever you
   want). The module will be called appletalk.o. If you want to compile
   it as a module, say M here and read Documentation/modules.txt. I
   hear that the GNU boycott of Apple is over, so even politically
-  correct people are allowed to say Y here.  At the time the kernel is
-  released the localtalk drivers are not yet ready to ship. The kernel
-  however supports localtalk and when such drivers become available
-  all you will need to do is download and install the localtalk
-  driver.
+  correct people are allowed to say Y here.
 
 IP-over-DDP support
 CONFIG_IPDDP
@@ -1353,23 +1398,27 @@
 
 COPS LocalTalk PC card support
 CONFIG_COPS
-  This allows you to use the COPS AppleTalk card to connect to LocalTalk
-  networks. You also need version 1.3.3 or later of the netatalk package.
-  This driver is experimental, which means that it may not work.
-  In particular the module support is not yet working for the 2.1.xx
-  kernels, so choose Y or N, but not M for now.
-  See the web site http://www.math.unm.edu/~bradford/ltpc.html for localtalk
+  This allows you to use COPS AppleTalk cards to connect to LocalTalk
+  networks. You also need version 1.3.3 or later of the netatalk
+  package.  This driver is experimental, which means that it may not
+  work.  In particular the module support is not yet working for the
+  2.1.xx kernels, so choose Y or N, but not M for now.  This driver
+  will only work if you choose "Appletalk DDP" networking support,
+  above.
+  Please read the file Documentation/networking/README.cops.  See the
+  web site http://www.math.unm.edu/~bradford/ltpc.html for localtalk
   IP tools.
 
 Dayna firmware support
 CONFIG_COPS_DAYNA
-  Support COPS compatible cards with Dayna style firmware (Dayna DL2000/
-  Daynatalk/PC (half length), COPS LT-95, Farallon PhoneNET PC III)
+  Support COPS compatible cards with Dayna style firmware (Dayna
+  DL2000/ Daynatalk/PC (half length), COPS LT-95, Farallon PhoneNET PC
+  III).
 
 Tangent firmware support
 CONFIG_COPS_TANGENT
-  Support COPS compatible cards with Tangent style firmware (Tangent ATB_II,
-  Novell NL-1000, Daystar Digital LT-200
+  Support COPS compatible cards with Tangent style firmware (Tangent
+  ATB_II, Novell NL-1000, Daystar Digital LT-200.
 
 Amateur Radio AX.25 Level 2
 CONFIG_AX25
@@ -1393,11 +1442,29 @@
   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). The module will
-  be called ax25.o. If you want to compile it as a module, say M here
-  and read Documentation/modules.txt.
+  that has a program like lynx or netscape).  This driver is also
+  available as a module ( = code which can be inserted in and removed
+  from the running kernel whenever you want). The module will be
+  called ax25.o. If you want to compile it as a module, say M here and
+  read Documentation/modules.txt.
+
+AX.25 DAMA Slave support
+CONFIG_AX25_DAMA_SLAVE
+  DAMA is a mechanism to prevent collisions when doing AX.25
+  networking. A DAMA server (called "master") accepts incoming traffic
+  from clients (called "slaves") and redistributes it to other
+  slaves. If you say Y here, your Linux box will act as a DAMA slave;
+  this is transparent in that you don't have to do any special DAMA
+  configuration. (Linux cannot yet act as a DAMA server.) If unsure,
+  say N.
+
+AX.25 DAMA Master support
+CONFIG_AX25_DAMA_MASTER
+  DAMA is a mechanism to prevent collisions when doing AX.25
+  networking. A DAMA server (called "master") accepts incoming traffic
+  from clients (called "slaves") and redistributes it to other
+  slaves. If you say Y here, your Linux box will act as a DAMA server.
+  If unsure, say N.
 
 Amateur Radio NET/ROM
 CONFIG_NETROM
@@ -1409,11 +1476,11 @@
   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). The module will be called
-  netrom.o. If you want to compile it as a module, say M here and read
+  need to have access to a machine on the Internet that has a program
+  like lynx or netscape).  This driver is also available as a module (
+  = code which can be inserted in and removed from the running kernel
+  whenever you want). The module will be called netrom.o. If you want
+  to compile it as a module, say M here and read
   Documentation/modules.txt.
 
 AX.25 over Ethernet
@@ -1436,11 +1503,11 @@
   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). The module will be called
-  rose.o. If you want to compile it as a module, say M here and read
+  need to have access to a machine on the Internet that has a program
+  like lynx or netscape).  This driver is also available as a module (
+  = code which can be inserted in and removed from the running kernel
+  whenever you want). The module will be called rose.o. If you want to
+  compile it as a module, say M here and read
   Documentation/modules.txt.
 
 CCITT X.25 Packet Layer
@@ -1462,25 +1529,30 @@
   Documentation/networking/x25.txt and
   Documentation/networking/x25-iface.txt.  One connects to an X.25
   network either with a dedicated network card using the X.21 protocol
-  (not yet supported by Linux) or one can do X.25 over ethernet using
-  an ordinary ethernet card and either the 802.2 LLC protocol (say Y
-  to "802.2 LLC" below) or LAPB over ethernet (say Y to "LAPB Data
-  Link Driver" and "LAPB over Ethernet driver" below).  If you want to
-  compile this driver as a module though ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt. The module will be
-  called x25.o. If unsure, say N.
+  (not yet supported by Linux) or one can do X.25 over a standard
+  telephone line using an ordinary modem (say Y to "X.25 async driver"
+  below) or over ethernet using an ordinary ethernet card and either
+  the 802.2 LLC protocol (say Y to "802.2 LLC" below) or LAPB over
+  ethernet (say Y to "LAPB Data Link Driver" and "LAPB over Ethernet
+  driver" below).  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. The module will be called x25.o. If
+  unsure, say N.
 
 LAPB Data Link Driver (EXPERIMENTAL) 
 CONFIG_LAPB
-  Link Access Procedure, Balanced (LAPB) is the data link layer part
-  of the X.25 protocol. It offers a reliable connection service to
-  exchange data frames with one other host, and it is used to
-  transport higher level protocols (mostly X.25 Packet Layer, but
-  others are possible as well).  If you want to use LAPB connections
-  over ethernet, say Y here and to "LAPB over Ethernet driver" below.
-  Read Documentation/networking/lapb-module.txt for technical details.
-  If you want to compile this driver as a module though ( = code which
+  Link Access Procedure, Balanced (LAPB) is the data link layer
+  (i.e. the lower) part of the X.25 protocol. It offers a reliable
+  connection service to exchange data frames with one other host, and
+  it is used to transport higher level protocols (mostly X.25 Packet
+  Layer, the higher part of X.25, but others are possible as
+  well). Usually, LAPB is used with specialized X.21 network cards, but
+  Linux currently supports LAPB only over ethernet connections. If you
+  want to use LAPB connections over ethernet, say Y here and to "LAPB
+  over Ethernet driver" below.  Read
+  Documentation/networking/lapb-module.txt for technical details.  If
+  you want to compile this driver as a module though ( = code which
   can be inserted in and removed from the running kernel whenever you
   want), say M here and read Documentation/modules.txt. The module
   will be called lapb.o.  If unsure, say N.
@@ -1544,7 +1616,7 @@
   and read Documentation/modules.txt and
   Documentation/scsi.txt. However, do not compile this as a module if
   your root filesystem (the one containing the directory /) is located
-  on a SCSI disk.
+  on a SCSI device.
 
 SCSI disk support
 CONFIG_BLK_DEV_SD
@@ -1589,7 +1661,7 @@
   required for some stuff which is newer than the SCSI-II standard:
   MultiSession CD support and some ioctls for reading Mode 2 Form 2
   sectors. You'll probably want to say Y here, unless you have a
-  _real old_ CD-ROM drive.
+  _really old_ CD-ROM drive.
 
 SCSI generic support
 CONFIG_CHR_DEV_SG
@@ -1676,12 +1748,13 @@
 CONFIG_SCSI_AIC7XXX
   Information about this SCSI host adapter is contained in
   drivers/scsi/README.aic7xxx and in the SCSI-HOWTO, available via ftp
-  (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that
-  the AHA2920 SCSI host adapter is *not* supported by this driver; choose
-  "Future Domain 16xx SCSI support" instead. If you want to compile this
-  driver as module ( = code which can be inserted in and removed from the
-  running kernel whenever you want), say M here and read Documentation/
-  modules.txt. The module will be called aic7xxx.o.
+  (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note
+  that the AHA2920 SCSI host adapter is *not* supported by this
+  driver; choose "Future Domain 16xx SCSI support" instead. 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. The module will be
+  called aic7xxx.o.
 
 Enable tagged command queueing
 CONFIG_AIC7XXX_TAGGED_QUEUEING
@@ -1689,45 +1762,55 @@
   driver.  Some scsi devices do not properly support this
   feature.  Tagged command queueing will improve performance.
 
+Override driver defaults for commands per LUN
+CONFIG_OVERRIDE_CMDS
+  This option allows you to set the maximum number of SCSI commands
+  queued per LUN (Logical Unit Number - some physical SCSI devices,
+  e.g. CD jukeboxes, act logically as several logical units).  If you
+  say N here, the driver will attempt to set the commands per LUN
+  using its own reasonable heuristic. If you say Y, you can specify
+  your preference in the next question.  If unsure, say N.
+
 Maximum number of commands per LUN
-  CONFIG_AIC7XXX_CMDS_PER_LUN
-  This option allows you to set the maximum number of commands queued
-  per LUN.  If tagged queueing is enabled, then you may want to try
-  increasing AIC7XXX_CMDS_PER_LUN to more than 2.  By default, we limit
-  the SCBs per LUN to 2 with or without tagged queueing enabled.  If
-  tagged queueing is disabled, the sequencer will keep the 2nd SCB in
-  the input queue until the first one completes - so it is OK to to have
-  more than 1 SCB queued.  If tagged queueing is enabled, then the
-  sequencer will attempt to send the 2nd SCB to the device while the
-  first SCB is executing and the device is disconnected.  For adapters
-  limited to 4 SCBs, you may want to actually decrease the commands per
-  LUN to 1, if you often have more than 2 devices active at the same
-  time.  This will allocate 1 SCB for each device and ensure that there
-  will always be a free SCB for up to 4 devices active at the same time.
-  When SCB paging is enabled, set the commands per LUN to 8 or higher
-  (see SCB paging support below).  Note that if AIC7XXX_CMDS_PER_LUN is
-  not defined and tagged queueing is enabled, the driver will attempt to
-  set the commands per LUN using its own heuristic based on the number
-  of available SCBs.
+CONFIG_AIC7XXX_CMDS_PER_LUN
+  If tagged queueing is enabled, then you may want to try increasing
+  the number of SCSI commands per LUN to more than 2.  By default, we
+  limit the commands per LUN to 2 with or without tagged queueing
+  enabled.  If tagged queueing is disabled, the sequencer in the host
+  adapter will keep the 2nd command in the input queue until the first
+  one completes - so it is OK to have more than 1 command queued.  If
+  tagged queueing is enabled, then the sequencer will attempt to send
+  the 2nd command block to the device while the first command block is
+  executing and the device is disconnected.  For adapters limited to 4
+  command blocks (SCB's), you may want to actually decrease the
+  commands per LUN to 1, if you often have more than 2 devices active
+  at the same time.  This will ensure that there will always be a free
+  SCB for up to 4 devices active at the same time.  When SCB paging is
+  enabled, set the commands per LUN to 8 or higher (see "SCB paging
+  support" below).  If unsure, go with the default for now.
 
 Enable SCB paging
 CONFIG_AIC7XXX_PAGE_ENABLE
   This option enables SCB paging.  This will increase performance when
-  tagged queueing is enabled.  Note that you should increase the
-  AIC7XXX_CMDS_PER_LUN to 8 as most tagged queueing devices allow at
-  least this many.  Note that EISA and VLB controllers do not support
-  SCB paging due to chip limitations; enabling it on these controllers
-  has no effect.
+  tagged queueing is enabled.  Note that, if you say Y here, you
+  should increase the "Maximum number of commands per LUN"
+  (AIC7XXX_CMDS_PER_LUN) above to 8 as most tagged queueing devices
+  allow at least this many.  Note that EISA and VLB controllers do not
+  support SCB paging due to chip limitations; enabling it on these
+  controllers has no effect.
 
 Collect statistics to report in /proc
 CONFIG_AIC7XXX_PROC_STATS
   This option enables collection of SCSI transfer statistics for the
   /proc filesystem.  This does affect performance since it has to
-  maintain statistics.
+  maintain statistics. The statistics will appear under
+  /proc/scsi/aic7xxx. This will only work if you also enable the "proc
+  filesystem", below.
 
 Delay in seconds after SCSI bus reset
 CONFIG_AIC7XXX_RESET_DELAY
-  This option sets the delay in seconds after a SCSI bus reset.
+  This option sets the delay in seconds after a SCSI bus reset. If you
+  don't know what you are doing, go with the default.
 
 BusLogic SCSI support
 CONFIG_SCSI_BUSLOGIC
@@ -1935,7 +2018,7 @@
   Intel-based hardware.
   Under Linux/Alpha only normal IO is currently supported by the driver 
   and so, this option has no effect.
-  The normal answer therefore is N.
+  The normal answer therefore is N. Try Y only if you have problems.
 
 not allow targets to disconnect
 CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
@@ -1945,6 +2028,25 @@
   not allow targets to disconnect is not reasonable if there is more
   than 1 device on a scsi bus.  The normal answer therefore is N.
 
+detect and read serial NVRAMs
+CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT
+  Enable support for reading the serial NVRAM data on Symbios and some
+  Symbios compatible cards, and Tekram DC390W/U/F cards. Useful for
+  systems with more than one Symbios compatible controller where at
+  least one has a serial NVRAM, or for a system with a mixture of
+  Symbios and Tekram cards. Enables setting the boot order of host
+  adaptors to something other than the default order or "reverse
+  probe" order.  Also enables Symbios and Tekram cards to be
+  distinguished so that the option "assume boards are SYMBIOS
+  compatible" (CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT) below may be set
+  in a system with a mixture of Symbios and Tekram cards so that the
+  Symbios cards can make use of the full range of Symbios features,
+  differential, led pin, without causing problems for the Tekram
+  card(s).  Also enables setting host and targets SCSI features as
+  defined in the user setup for each host using a serial NVRAM. Read
+  drivers/scsi/README.ncr53c8xx for more information. The default
+  answer is N, the normal answer should be Y.
+
 enable tagged command queuing
 CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE
   This option allows you to enable tagged command queuing support at
@@ -1967,25 +2069,6 @@
   possible.  The default value is 4. Minimum is 2, maximum is 12.  The
   normal answer therefore is the default one.
 
-detect and read serial NVRAM
-CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT
-  Enable support for reading the serial NVRAM data on Symbios and
-  some Symbios compatible cards, and Tekram DC390W/U/F cards. Useful for
-  systems with more than one Symbios compatible controller where at least
-  one has a serial NVRAM, or for a system with a mixture of Symbios and
-  Tekram cards. Enables setting the boot order of host adaptors
-  to something other than the default order or "reverse probe" order. 
-  Also enables Symbios and Tekram cards to be distinguished so
-  CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT may be set in a system with a
-  mixture of Symbios and Tekram cards so the Symbios cards can make use of
-  the full range of Symbios features, differential, led pin, without
-  causing problems for the Tekram card(s).
-      (added by Richard Waltham: dormouse@farsrobt.demon.co.uk)
-  Also enables setting host and targets SCSI features as defined in the 
-  user setup for each host using a serial NVRAM (added by the maintainer).
-  The default answer is N, the normal answer should be Y.
-  Read drivers/scsi/README.ncr53c8xx for more information.
-
 assume boards are SYMBIOS compatible
 CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
   This option allows you to enable some features depending on GPIO
@@ -2000,28 +2083,13 @@
   (SDMS 4.0 + Promise SCSI ULTRA 875 rev 0x3 + ASUS SC200 810A rev
   0x12).  This option must be set to N if your system has at least one
   53C8XX based scsi board with a vendor-specific BIOS (example: Tekram
-  DC-390/U/W/F).  If unsure, say N.
-  However, if all your non Symbios compatible boards have NvRAM, setting 
-  option CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT allows the driver to 
-  distinguish Symbios compatible boards from other ones.
-  So, you can answer Y if all non Symbios compatible boards have NVRAM.
-
-assume boards are SYMBIOS compatible
-CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
-  This option allows you to enable some features depending on GPIO
-  wiring.  These General Purpose Input/Output pins can be used for
-  vendor specific features or implementation of the standard SYMBIOS
-  features.  Genuine SYMBIOS boards use GPIO0 in output for controller
-  LED and GPIO3 bit as a flag indicating singled-ended/differential
-  interface.
-  If all the boards of your system are genuine SYMBIOS boards or use
-  BIOS and drivers from SYMBIOS, you would want to enable this option,
-  obviously at your own risks.
-  The driver behaves correctly on my system with this option enabled.
-  (SDMS 4.0 + Promise SCSI ULTRA 875 rev 0x3 + ASUS SC200 810A rev
-  0x12).  This option must be set to N if your system has at least one
-  53C8XX based scsi board with a vendor-specific BIOS (example: Tekram
-  DC-390/U/W/F).  If unsure, say N.
+  DC-390/U/W/F). 
+  However, if all your non Symbios compatible boards have NvRAM,
+  setting option "detect and read serial NVRAMs"
+  (CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT) above allows the driver to
+  distinguish Symbios compatible boards from other ones.  So, you can
+  answer Y if all non Symbios compatible boards have NVRAM.
+  If unsure, say N.
 
 IBMMCA SCSI support
 CONFIG_SCSI_IBMMCA
@@ -2031,13 +2099,17 @@
   code which can be inserted in and removed from the running kernel
   whenever you want). The module will be called ibmmca.o. If you want
   to compile it as a module, say M here and read
-  Documentation/modules.txt.
-  Normally, all IBM MCA SCSI adapters are automatically detected. You
-  can completely override auto-detection by specifying
-  "ibmmcascsi=io1,io2,..." at the boot loader's command prompt or
-  "io_port=io1,io2,... scsi_id=id1,id2,..." as a parameter of insmod.
-  "io" and "id" are the I/O base address and the SCSI ID of each
-  adapter, respectively.
+  Documentation/modules.txt.  
+  Normally, all IBM MCA SCSI adapters are automatically detected. If
+  that doesn't work right however, you can completely override
+  auto-detection by specifying "ibmmcascsi=io1,io2,..." at the boot
+  loader's command prompt or "io_port=io1,io2,... scsi_id=id1,id2,..."
+  as a parameter of insmod.  "io" and "id" are the I/O base address
+  and the SCSI ID of each adapter, respectively.
+  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. The module will be
+  called ibmmca.o.
 
 Always IN2000 SCSI support
 CONFIG_SCSI_IN2000
@@ -2189,17 +2261,27 @@
 
 Tekram DC390W/U/F (T) SCSI support
 CONFIG_SCSI_DC390W
-  This driver supports the Tekram DC390W/U/F (T) PCI SCSI host adapters with
-  the NCR/Symbios 53c825/875 chips. If you have a DC390 (T) adaptor with the 
-  Am53C974A chip use the DC390(T) driver.
-
+  This driver supports the Tekram DC390W/U/F (T) PCI SCSI host
+  adapters with the NCR/Symbios 53c825/875 chips. Say Y here if you
+  have one of those. If however you have a DC390 (T) adaptor with the
+  Am53C974A chip, use the DC390(T) driver "Tekram DC390(T) (AMD
+  PCscsi) SCSI support", below.
+  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. The module will be
+  called ???.o.
+  
 Tekram DC390(T) (AMD PCscsi) SCSI support
 CONFIG_SCSI_DC390T
-  This driver supports the Tekram DC390(T) PCI SCSI Hostadapter with
+  This driver supports the Tekram DC390(T) PCI SCSI host adapter with
   the Am53C974A chip, and perhaps other cards using the same chip.
-  
   This driver does _not_ support the DC390W/U/F adaptor with the 
-  NCR/Symbios chips.
+  NCR/Symbios chips; use "Tekram DC390W/U/F (T) SCSI support" for that
+  one.
+  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. The module will be
+  called tmscsim.o.
 
 AM53/79C974 PCI SCSI support
 CONFIG_SCSI_AM53C974
@@ -2219,29 +2301,34 @@
   driver and how to use it you should read the file
   drivers/scsi/README.ppa.  You should also read the SCSI-HOWTO, which
   is available via anonymous ftp from sunsite.unc.edu in the directory
-  /pub/Linux/docs/HOWTO.  This driver is also available as a module
-  which can be inserted in and removed from the running kernel
-  whenever you want. If you want to use any two of a parallel port ZIP
-  drive, a parallel printer or PLIP on the same parallel port, you
-  should compile the drivers as modules and only insert them as
-  needed. To compile this driver as a module, say M here and read
-  Documentation/modules.txt. The module will be called ppa.o. Note
-  that you can say N here if you have the SCSI version of the ZIP
-  drive: it will be supported automatically if you said Y to the
-  generic "SCSI disk support", above.
+  /pub/Linux/docs/HOWTO. If you use this driver, you will still be
+  able to use the parallel port for other tasks, such as a printer; it
+  is safe to compile both drivers into the kernel. This driver is also
+  available as a module which can be inserted in and removed from the
+  running kernel whenever you want. To compile this driver as a
+  module, say M here and read Documentation/modules.txt. The module
+  will be called ppa.o. Note that you can say N here if you have the
+  SCSI version of the ZIP drive: it will be supported automatically if
+  you said Y to the generic "SCSI disk support", above.
 
 EPP FIFO Checking
 CONFIG_SCSI_PPA_HAVE_PEDANTIC
-  Some chipsets are slower then their motherboard. We have to control
-  the state of the FIFO now and then.  The values are 0 (don't check
-  FIFO), 1 (check FIFO every 4 bytes), 2 (check FIFO every other byte)
-  and 3 (check FIFO every time). If your EPP chipset is from the SMC
-  series, you are likely to have to set this value greater than 0.
+  EPP (Enhanced Parallel Port) is a standard for parallel ports which
+  allows them to act as expansion buses that can handle up to 64
+  peripheral devices. Some parallel port chipsets are slower than
+  their motherboard, and so we have to control the state of the FIFO
+  every now and then to avoid data loss.  The permitted values for
+  this option are 0 (don't check FIFO), 1 (check FIFO every 4 bytes),
+  2 (check FIFO every other byte) and 3 (check FIFO every time). If
+  your EPP chipset is from the SMC series, you are likely to have to
+  set this value greater than 0.
 
 EPP Timing
 CONFIG_SCSI_PPA_EPP_TIME
-  This is the "reset time period", a delay time.  Too low a value may
-  cause all sorts of mid-level SCSI problems.
+  This is the "reset time period", a delay time. The lower the value,
+  the faster the access to the ZIP drive; too low a value may
+  cause all sorts of mid-level SCSI problems however. If unsure, go
+  with the default.
 
 Network device support?
 CONFIG_NETDEVICES
@@ -2253,33 +2340,23 @@
   shell account or a BBS, even using term (term is a program which
   gives you almost full Internet connectivity if you have a regular
   dial up shell account on some Internet connected Unix computer. Read
-  the Term-HOWTO).  You'll have to say Y if your computer contains a
-  network card that you want to use under linux (make sure you know
-  its name because you will be asked for it and read the
-  Ethernet-HOWTO; also, if you plan to use more than one network card
-  under linux, read the Multiple-Ethernet-mini-HOWTO, available from
+  http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html).  You'll
+  have to say Y if your computer contains a network card that you want
+  to use under linux (make sure you know its name because you will be
+  asked for it and read the Ethernet-HOWTO; also, 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) or if you want to use
   SLIP (Serial Line Internet Protocol is the protocol used to send
   Internet traffic over telephone lines or nullmodem cables) or CSLIP
-  (compressed SLIP) or PPP (better and newer variant of SLIP) or PLIP
-  (Parallel Line Internet Protocol is mainly used to create a mini
-  network by connecting the parallel ports of two local machines) or
-  AX.25/KISS (protocol for sending internet traffic over radio links).
-  Make sure to read the NET-2-HOWTO.  Eventually, you will have to
-  read Olaf Kirch's excellent book "Network Administrator's Guide", to
-  be found in sunsite.unc.edu:/pub/Linux/docs/LDP.  If unsure, say Y.
-
-CONFIG_NET_ETHERNET
-  Ethernet is the most common protocol used on Local Area Networks
-  (LANs) in universities or companies. 10-base-2 and 10-base-T and
-  100-base-<whatever> are common types of ethernet. If your Linux
-  machine will be connected to an Ethernet and you have an ethernet
-  network card installed in your computer, say Y here and read the
-  Ethernet-HOWTO, available via ftp (user: anonymous) from
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  Note that the answer to this
-  question won't directly affect the kernel: saying N will just cause
-  this configure script to skip all the questions about Ethernet
-  network cards. If unsure, say N.
+  (compressed SLIP) or PPP (Point to Point Protocol, a better and
+  newer replacement for SLIP) or PLIP (Parallel Line Internet Protocol
+  is mainly used to create a mini network by connecting the parallel
+  ports of two local machines) or AX.25/KISS (protocol for sending
+  internet traffic over radio links).  Make sure to read the
+  NET-2-HOWTO.  Eventually, you will have to read Olaf Kirch's
+  excellent book "Network Administrator's Guide", to be found in
+  sunsite.unc.edu:/pub/Linux/docs/LDP.  If unsure, say Y.
 
 Dummy net driver support
 CONFIG_DUMMY
@@ -2296,8 +2373,8 @@
   running kernel whenever you want), say M here and read
   Documentation/modules.txt. The module will be called dummy.o. If you
   want to use more than one dummy device at a time, you need to
-  compile it as a module. Instead of 'dummy', it will they will then
-  be called 'dummy0', 'dummy1' etc.
+  compile this driver as a module. Instead of 'dummy', the devices
+  will then be called 'dummy0', 'dummy1' etc.
   
 SLIP (serial line) support
 CONFIG_SLIP
@@ -2318,11 +2395,12 @@
   SLIP. Note that you don't need this option if you just want to run
   term (term is a program which gives you almost full Internet
   connectivity if you have a regular dial up shell account on some
-  Internet connected Unix computer. Read the Term-HOWTO). SLIP support
-  will enlarge your kernel by about 4kB. If unsure, say N.  If you
-  want to compile this as a module ( = code which can be inserted in
-  and removed from the running kernel whenever you want), say M here
-  and read Documentation/modules.txt as well as
+  Internet connected Unix computer. Read
+  http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html). SLIP
+  support will enlarge your kernel by about 4kB. If unsure, say N.  If
+  you want to compile this as a module ( = code which can be inserted
+  in and removed from the running kernel whenever you want), say M
+  here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt. The module will be called
   slip.o.
   
@@ -2394,20 +2472,41 @@
   don't need "PPP support" if you just want to run term (term is a
   program which gives you almost full Internet connectivity if you
   have a regular dial up shell account on some Internet connected UNIX
-  computer. Read the Term-HOWTO). The PPP option enlarges your kernel
-  by about 16kB. 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 said Y to "Version information on all
-  symbols" above, then you cannot compile the PPP driver into the
-  kernel; you can then only compile it as a module. The module will be
-  called ppp.o. If you want to compile it as a module, say M here
-  and read Documentation/modules.txt as well as
-  Documentation/networking/net-modules.txt. Note that, no matter what
-  you do, the BSD compression code (used to compress the IP packets
-  sent over the serial line; has to be supported at the other end as
-  well) can only be compiled as a module; it is called bsd_comp.o and
-  will show up in the directory modules once you have said "make
-  modules". If unsure, say N.
+  computer. Read
+  http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html). The PPP
+  option enlarges your kernel by about 16kB. 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 said Y to
+  "Version information on all symbols" above, then you cannot compile
+  the PPP driver into the kernel; you can then only compile it as a
+  module. The module will be called ppp.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt as well
+  as Documentation/networking/net-modules.txt. Note that, no matter
+  what you do, the BSD compression code (used to compress the IP
+  packets sent over the serial line; has to be supported at the other
+  end as well) will always be compiled as a module; it is called
+  bsd_comp.o and will show up in the directory modules once you have
+  said "make modules". If unsure, say N.
+
+Shortwave radio modem driver
+CONFIG_HFMODEM
+  This experimental driver is used by a package (to be released)
+  that implements the shortwave radio protocols RTTY, Sitor (Amtor),
+  Pactor 1 and GTOR using a standard PC soundcard. If unsure,
+  say N.
+
+Shortwave radio modem driver support for SoundBlaster and compatible cards
+CONFIG_HFMODEM_SBC
+  This option enables the hfmodem driver to use SoundBlaster and
+  compatible cards. It requires a 16bit capable card, i.e.
+  SB16 or better, or ESS1688 or newer.
+
+Shortwave radio modem driver support for WSS and Crystal cards
+CONFIG_HFMODEM_WSS
+  This option enables the hfmodem driver to use WindowsSoundSystem
+  compatible cards. These cards feature a codec chip from either
+  Analog Devices (such as AD1848, AD1845) or Crystal
+  Semiconductors (such as CS4248, CS423x).
 
 STRIP (Metricom Starmode radio IP)
 CONFIG_STRIP
@@ -2428,9 +2527,9 @@
   the running kernel whenever you want), say M here and read
   Documentation/modules.txt. The module will be called strip.o.
 
-CONFIG_LAPBETHER
 LAPB over Ethernet driver
-  This is a driver for a pseudo device (usually called /dev/lapb0)
+CONFIG_LAPBETHER
+  This is a driver for a pseudo device (typically called /dev/lapb0)
   which allows you to open an LAPB point-to-point connection to some
   other computer on your ethernet network. In order to do this, you
   need to say Y or M to the driver for your ethernet card as well as
@@ -2440,6 +2539,18 @@
   Documentation/modules.txt. The module will be called lapbether.o.
   If unsure, say N.
 
+X.25 async driver
+CONFIG_X25_ASY
+  This is a driver for sending and receiving X.25 frames over regular
+  asynchronous serial lines such as telephone lines equipped with
+  ordinary modems. Experts should note that this driver doesn't
+  currently comply with the asynchronous HDLS framing protocols in
+  CCITT recommendation X.25. 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. The module will be called x25_asy.o.  If
+  unsure, say N.
+
 Z8530 SCC driver for AX.25
 CONFIG_SCC
   These cards are used to connect your Linux box to an amateur radio
@@ -2459,11 +2570,11 @@
   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 driver as a module ( = code which can be inserted in
-  and removed from the running kernel whenever you want), say M here
-  and read Documentation/modules.txt. This is recommended. The module
-  will be called baycom.o.
+  http://www.baycom.de and Documentation/networking/baycom.txt. If you
+  want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. This is
+  recommended. The module will be called baycom.o.
 
 Soundcard modem driver for AX.25
 CONFIG_SOUNDMODEM
@@ -2474,9 +2585,9 @@
   the standard ax25 utilities package. For information 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 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/networking/soundmodem.txt. If you want to compile this
+  driver as a module ( = code which can be inserted in and removed
+  from the running kernel whenever you want), say M here and read
   Documentation/modules.txt. This is recommended. The module will be
   called soundmodem.o.
 
@@ -2508,24 +2619,24 @@
 Soundcard modem support for 2400 baud AFSK modulation (7.3728MHz crystal)
 CONFIG_SOUNDMODEM_AFSK2400_7
   This option enables the soundmodem driver 2400 baud AFSK modem,
-  compatible to TCM3105 modems (over-)clocked with a 7.3728MHz crystal.
-  Note that the availability of this driver does _not_ imply that I
-  recommend building such links. It is only here since users especially
-  in eastern europe have asked me to do so. In fact this modulation scheme
-  has many disadvantages, mainly its incompatibility with many transceiver
-  designs and the fact that the TCM3105 (if used) is operated widely outside
-  its specifications.
+  compatible to TCM3105 modems (over-)clocked with a 7.3728MHz
+  crystal.  Note that the availability of this driver does _not_ imply
+  that I recommend building such links. It is only here since users
+  especially in eastern Europe have asked me to do so. In fact this
+  modulation scheme has many disadvantages, mainly its incompatibility
+  with many transceiver designs and the fact that the TCM3105 (if
+  used) is operated widely outside its specifications.
 
 Soundcard modem support for 2400 baud AFSK modulation (8MHz crystal)
 CONFIG_SOUNDMODEM_AFSK2400_8
   This option enables the soundmodem driver 2400 baud AFSK modem,
   compatible to TCM3105 modems (over-)clocked with an 8MHz crystal.
   Note that the availability of this driver does _not_ imply that I
-  recommend building such links. It is only here since users especially
-  in eastern europe have asked me to do so. In fact this modulation scheme
-  has many disadvantages, mainly its incompatibility with many transceiver
-  designs and the fact that the TCM3105 (if used) is operated widely outside
-  its specifications.
+  recommend building such links. It is only here since users
+  especially in eastern Europe have asked me to do so. In fact this
+  modulation scheme has many disadvantages, mainly its incompatibility
+  with many transceiver designs and the fact that the TCM3105 (if
+  used) is operated widely outside its specifications.
 
 Soundcard modem support for 4800 baud HAPN-1 modulation
 CONFIG_SOUNDMODEM_HAPN4800
@@ -2543,26 +2654,6 @@
   can only use one protocol at a time, depending on what the other end
   can understand).
 
-Shortwave radio modem driver
-CONFIG_HFMODEM
-  This experimental driver is used by a package (to be released)
-  that implements the shortwave radio protocols RTTY, Sitor (Amtor),
-  Pactor 1 and GTOR using a standard PC soundcard. If unsure,
-  say N.
-
-Shortwave radio modem driver support for SoundBlaster and compatible cards
-CONFIG_HFMODEM_SBC
-  This option enables the hfmodem driver to use SoundBlaster and
-  compatible cards. It requires a 16bit capable card, i.e.
-  SB16 or better, or ESS1688 or newer.
-
-Shortwave radio modem driver support for WSS and Crystal cards
-CONFIG_HFMODEM_WSS
-  This option enables the hfmodem driver to use WindowsSoundSystem
-  compatible cards. These cards feature a codec chip from either
-  Analog Devices (such as AD1848, AD1845) or Crystal
-  Semiconductors (such as CS4248, CS423x).
-
 Serial port KISS driver for AX.25
 CONFIG_MKISS
   KISS is the protocol used to send IP traffic over AX.25 radio
@@ -2598,24 +2689,7 @@
   = code which can be inserted in and removed from the running kernel
   whenever you want), say M here and read Documentation/modules.txt as
   well as Documentation/networking/net-modules.txt. The module will be
-  called plip.o. If you want to use both a parallel printer and PLIP,
-  there are two cases: 1) If the printer and the PLIP cable are to use
-  the same parallel port (presumably because you have just one), it is
-  best to compile both drivers as modules and load and unload them as
-  needed. 2) In order to use different parallel ports for the printer
-  and the PLIP cable, you can say Y to the printer driver and specify
-  the base address of the parallel port(s) to use for the printer(s)
-  with the "lp" kernel command line option. (Try "man bootparam" or
-  see the documentation of your boot loader (lilo or loadlin) about
-  how to pass options to the kernel at boot time. The lilo procedure
-  is also explained in the SCSI-HOWTO, available via ftp (user:
-  anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO.) The standard
-  base addresses as well as the syntax of the "lp" command line option
-  can be found in drivers/char/lp.c. You can then say Y to this PLIP
-  driver or, preferably, M in which case
-  Documentation/networking/net-modules.txt tells you how to specify
-  the port and IRQ to be used by PLIP at module load time.  It's safe
-  to say N here.
+  called plip.o.
 
 EQL (serial line load balancing) support
 CONFIG_EQUALIZER
@@ -2643,9 +2717,9 @@
   relay network. For a general explanation of the protocol, check out
   http://frame-relay.indiana.edu/4000/4000index.html on the WWW. (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.) To use frame
-  relay, you need supporting hardware (FRAD) and certain programs from
-  the net-tools package as explained in
+  that has a program like lynx or netscape.) To use frame relay, you
+  need supporting hardware (FRAD) and certain programs from the
+  net-tools package as explained in
   Documentation/networking/framerelay.txt. This driver is also
   available as a module ( = code which can be inserted in and removed
   from the running kernel whenever you want). The module will be
@@ -2653,7 +2727,7 @@
   and read Documentation/modules.txt.
 
 Max open DLCI
-CONFIG_DLCI_COUNT 
+CONFIG_DLCI_COUNT
   This is the maximal number of logical point-to-point frame relay
   connections (the identifiers of which are called DCLIs) that
   the driver can handle. The default is probably fine.
@@ -2695,8 +2769,8 @@
   more information.
       WAN routing is always built as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
-  The module will be called wanrouter.o.  For general information
-  about modules read Documentation/modules.txt.
+  The module is called wanrouter.o.  For general information about 
+  modules read Documentation/modules.txt.
 
 WAN Drivers
 CONFIG_WAN_DRIVERS
@@ -2767,11 +2841,19 @@
 
 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.
+  Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
+  type of Local Area Networks (LANs) in universities or
+  companies. 10-base-2 or Thinnet (10 Mbps over coaxial cable, linking
+  computers in a chain), 10-base-T (10 Mbps over twisted pair
+  telephone cable, linking computers to a central hub) and
+  100-base-<whatever> (100 Mbps) are common types of ethernet. If your
+  Linux machine will be connected to an Ethernet and you have an
+  ethernet network card installed in your computer, say Y here and
+  read the Ethernet-HOWTO, available via ftp (user: anonymous) from
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  Note that the answer to this
+  question won't directly affect the kernel: saying N will just cause
+  this configure script to skip all the questions about Ethernet
+  network cards. If unsure, say N.
 
 Western Digital/SMC cards
 CONFIG_NET_VENDOR_SMC
@@ -3112,13 +3194,14 @@
 
 EtherExpressPro support
 CONFIG_EEXPRESS_PRO
-  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). The module will be called
-  eepro.o. If you want to compile it as a module, say M here and read
-  Documentation/modules.txt as well as
+  If you have a network (ethernet) card of this type, say Y. Note
+  however that the EtherExpressPro 100 ethernet card has its own
+  separate driver. Please 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). The
+  module will be called eepro.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt. If you plan to use more
   than one network card under linux, read the
   Multiple-Ethernet-mini-HOWTO, available from
@@ -3170,13 +3253,13 @@
   which are commonly used to send internet traffic over amateur radio.
   More information about these cards is on the WWW at
   http://hydra.carleton.ca/info/pi2.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 have one of these cards,
-  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. If you want
-  to compile this as a module ( = code which can be inserted in and
+  to have access to a machine on the Internet that has a program like
+  lynx or netscape). If you have one of these cards, 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. 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. The module will be called pi2.o.
 
@@ -3196,18 +3279,26 @@
 
 AT&T WaveLAN & DEC RoamAbout DS support
 CONFIG_WAVELAN
-    The Lucent Wavelan (formerly NCR and AT&T ; or DEC RoamAbout DS)
-  is a Radio LAN (wireless ethernet-like) at 900 MHz and 2.4 GHz.
-    This driver support the ISA version of the Wavelan. A driver for
-  the pcmcia hardware is available in David Hinds's pcmcia package.
-    This driver is fairly stable and may be compiled as a module
-  (wavelan.o). It implements many nice feature and the Wireless
-  Extensions (you must get the Wireless tools from the net).
-    For documentation, refer to :
-      o the wavelan man page, wireless tools man pages
-      o wavelan.p.h and the source code
-      o Ethernet-HOWTO, Multiple-Ethernet-mini-HOWTO, Module-HOWTO
-      o More documentation to come when I will have the time :-)
+  The Lucent Wavelan (formerly NCR and AT&T ; or DEC RoamAbout DS) is
+  a Radio LAN (wireless ethernet-like Local Area Network) using the
+  radio frequencies 900 MHz and 2.4 GHz.
+  This driver support the ISA version of the Wavelan card. A driver
+  for the pcmcia hardware is available in David Hinds's pcmcia
+  package.
+  If you want to use a card of this type under Linux, say Y and read
+  the Ethernet-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. Some more specific
+  information is contained in drivers/net/README.wavelan. You will
+  also need the wireless tools package available from
+  ftp://ftp.inka.de/pub/comp/Linux/networking/NetTools/contrib/.
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you
+  want). The module will be called wavelan.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt as
+  well as Documentation/networking/net-modules.txt. 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.
 
 HP PCLAN+ (27247B and 27252A) support
 CONFIG_HPLAN_PLUS
@@ -3287,6 +3378,15 @@
   Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
+AMD PCnet32 (VLB and PCI) support
+CONFIG_PCNET32
+  if you have a PCnet32 or PCnetPCI based network (ethernet) card, say
+  Y here 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.
+
 Ansel Communications EISA 3200 support
 CONFIG_AC3200
   If you have a network (ethernet) card of this type, say Y and read
@@ -3380,6 +3480,20 @@
   Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
+EtherExpressPro/100 support
+CONFIG_EEXPRESS_PRO100
+  If you have an Intel EtherExpressPro 100 PCI network (ethernet)
+  card, 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). The module will
+  be called eepro100.o. If you want to compile it as a module, say M
+  here and read Documentation/modules.txt as well as
+  Documentation/networking/net-modules.txt. 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.
+
 ICL EtherTeam 16i/32 support
 CONFIG_ETH16I
   If you have a network (ethernet) card of this type, say Y and read
@@ -3397,10 +3511,11 @@
 TI ThunderLAN support (EXPERIMENTAL)
 CONFIG_TLAN
   If you have a TLAN based network card which is supported by this
-  driver, say Y and read the Ethernet-HOWTO.  Devices currently supported
-  are the Compaq Netelligent 10, Netelligent 10/100, and Internal
-  NetFlex 3.  This driver is also available as a module.  Please email
-  feedback to james.banks@caldera.com.
+  driver, say Y and read the Ethernet-HOWTO.  Devices currently
+  supported are the Compaq Netelligent 10, Netelligent 10/100, and
+  Internal NetFlex 3.  This driver is also available as a module.  The
+  module will be called tlan.o. Please email feedback to
+  james.banks@caldera.com.
 
 Zenith Z-Note support
 CONFIG_ZNET
@@ -3426,9 +3541,7 @@
   asked for your specific device in the following questions.  If you
   plan to use more than one network device under linux, read the
   Multiple-Ethernet-mini-HOWTO, available from
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If you intend to use an
-  adapter attaching to the parallel port as well as a parallel
-  printer, you should compile both drivers as modules (if possible).
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
 AT-LAN-TEC/RealTek pocket adapter support
 CONFIG_ATP
@@ -3447,30 +3560,30 @@
   This is a network (ethernet) device which attaches to your parallel
   port. Read drivers/net/README.DLINK as well as the Ethernet-HOWTO,
   available via ftp (user: anonymous) from
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO if you want to use this.  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. The module will be called
-  de600.o. If you intend to use this pocket adapter as well as a
-  parallel printer, you should compile both drivers as modules. 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 use this. It is
+  possible to have several devices share a single parallel port and it
+  is safe to compile the corresponding drivers into the kernel. If you
+  want to compile this driver as a module however ( = code which can
+  be inserted in and removed from the running kernel whenever you
+  want), say M here and read Documentation/modules.txt. The module
+  will be called de600.o. 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.
 
 D-Link DE620 pocket adapter support
 CONFIG_DE620
   This is a network (ethernet) device which attaches to your parallel
   port. Read drivers/net/README.DLINK as well as the Ethernet-HOWTO,
   available via ftp (user: anonymous) from
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO if you want to use this.  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. The module will be called
-  de620.o. If you intend to use this pocket adapter as well as a
-  parallel printer, you should compile both drivers as modules. 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 use this. It is
+  possible to have several devices share a single parallel port and it
+  is safe to compile the corresponding drivers into the kernel. If you
+  want to compile this driver as a module however ( = code which can
+  be inserted in and removed from the running kernel whenever you
+  want), say M here and read Documentation/modules.txt. The module
+  will be called de620.o. 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.
  
 Token Ring driver support
 CONFIG_TR
@@ -3680,9 +3793,13 @@
   other models).  Say Y if you have one of these, and read the file
   Documentation/cdrom/bpcd. If you say Y here, you should also say Y
   to "ISO9660 cdrom filesystem support" below, because that's the
-  filesystem used on CDROMs. If you have several different devices
-  that will share a common parallel port, say M and build them as
-  modules. This module will be called bpcd.o.
+  filesystem used on CDROMs. It is possible for several devices to
+  share a parallel port and it is safe to compile the corresponding
+  drivers all into the kernel. This driver is also available as a
+  module ( = code which can be inserted in and removed from the
+  running kernel whenever you want). The module will be called
+  bpcd.o. If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.
 
 Philips/LMS CM206 CDROM support
 CONFIG_CM206
@@ -3744,10 +3861,12 @@
 Preload dcache
 CONFIG_DCACHE_PRELOAD
   Preloading will create dcache entries when a directory is scanned
-  (e.g. with ls) the *first* time. This should speed up successive
-  inode lookups, but also can consume large amounts of memory.
+  (e.g. with ls) for the *first* time. This should speed up successive
+  lookups of information about files in that directory, but can also
+  consume large amounts of memory.  
   Please report speedups (or slowdowns due to the memory usage if they
   occur) to schoebel@informatik.uni-stuttgart.de .
+  If unsure, say N.
 
 Quota support
 CONFIG_QUOTA
@@ -3777,118 +3896,136 @@
 
 Filename translation support
 CONFIG_TRANS_NAMES
-  Normally used only when you want diskless clients to mount the root
-  filesystem of the server. If unsure, or if you don't have clients, select N.
-  When selected, filenames, directory names etc become context-sensitive.
-  If you have a file named "/etc/config#host=banana#", it will appear
-  (by default) as hardlinked to "/etc/config" on host "banana", while on host
-  "mango" another file "/etc/config#host=mango#" will appear as been
-  hardlinked to "/etc/config". The default behaviour can be changed
-  by setting the _first_ environment variable NAMETRANS to a colon-separated
-  list of suffixes which are tried in the specified order. For example,
-  in 'env - NAMETRANS=#host=mango#:#ktype=diskless# "`env`" command ...' the
-  command will see the same files as if it had been executed on host "mango"
-  with a diskless kernel. Using NAMETRANS supersedes _all_ default
-  translations. Thus translations can be generally switched off by an
-  empty list, e.g. 'env - NAMETRANS= "`env`" command ...'.
-  Note that some system utililies like tar, dump, restore should
-  be used with translation switched off, in order to avoid doubled
-  space in archive files and when extracting from them. Also, make sure
-  that nfsd, mountd (and similar ones like samba daemons) run without
-  translation, in order to avoid doubled (or even wrong) translation
-  at the server and at the client. You can automatically force the creation
-  of context-dependent filenames if there exists a template filename like
-  "/etc/mtab#host=CREATE#". As soon as a process running on "mango" tries
-  to create a file "/etc/mtab", the version "/etc/mtab#host=mango#" is
-  created instead (which appears in turn as hardlinked to "/etc/mtab").
-  Note that if you want to make "/etc/fstab" context-dependend, you should
-  execute "touch /etc/mtab#host=CREATE#" and
-  "touch /etc/mtab.tmp#host=CREATE#", because mount, umount and others
-  running on different hosts would otherwise try to create one shared
-  /etc/mtab which would result in a clash. Also one should execute
-  "touch /etc/nologin#host=CREATE#" to prevent global side effects from
-  shutdown resp. runlevel.
+  This is a useful feature if you have a pool of diskless Linux
+  clients which mount their root filesystems from a central
+  server. Depending on their hostnames, the clients can then see
+  different versions of certain files, which keeps maintenance at a
+  minimum when used for configuration files. The kernel running on the
+  clients should have this option enabled. If you don't administer a
+  pool of Linux clients, say N here, otherwise read on:
+  When you say Y here, filenames, directory names etc become
+  context-sensitive.  If you have a file named
+  "/etc/config#host=banana#", it will appear (by default) as
+  hardlinked to "/etc/config" on host "banana", while on host "mango"
+  another file "/etc/config#host=mango#" will appear as having been
+  hardlinked to "/etc/config".
+  This default behaviour can be changed by setting the _first_
+  environment variable NAMETRANS to a colon-separated list of suffixes
+  which are tried in the specified order. For example, in 'env -
+  NAMETRANS=#host=mango#:#ktype=diskless# "`env`" command ...' the
+  command will see the same files as if it had been executed on host
+  "mango" with a diskless kernel.
+  Using NAMETRANS supersedes _all_ default translations. Thus
+  translations can be completely switched off with an empty list,
+  e.g. 'env - NAMETRANS= "`env`" command ...'.  Note that some system
+  utilities like tar, dump, restore should be used with translation
+  switched off, in order to avoid doubled space in archive files and
+  when extracting from them. Also, make sure that nfsd, mountd (and
+  similar ones like samba daemons) run without translation, in order
+  to avoid doubled (or even wrong) translation at the server and at
+  the client.
+  You can automatically force the creation of context-dependent
+  filenames if there exists a template filename like
+  "/etc/mtab#host=CREATE#". As soon as a process running on "mango"
+  tries to create a file "/etc/mtab", the version
+  "/etc/mtab#host=mango#" is created instead (which appears in turn as
+  hardlinked to "/etc/mtab").  Note that if you want to make
+  "/etc/fstab" context-dependent, you should execute "touch
+  /etc/mtab#host=CREATE#" and "touch /etc/mtab.tmp#host=CREATE#",
+  because mount, umount and others running on different hosts would
+  otherwise try to create one shared /etc/mtab which would result in a
+  clash. Also one should execute "touch /etc/nologin#host=CREATE#" to
+  prevent global side effects from shutdown resp. runlevel.
+  Please read Documentation/transname.txt if you intend to say Y here.
 
 Restrict translation to gid
 CONFIG_TRANS_RESTRICT
-  When selected, default translations are carried out only if the parent
-  directory of the context-sensitive file belongs to a specific group id
-  (gid). Trying to translate names everywhere will decrease performance of
-  file openings. Normally translations are used only in system configuration
-  files but not in ordinary user filespace. So you should change the gid of
-  directories containing context-dependent files to some special group like
-  "adm" (group id 4) and enable this option. As a result, users will not
-  notice any performance degradation resulting from filename translation.
+  If you say Y here, default filename translations are carried out
+  only if the parent directory of the context-sensitive file belongs
+  to a specific group id (gid). Trying to translate names everywhere
+  will decrease performance of file openings. Normally translations
+  are used only in system configuration files but not in ordinary user
+  filespace. So you should change the gid of directories containing
+  context-dependent files to some special group like "adm" (group id
+  4) and enable this option. As a result, users will not notice any
+  performance degradation resulting from filename translation.
   Note that translations resulting from the first environment variable
-  "NAMETRANS=..." are always carried out regardless of the gid of directories.
-  Beware, before turning on this option make sure all directories containing
-  context-dependent files belong to the special group, or system
-  initialization may fail. In unsure, select N.
+  "NAMETRANS=..." are always carried out regardless of the gid of
+  directories.
+  Beware: before turning on this option make sure that all directories
+  containing context-dependent files belong to the special group, or
+  system initialization may fail. If unsure, select N.
 
 Group id (gid) for translation restriction
 CONFIG_TRANS_GID
   Default name translations will be carried out only inside directories
-  belonging to the group id (gid) you can specify here.
+  belonging to the group id (gid) that you specify here.
   Default is 4 (group "adm").
 
 Nodename (hostname) translation
 CONFIG_TR_NODENAME
-  Enables translation of name suffixes like in "/etc/config#host=banana#".
-  The syntax is <filename>#host=<hostname>#. The hostname can be queried
-  with the command "uname -n". Normally this option is used heavily when
+  Enables translation of name suffixes like in
+  "/etc/config#host=banana#".  The syntax is
+  <filename>#host=<hostname>#. The hostname can be queried with the
+  command "uname -n". Normally this option is used heavily when
   translation is enabled. If unsure, say Y.
 
 Kernelname translation
 CONFIG_TR_KERNNAME
-  Enables translation of name suffixes like in "/etc/config#kname=default#".
-  The string is hard compiled into the kernel by the following option.
-  Useful if your kernel does not know the hostname at boot time, and there
-  is no way to tell the hostname by lilo or bootp. Please avoid using this
-  option and prefer CONFIG_TR_NODENAME wherever possible. When mounting
-  the root over nfs, the own hostname must be known at boot time anyway;
-  this option is just for special use.
-  Note that the default translations are tried in the order as occuring
-  in the configuration, that is 1) host 2) kname 3) ktype 4) machine
-  5) system. If unsure, say Y.
+  Enables translation of name suffixes like in
+  "/etc/config#kname=default#".  The string is hard compiled into the
+  kernel by the following option.  Useful if your kernel does not know
+  the hostname at boot time, and there is no way to tell the hostname
+  by lilo or bootp. Please avoid using this option and prefer
+  "Nodename (hostname) translation" (CONFIG_TR_NODENAME) wherever
+  possible. When mounting the root over nfs, the own hostname must be
+  known at boot time anyway; this option is just for special use.
+  Note that the default translations are tried in the order as
+  occurring in the configuration, that is 1) host 2) kname 3) ktype 4)
+  machine 5) system. If unsure, say Y.
 
 String for kernelname translation
 CONFIG_KERNNAME
   Enter the string you want to compile into the kernel. The string
-  will be used as context in context-depenant file like
-  "/etc/config#kname=<hostname>#".
+  will be used as context in context-dependent files like
+  "/etc/config#kname=<string>#".
 
 Kerneltype translation
 CONFIG_TR_KERNTYPE
-  Enables translation of name suffixes like in "/etc/config#ktype=default#".
-  The syntax is <filename>#ktype=<string>#. The string is hard compiled
-  in the kernel by the following option. Use if you want to create
-  different kernels with different behaviour. For example, use the string
-  "default" on your server, and use "diskless" on all your diskless clients
-  (and perhaps "dataless" on dataless clients). This way you can avoid
-  dozens of "config#host=<something># with same contents and you have no
-  effort when new machines are added. If unsure, say Y.
+  Enables translation of name suffixes like in
+  "/etc/config#ktype=default#".  The syntax is
+  <filename>#ktype=<string>#. The string is hard compiled in the
+  kernel by the following option. Use if you want to create different
+  kernels with different behaviour. For example, use the string
+  "default" on your server, and use "diskless" on all your diskless
+  clients (and perhaps "dataless" on dataless clients). This way you
+  can avoid dozens of "config#host=<something># with same contents and
+  you have no effort when new machines are added. If unsure, say Y.
 
 String for kerneltype translation
 CONFIG_KERNTYPE
   Enter the string you want to compile into the kernel. The string
-  will be used as context in context-depenant file like
-  "/etc/config#ktype=default#". If your kernel is to be used on a server,
-  you probably can use "default" here. If your kernel is intended for
-  a diskless client, you probably should enter "diskless" here.
+  will be used as context in context-dependent files like
+  "/etc/config#ktype=default#". If your kernel is to be used on a
+  server, you probably can use "default" here. If your kernel is
+  intended for a diskless client, you probably should enter "diskless"
+  here.
 
 Machine type translation
 CONFIG_TR_MACHINE
-  Enables translation of name suffixes like in "/etc/config#machine=i486#".
-  The syntax is <filename>#machine=<id>#. The machine types can be queried
-  with the command "uname -m". Normally used only on multi-architecture
+  Enables translation of name suffixes like in
+  "/etc/config#machine=i486#".  The syntax is
+  <filename>#machine=<id>#. The machine types can be queried with the
+  command "uname -m". Normally used only on multi-architecture
   installations. If unsure, say Y.
 
 System name translation
 CONFIG_TR_SYSNAME
-  Enables translation of name suffixes like in "/etc/config#system=Linux#".
-  The syntax is <filename>#system=<id>#. The system name can be queried
-  with the command "uname -s". Currently only supportet by Linux, but
-  hopefully other operating systems will pick up the idea of context-dependent
+  Enables translation of name suffixes like in
+  "/etc/config#system=Linux#".  The syntax is
+  <filename>#system=<id>#. The system name can be queried with the
+  command "uname -s". Currently only supported by Linux, but hopefully
+  other operating systems will pick up the idea of context-dependent
   translations. If unsure, say Y.
 
 Minix fs support
@@ -4065,7 +4202,24 @@
   If you want your Linux box to mount its whole root filesystem from
   some other computer over the net via NFS (presumably because your
   box doesn't have a harddisk), say Y. Read Documentation/nfsroot.txt
-  for details. Most people say N here.
+  for details. Most people say N here. 
+
+NFS server support
+CONFIG_NFSD
+  If you want your Linux box to act as a NFS *server*, so that other
+  computers on your local network which support NFS can access files
+  on your box transparently, you have two options: you can use the
+  self-contained user space program nfsd, in which case you should say
+  N here, or you can say Y and use this new experimental kernel based
+  NFS server. The advantage of the kernel based solution is that it is
+  faster; it might not be completely stable yet, though. You will need
+  the support software from the linux-nfs package available at
+  ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/.  
+  The nfs server is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you
+  want). The module is called nfsd.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt. If unsure,
+  say N.
 
 BOOTP support
 CONFIG_RNFS_BOOTP
@@ -4086,8 +4240,8 @@
   some other computer over the net via NFS and you want the IP address
   of your computer to be discovered automatically at boot time using
   the RARP protocol (an older protocol which is being obsoleted by
-  BOOTP), say Y here. Note that in case you want to use RARP, a RARP
-  server must be operating on your network. Read
+  BOOTP and DHCP), say Y here. Note that in case you want to use RARP,
+  a RARP server must be operating on your network. Read
   Documentation/nfsroot.txt for details.
 
 ISO9660 cdrom filesystem support
@@ -4152,10 +4306,14 @@
   on demand.  This implementation is partially kernel-based to reduce
   overhead in the already-mounted case; this is unlike the BSD
   automounter (amd), which is only in user space.  To use the
-  automounter you also need the user-space tools from
-  ftp.kernel.org:/pub/linux/daemons/autofs.  If you are not a part of
-  a fairly large, distributed network, you probably do not need an
-  automounter, and can say N here.
+  automounter you need the user-space tools from
+  ftp.kernel.org:/pub/linux/daemons/autofs; you also want to say Y to
+  "NFS filesystem support", above.  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. The module will be called autofs.o.
+  If you are not a part of a fairly large, distributed network, you
+  probably do not need an automounter, and can say N here.
 
 BSD UFS filesystem support (read only)
 CONFIG_UFS_FS
@@ -4204,7 +4362,9 @@
   (WfW), Windows 95, Windows NT and Lan Manager use to share files and
   printers over local networks. Saying Y here allows you to mount
   their filesystems (often called "shares" in this context) and access
-  them just like any other unix directory. For details, read
+  them just like any other unix directory. Currently, this works only
+  if the Windows machines use TCP/IP as the underlying transport
+  protocol, and not Netbeui.  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),
@@ -4213,12 +4373,12 @@
   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. The module will be called
-  smbfs.o. Most people say N, however.
+  you need to have access to a machine on the Internet that has a
+  program like lynx or netscape).  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. The module will be called smbfs.o. Most
+  people say N, however.
 
 SMB Win95 bug work-around
 CONFIG_SMB_WIN95
@@ -4276,14 +4436,15 @@
 CONFIG_VT
   This includes support for a terminal device using display and
   keyboard devices. Only people using embedded systems want to say N
-  here. Most say Y here.
+  here; most everybody says Y.
 
 Console on virtual terminal
 CONFIG_VT_CONSOLE
   If you enable this option, all kernel messages will be sent to the
   device /dev/tty which corresponds to the virtual terminal you have
-  visible on your display. You should say Y here if you have no other
-  console device.
+  visible on your display. You should say N here only if you have some
+  other console device, in which case you probably want to say Y to
+  "Console on serial port", below. If unsure, say N.
 
 Standard/generic serial support
 CONFIG_SERIAL
@@ -4307,22 +4468,37 @@
 Console on serial port
 CONFIG_SERIAL_CONSOLE
   If you enable this option, all kernel messages will be sent to the
-  device /dev/ttyS1 which corresponds to a serial port; this could be
-  useful if you attached a terminal or printer to that port. You can
-  use this in combination with console on virtual terminal, in which
-  case you get the output on both serial and display. Most people say
-  N here so that they can use the serial port for modem, mouse or some
-  other device.
+  device /dev/ttyS0 which corresponds to a serial port; this could be
+  useful if you attached a terminal or printer to that port. (You can
+  change the number of the serial port used from 0 to something else
+  by setting the variable CONFIG_SERIAL_CONSOLE_PORT.) You can use
+  this option in combination with the option "Console on virtual
+  terminal" above, in which case you get the output on both the serial
+  port and on your display. Most people say N here so that they can
+  use the serial port for modem, mouse or some other device.
+
+Comtrol Rocketport support
+CONFIG_ROCKETPORT
+  This is a driver for the Comtrol Rocketport cards which provide
+  multiple serial ports.  You would need something like this to
+  connect more than two modems to your linux box, for instance in
+  order to become a BBS.If you want to compile this driver as a
+  module, say M here and read Documentation/modules.txt. The module
+  will be called rocket.o.
 
-Digi Intl. epca support
+Digiboard Intelligent async support
 CONFIG_DIGIEPCA
-  This is a driver for Digi Internationals Xx, Xeve, and Xem 
-  series of cards.  This driver supports the original PC (ISA) boards as
-  well as PCI, and EISA.  If you have a card like this, say Y here and read
-  the file Documentation/digiepca.txt.  NOTE: This driver is seperate from
-  the driver written and copyrighted by Troy De Jongh.  Because they both
-  attempt (In some cases) to access the same hardware only one of these
-  drivers (CONFIG_DIGIEPCA or CONFIG_DIGI) should be selected.
+  This is a driver for Digi International's Xx, Xeve, and Xem series
+  of cards which provide multiple serial ports.  You would need
+  something like this to connect more than two modems to your linux
+  box, for instance in order to become a BBS. This driver supports the
+  original PC (ISA) boards as well as PCI, and EISA.  If you have a
+  card like this, say Y here and read the file
+  Documentation/digiepca.txt.  NOTE: There is another, separate driver
+  for the Digiboard PC boards: "Digiboard PC/Xx Support" below. You
+  should (and can) only select one of the two drivers. If you want to
+  compile this driver as a module, say M here and read
+  Documentation/modules.txt. The module will be called epca.o.
 
 Digiboard PC/Xx Support
 CONFIG_DIGI
@@ -4387,7 +4563,7 @@
 CONFIG_ESPSERIAL
   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
+  Documentation/hayes-esp.txt. 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. The module will be called esp.o.
@@ -4401,35 +4577,38 @@
 
 Hayes ESP serial port receive trigger level
 CONFIG_ESPSERIAL_RX_TRIGGER
-  This is the trigger level (in bytes) of the receive FIFO.  Larger values
-  may result in fewer interrupts; however, a value too high could result in
-  data loss.  Valid values are 1 through 1023.
+  This is the trigger level (in bytes) of the receive FIFO.  Larger
+  values may result in fewer interrupts; however, a value too high
+  could result in data loss.  Valid values are 1 through 1023.
 
 Hayes ESP serial port transmit trigger level
 CONFIG_ESPSERIAL_TX_TRIGGER
-  This is the trigger level (in bytes) of the transmit FIFO.  Larger values
-  may result in fewer interrupts; however, a value too high could result in
-  degraded trasmit performance.  Valid values are 1 through 1023.
+  This is the trigger level (in bytes) of the transmit FIFO.  Larger
+  values may result in fewer interrupts; however, a value too high
+  could result in degraded transmit performance.  Valid values are 1
+  through 1023.
 
 Hayes ESP serial port flow off level
 CONFIG_ESPSERIAL_FLOW_OFF
-  This is the level (in bytes) at which the ESP port will flow off the remote
-  transmitter.  Valid values are 1 through 1023.  This value should be greater
-  than the receive trigger level and the flow on level.
+  This is the level (in bytes) at which the ESP port will "flow off"
+  the remote transmitter (i.e. tell him to stop stop sending more
+  bytes).  Valid values are 1 through 1023.  This value should be
+  greater than the receive trigger level and the flow on level.
 
 Hayes ESP serial port flow on level
 CONFIG_ESPSERIAL_FLOW_ON
-  This is the level (in bytes) at which the ESP port will flow on the remote
-  transmitter after having flowed it off.  Valid values are 1 through 1023.
-  This value should be less than the flow off level, but greater than the
-  receive trigger level.
+  This is the level (in bytes) at which the ESP port will "flow on"
+  the remote transmitter (i.e. tell him to resume sending bytes) after
+  having flowed it off.  Valid values are 1 through 1023.  This value
+  should be less than the flow off level, but greater than the receive
+  trigger level.
 
 Hayes ESP serial port receiver timeout
 CONFIG_ESPSERIAL_RX_TMOUT
-  This is the amount of time that the ESP port will wait after receiving the
-  final character before signalling an interrupt.  Valid values are 0 through
-  255.  A value too high will increase latency, and a value too low will cause
-  unnecessary interrupts.
+  This is the amount of time that the ESP port will wait after
+  receiving the final character before signaling an interrupt.  Valid
+  values are 0 through 255.  A value too high will increase latency,
+  and a value too low will cause unnecessary interrupts.
 
 Parallel printer support
 CONFIG_PRINTER
@@ -4437,15 +4616,27 @@
   box (as opposed to using a serial printer; if the connector at the
   printer has 9 or 25 holes ["female"], then it's serial), say Y. Also
   read the Printing-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.
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  It is possible to share one
+  parallel port among several devices (e.g. printer and ZIP drive) and
+  it is safe to compile the corresponding drivers into the kernel. If
+  you want to compile this driver as a module however ( = code which
+  can be inserted in and removed from the running kernel whenever you
+  want), say M here and read Documentation/modules.txt. The module
+  will be called lp.o.  If you have several parallel ports, you
+  should specify the base address for the port to use by the printer
+  with the "lp" kernel command line option. (Try "man bootparam" or
+  see the documentation of your boot loader (lilo or loadlin) about
+  how to pass options to the kernel at boot time. The lilo procedure
+  is also explained in the SCSI-HOWTO, available via ftp (user:
+  anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO.) The standard
+  base addresses as well as the syntax of the "lp" command line option
+  can be found in drivers/char/lp.c. If you have more than 3 printers,
+  you need to increase the LP_NO variable in lp.c.
 
 CONFIG_PRINTER_READBACK
-  If your printer conforms to IEEE 1284, it may be able to provide a status
-  indication when you read from it (for example, with `cat /dev/lp1').  To
-  use this feature, say Y here.
+  If your printer conforms to IEEE 1284, it may be able to provide a
+  status indication when you read from it (for example, with `cat
+  /dev/lp1').  To use this feature, say Y here.
 
 Mouse Support (not serial mice)
 CONFIG_MOUSE
@@ -4489,12 +4680,14 @@
   explained in detail in the Busmouse-HOWTO, available via ftp (user:
   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. The module will be
-  called psaux.o. If you are unsure, say N and read the HOWTO
+  on the Linux console and under X. Using the "-R" option of the Linux
+  mouse managing program gpm (available from
+  sunsite.unc.edu:/pub/Linux/system/Daemons) solves this problem, or
+  you can get the "mconv" utility also from sunsite.
+  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. The module
+  will be called psaux.o. 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)
@@ -4506,9 +4699,13 @@
 
 PC110 digitizer pad support
 CONFIG_PC110_PAD
-  This drives the digitizer pad on the IBM PC110 palmtop (see 
-  http://toy.cabi.net). It can turn the digitizer pad into a 
-  mouse emulation with tap gestures or into an absolute pad.
+  This drives the digitizer pad on the IBM PC110 palmtop (see
+  http://toy.cabi.net). It can turn the digitizer pad into a PS/2
+  mouse emulation with tap gestures or into an absolute pad.  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. The module will be called
+  pc110pad.o.
 
 Microsoft busmouse support
 CONFIG_MS_BUSMOUSE
@@ -4761,13 +4958,34 @@
 CONFIG_NVRAM
   If you say Y here and create a character special file /dev/nvram
   with major number 10 and minor number 144 using mknod ("man mknod"),
-  you get access to the non-volatile memory in the real time clock
-  (RTC). This is conventionally called "CMOS RAM" on PCs and "NVRAM"
-  on Ataris. /dev/nvram may be used to view settings there, or to
-  change them (with some utility). It could also be used to frequently
-  save a few bits of very important data, that may not be lost over
-  power-off and for which writing to disk is too insecure. On Atari
-  machines, /dev/nvram is always configured and needs not be selected.
+  you get access to the 50 bytes of non-volatile memory in the real
+  time clock (RTC), which is contained in every PC and most
+  Ataris. This memory is conventionally called "CMOS RAM" on PCs and
+  "NVRAM" on Ataris. /dev/nvram may be used to view settings there, or
+  to change them (with some utility). It could also be used to
+  frequently save a few bits of very important data that may not be
+  lost over power-off and for which writing to disk is too
+  insecure. On Atari machines, /dev/nvram is always configured and
+  does not need to be selected.  This driver is also available as a
+  module ( = code which can be inserted in and removed from the
+  running kernel whenever you want). The module will be called
+  nvram.o. If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.
+
+PC joystick support
+CONFIG_JOYSTICK
+  If you have a joystick, you can say Y here. If you then create a
+  character special file under /dev with major number 15 and minor
+  number 0 or 1 (for the two joystick ports) using mknod ("man
+  mknod"), you can read the status of the buttons and the x and y
+  coordinates from that file. More information, an example program and
+  a calibration program are contained in the joystick package which is
+  available via ftp (user: anonymous) in
+  sunsite.unc.edu/pub/Linux/kernel/patches/console/. This driver is
+  also available as a module ( = code which can be inserted in and
+  removed from the running kernel whenever you want). The module will
+  be called joystick.o. If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
 
 ARC console time
 CONFIG_RTC_ARC
@@ -4902,18 +5120,14 @@
 
 Support for Crystal CS4232 based (PnP) cards
 CONFIG_CS4232
-  Say Y here if you have a card based on the Crystal CS4232 chip set.
+  Say Y here if you have a card based on the Crystal CS4232 chip set,
+  which use the Plug and Play protocol.
 
 Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers
 CONFIG_MAUI
   Say Y here if you have a Turtle Beach Wave Front, Maui, or 
   Tropez sound card.
 
-Support for Crystal CS4232 based (PnP) cards
-CONFIG_CS4232
-  Use this option to enable experimental support for cards that use
-  the Plug and Play protocol.
-
 /dev/dsp and /dev/audio support
 CONFIG_AUDIO
   Answering N disables /dev/dsp and /dev/audio, the A/D and D/A
@@ -4960,36 +5174,35 @@
 Gallant's Audio Excel DSP 16 support (SC-6000 and SC-6600)
 CONFIG_AEDSP16
   Answer Y if you have a Gallant's Audio Excel DSP 16 card. This card
-  emulate an SBPro or a Microsoft Sound System card.
-  You must select one of the Sound Blaster or Microsoft Sound System
-  drivers before select this menu item.
-  Read the drivers/sound/lowlevel/README.aedsp16 file and the head of
-  drivers/sound/lowlevel/aedsp16.c to have more informations about
-  this driver and its configuration.
-
-  If you are changing the card configuration, please, undefine all
-  the old Audio Excel parameters because leaving it defined while
-  selecting the alternate emulation, may screw up your .config file.
-
-  !!!NOTE!!!
-  The driver supports Audio Excel DSP 16 but not the III version of
-  this card. Read drivers/sound/lowlevel/Readme.aedsp16 if you want
-  to know something more on how to use the III version with this sound
-  driver.
+  can emulate an SBPro or a Microsoft Sound System card, so you should
+  have said Y to either "SoundBlaster (SB, SBPro, SB16, clones)
+  support" or "Microsoft Sound System support", above, and you need to
+  answer the "MSS emulation" and "SBPro emulation" questions below
+  accordingly. You should say Y to one and only one of these
+  questions.  Read the drivers/sound/lowlevel/README.aedsp16 file and
+  the head of drivers/sound/lowlevel/aedsp16.c to get more
+  information about this driver and its configuration.  This driver
+  supports Audio Excel DSP 16 but not the III nor Pnp versions of this
+  card. Read drivers/sound/lowlevel/README.aedsp16 if you want to know
+  something more on how to use the III version with this sound driver.
 
 SC-6600 based audio cards (new Audio Excel DSP 16)
 CONFIG_SC6600
   The SC6600 is the new version of DSP mounted on the Audio Excel DSP 16
-  cards. Check the FCC ID of your audio card and answer Y if you have an
-  SC6600 DSP.
+  cards. Find in the manual the FCC ID of your audio card and answer Y if
+  you have an SC6600 DSP.
 
 Audio Excel DSP 16 (MSS emulation)
 CONFIG_AEDSP16_MSS
-  Answer Y if you want your audio card emulate Microsoft Sound System.
+  Answer Y if you want your audio card to emulate Microsoft Sound
+  System.  You should then say Y to "Microsoft Sound System support"
+  and say N to "Audio Excel DSP 16 (SBPro emulation)".
 
 Audio Excel DSP 16 (SBPro emulation)
 CONFIG_AEDSP16_SBPRO
-  Answer Y if you want your audio card emulate Sound Blaster Pro.
+  Answer Y if you want your audio card to emulate Sound Blaster Pro.
+  You should then say Y to "SoundBlaster (SB, SBPro, SB16, clones)
+  support" and N to "Audio Excel DSP 16 (MSS emulation)".
 
 Kernel profiling support
 CONFIG_PROFILE
@@ -5016,10 +5229,10 @@
   flush the disks, reboot the system immediately or dump some status
   information). This is accomplished by pressing various keys while
   holding SysRq (Alt+PrintScreen). As you are expected to be a kernel
-  hacker to use this, the simple rule about learning what do the keys
-  mean is "Use the source, Luke!" -- read drivers/char/sysrq.c.
-  Don't say Y unless you really know what does this hack do.
- 
+  hacker to use this, the simple rule about learning what the keys
+  mean is "Use the source, Luke!" -- read drivers/char/sysrq.c.  
+  Don't say Y unless you really know what this hack does.
+
 ISDN subsystem
 CONFIG_ISDN
   ISDN ("Integrated Services Digital Networks", called RNIS in France)
@@ -5032,10 +5245,10 @@
   provider purchased an ISDN line from the phone company.  For
   details, read http://alumni.caltech.edu/~dank/isdn/ on the WWW. (To
   browse the WWW, you need to have access to a machine on the Internet
-  that has one of the programs lynx, netscape or Mosaic.)  This driver
-  allows you to use an ISDN-card for networking connections and as
-  dialin/out device. The isdn-tty's have a built in AT-compatible
-  modem emulator. Network devices support autodial, channel-bundling,
+  that has a program like lynx or netscape.)  This driver allows you
+  to use an ISDN-card for networking connections and as dialin/out
+  device. The isdn-tty's have a built in AT-compatible modem
+  emulator. Network devices support autodial, channel-bundling,
   callback and caller-authentication without having a daemon
   running. A reduced T.70 protocol is supported with tty's suitable
   for German BTX. On D-Channel, the protocols EDSS1 and 1TR6 are
@@ -5074,8 +5287,8 @@
   (mgetty+sendfax by gert@greenie.muc.de with an extension, available
   with the ISDN utility package for example), you will be able to use
   your Linux box as an ISDN-answering machine. Of course, this must be
-  supported by the lowlevel driver also. Currently, the HiSax driver is
-  the only voice-supporting driver. See
+  supported by the lowlevel driver also. Currently, the HiSax driver
+  is the only voice-supporting driver. See
   Documentation/isdn/README.audio for more information.
 
 ICN 2B and 4B support
@@ -5093,16 +5306,14 @@
 
 HiSax SiemensChipSet driver support
 CONFIG_ISDN_DRV_HISAX
-  This is an alternative driver supporting the Siemens chipset on
-  various ISDN-cards (like AVM A1, Elsa ISDN cards, Teles S0-16.0,
-  Teles S0-16.3, Teles S0-8, Teles/Creatix PnP, ITK micro ix1 and many
-  compatibles). It's a complete rewrite of the original Teles driver.
-  So you either say M or Y here and N in the above Teles section. 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. The module will be called
-  hisax.o.  See Documentation/isdn/README.HiSax for further
-  informations on using this driver.
+  This is a driver supporting the Siemens chipset on various
+  ISDN-cards (like AVM A1, Elsa ISDN cards, Teles S0-16.0, Teles
+  S0-16.3, Teles S0-8, Teles/Creatix PnP, ITK micro ix1 and many
+  compatibles). 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. The module
+  will be called hisax.o.  See Documentation/isdn/README.HiSax for
+  further informations on using this driver.
 
 HiSax Support for Teles 16.0/8.0
 CONFIG_HISAX_16_0
@@ -5127,14 +5338,21 @@
   using the different cards, a different D-channel protocol, or
   non-standard irq/port/shmem settings.
 
-HiSax Support for Elsa cards
+HiSax Support for Elsa ISA cards
 CONFIG_HISAX_ELSA_PCC
-  This enables HiSax support for the Elsa Mircolink cards and
+  This enables HiSax support for the Elsa Mircolink ISA cards and
   for the Elsa Quickstep series cards.
   See Documentation/isdn/README.HiSax on how to configure it 
   using the different cards, a different D-channel protocol, or
   non-standard irq/port/shmem settings.
 
+HiSax Support for Elsa PCMCIA card
+CONFIG_HISAX_ELSA_PCMCIA
+  This enables HiSax support for the Elsa PCMCIA cards.
+  See Documentation/isdn/README.HiSax on how to configure it 
+  using the different cards, a different D-channel protocol, or
+  non-standard irq/port/shmem settings.
+
 HiSax Support for ITK ix1-micro Revision 2
 CONFIG_HISAX_IX1MICROR2
   This enables HiSax support for the ITK ix1-micro Revision 2 card.
@@ -5149,6 +5367,11 @@
   NOTE: This is mutually exclusive with HiSax Support for
   German 1TR6 if you have only one ISDN card installed.
 
+HiSax Support for US/NI-1
+CONFIG_HISAX_NI1
+  You should choose the D-channel protocol your local
+  telephone service provider uses here by saying Y or N.
+  
 HiSax Support for German 1TR6
 CONFIG_HISAX_1TR6
   You should choose the D-channel protocol your local
@@ -5177,6 +5400,26 @@
   called sc.o.  See Documentation/isdn/README.sc and
   http://www.spellcast.com for more information.
 
+AVM-B1 with CAPI2.0 support
+CONFIG_ISDN_DRV_AVMB1
+  This enables support for the AVM B1 ISDN networking cards. In
+  addition, a CAPI (Common ISDN Application Programming Interface, a
+  standard making it easy for programs to access ISDN hardware, see
+  http://www.capi.org/) interface for this card is provided. In order
+  to use this card, additional firmware is necessary, which has to be
+  downloaded into the card using a utility which is distributed
+  separately. Please read the file Documentation/isdn/README.avmb1.
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you
+  want). The module will be called avmb1.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt.
+
+Verbose reason code reporting (kernel size +=7K)
+CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
+  If you say Y here, the AVM B1 driver will give verbose reasons for
+  disconnecting. This will increase the size of the kernel by 7K. If
+  unsure, say Y.
+
 Support for AP1000 multicomputer
 CONFIG_AP1000
   This enables support for a sparc based parallel multi-computer
@@ -5204,13 +5447,15 @@
 Amiga support
 CONFIG_AMIGA
   This option enables support for the Amiga series of computers.  If
-  you plan to use this kernel on an Amiga, say Y here; otherwise say N.
+  you plan to use this kernel on an Amiga, say Y here and browse the
+  material available in Documentation/m68k; otherwise say N.
 
 Atari support
 CONFIG_ATARI
   This option enables support for the 68000-based Atari series of
   computers (including the TT, Falcon and Medusa).  If you plan to use
-  this kernel on an Atari, say Y here; otherwise say N.
+  this kernel on an Atari, say Y here and browse the material
+  available in Documentation/m68k; otherwise say N.
 
 Macintosh support
 CONFIG_MAC
@@ -5728,4 +5973,20 @@
 # LocalWords:  wanrouter WANPIPE multiprotocol Mbps wanpipe EtherWORKS nodma SC
 # LocalWords:  smp HiSax SiemensChipSet Siemens AVM Elsa ITK hisax PCC MICROR
 # LocalWords:  Mircolink EURO DSS Spellcaster BRI sc spellcast Digiboards GPIO
-# LocalWords:  SYMBIOS COMPAT SDMS rev ASUS Tekram
+# LocalWords:  SYMBIOS COMPAT SDMS rev ASUS Tekram HX VX API ibmmcascsi ASY asy
+# LocalWords:  loader's PCnetPCI automounter AUTOFS amd autofs VT Gallant's Pnp
+# LocalWords:  AEDSP aedsp enskip tik Sysctl sysctl PARPORT parport pnp IDs EPP
+# LocalWords:  Autoprobe conformant bart patrickr HDLS READBACK AB usr DAMA DS
+# LocalWords:  Symbios PCscsi tmscsim RoamAbout GHz Hinds's contrib mathematik
+# LocalWords:  darmstadt okir DIGIEPCA International's Xem digiepca epca bootup
+# LocalWords:  zorro CAPI AVMB capi avmb VP SYN syncookies EM em pc Ethertalk
+# LocalWords:  Dayna DL Daynatalk LT PhoneNET ATB Daystar queueing CMDS SCBs ls
+# LocalWords:  SCB STATS Thinnet ThunderLAN TLAN Netelligent NetFlex tlan james
+# LocalWords:  caldera Preload dcache Preloading slowdowns schoebel uni
+# LocalWords:  stuttgart rdist TRANS hostnames mango jukeboxes ESS
+# LocalWords:  hardlinked NAMETRANS env mtab fstab umount nologin runlevel gid
+# LocalWords:  transname filespace adm Nodename hostname uname Kernelname bootp
+# LocalWords:  KERNNAME kname ktype kernelname Kerneltype KERNTYPE Alt SCB's RX
+# LocalWords:  dataless kerneltype SYSNAME Netbeui Comtrol Rocketport palmtop
+# LocalWords:  nvram SYSRQ SysRq PrintScreen sysrq NVRAMs NvRAM Shortwave RTTY
+# LocalWords:  HFMODEM shortwave Sitor Amtor Pactor GTOR hfmodem hayes TX TMOUT
diff -u --recursive --new-file v2.1.50/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.50/linux/MAINTAINERS	Mon Aug  4 16:25:35 1997
+++ linux/MAINTAINERS	Sat Aug 16 09:51:46 1997
@@ -95,6 +95,13 @@
 L:	linux-net@vger.rutgers.edu
 S:	Maintained
 
+NI5010 NETWORK DRIVER
+P:     Jan-Pascal van Best and Andreas Mohr
+M:     jvbest@qv3pluto.leidenuniv.nl (Best)
+M:     100.30936@germany.net (Mohr)
+L:     linux-net@vger.rutgers.edu
+S:     Maintained
+
 TLAN NETWORK DRIVER
 P:	James Banks
 M:	james.banks@caldera.com
@@ -259,9 +266,8 @@
 S:	Maintained
 
 MODULE SUPPORT [GENERAL], KERNELD
-P:	Bjorn Ekwall
-M:	bj0rn@blox.se
-W:	http://www.pi.se/blox/modules/
+P:	Richard Henderson
+M:	richard@gnu.ai.mit.edu
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
diff -u --recursive --new-file v2.1.50/linux/Makefile linux/Makefile
--- v2.1.50/linux/Makefile	Thu Aug 14 20:49:16 1997
+++ linux/Makefile	Sat Aug 16 09:53:08 1997
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 50
+SUBLEVEL = 51
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
@@ -147,6 +147,10 @@
 
 ifdef CONFIG_SBUS
 DRIVERS := $(DRIVERS) drivers/sbus/sbus.a
+endif
+
+ifdef CONFIG_PPC
+DRIVERS := $(DRIVERS) drivers/macintosh/macintosh.a
 endif
 
 ifdef CONFIG_PNP
diff -u --recursive --new-file v2.1.50/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.1.50/linux/arch/i386/defconfig	Mon Aug  4 16:25:35 1997
+++ linux/arch/i386/defconfig	Sat Aug 16 10:05:22 1997
@@ -148,6 +148,8 @@
 # CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
 # CONFIG_SCSI_ULTRASTOR is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
 
 #
 # Network device support
@@ -214,6 +216,7 @@
 # CONFIG_ROMFS_FS is not set
 CONFIG_AUTOFS_FS=y
 # CONFIG_UFS_FS is not set
+# CONFIG_MAC_PARTITION is not set
 
 #
 # Character devices
diff -u --recursive --new-file v2.1.50/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- v2.1.50/linux/arch/i386/kernel/i386_ksyms.c	Thu May 29 21:53:04 1997
+++ linux/arch/i386/kernel/i386_ksyms.c	Fri Aug 15 15:34:49 1997
@@ -7,6 +7,7 @@
 #include <linux/sched.h>
 #include <linux/in6.h>
 #include <linux/interrupt.h>
+#include <linux/smp_lock.h>
 
 #include <asm/semaphore.h>
 #include <asm/processor.h>
@@ -49,6 +50,7 @@
 EXPORT_SYMBOL_NOVERS(active_kernel_processor);
 EXPORT_SYMBOL(smp_invalidate_needed);
 EXPORT_SYMBOL_NOVERS(__lock_kernel);
+EXPORT_SYMBOL(lk_lockmsg);
 
 /* Global SMP irq stuff */
 EXPORT_SYMBOL(synchronize_irq);
diff -u --recursive --new-file v2.1.50/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c
--- v2.1.50/linux/arch/i386/mm/fault.c	Thu Jul 17 10:06:03 1997
+++ linux/arch/i386/mm/fault.c	Sat Aug 16 22:14:24 1997
@@ -186,16 +186,15 @@
  *
  * First we check if it was the bootup rw-test, though..
  */
-	if (wp_works_ok < 0 && address == 0xc0000000 && (error_code & 1)) {
+	if (wp_works_ok < 0 && address == TASK_SIZE && (error_code & 1)) {
 		wp_works_ok = 1;
-		pg0[0] = pte_val(mk_pte(0, PAGE_SHARED));
+		pg0[0] = pte_val(mk_pte(TASK_SIZE, PAGE_SHARED));
 		flush_tlb();
 		goto out;
 	}
-	if (address < PAGE_SIZE) {
+	if (address < PAGE_SIZE)
 		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
-		pg0[0] = pte_val(mk_pte(0, PAGE_SHARED));
-	} else
+	else
 		printk(KERN_ALERT "Unable to handle kernel paging request");
 	printk(" at virtual address %08lx\n",address);
 	__asm__("movl %%cr3,%0" : "=r" (page));
diff -u --recursive --new-file v2.1.50/linux/arch/m68k/kernel/Makefile linux/arch/m68k/kernel/Makefile
--- v2.1.50/linux/arch/m68k/kernel/Makefile	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/kernel/Makefile	Sat Aug 16 09:51:07 1997
@@ -13,7 +13,7 @@
 all: kernel.o head.o
 O_TARGET := kernel.o
 O_OBJS := entry.o process.o traps.o ints.o signal.o ptrace.o \
-	  setup.o bios32.o sys_m68k.o time.o
+	  setup.o sys_m68k.o time.o
 ifdef CONFIG_VT
 O_OBJS += console.o
 endif
diff -u --recursive --new-file v2.1.50/linux/arch/m68k/kernel/bios32.c linux/arch/m68k/kernel/bios32.c
--- v2.1.50/linux/arch/m68k/kernel/bios32.c	Wed Dec 27 12:46:21 1995
+++ linux/arch/m68k/kernel/bios32.c	Wed Dec 31 16:00:00 1969
@@ -1,7 +0,0 @@
-/*
- * bios 32 replacement
- */
-unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
-{
-	return memory_start;
-}
diff -u --recursive --new-file v2.1.50/linux/arch/m68k/kernel/process.c linux/arch/m68k/kernel/process.c
--- v2.1.50/linux/arch/m68k/kernel/process.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/m68k/kernel/process.c	Sat Aug 16 09:51:07 1997
@@ -65,7 +65,7 @@
 	current->priority = -100;
 	current->counter = -100;
 	for (;;){
-		if (!need_resched)
+		if (!resched_needed())
 #if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
 			/* block out HSYNC on the atari (falcon) */
 			__asm__("stop #0x2200" : : : "cc");
diff -u --recursive --new-file v2.1.50/linux/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c
--- v2.1.50/linux/arch/m68k/kernel/ptrace.c	Sat May 24 09:10:22 1997
+++ linux/arch/m68k/kernel/ptrace.c	Sat Aug 16 09:51:07 1997
@@ -526,7 +526,7 @@
 		goto out;
 	current->exit_code = SIGTRAP;
 	current->state = TASK_STOPPED;
-	notify_parent(current);
+	notify_parent(current, SIGCHLD);
 	schedule();
 	/*
 	 * this isn't the same as continuing with a signal, but it will do
diff -u --recursive --new-file v2.1.50/linux/arch/m68k/kernel/signal.c linux/arch/m68k/kernel/signal.c
--- v2.1.50/linux/arch/m68k/kernel/signal.c	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/kernel/signal.c	Sat Aug 16 09:51:07 1997
@@ -441,7 +441,7 @@
 					regs->pc -= 2;
 				}
 			}
-			notify_parent(current);
+			notify_parent(current, SIGCHLD);
 			schedule();
 			if (!(signr = current->exit_code)) {
 			discard_frame:
@@ -489,7 +489,7 @@
 				current->exit_code = signr;
 				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
 				      SA_NOCLDSTOP))
-					notify_parent(current);
+					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
 
diff -u --recursive --new-file v2.1.50/linux/arch/mips/Makefile linux/arch/mips/Makefile
--- v2.1.50/linux/arch/mips/Makefile	Mon Jul  7 08:18:53 1997
+++ linux/arch/mips/Makefile	Sat Aug 16 09:51:07 1997
@@ -13,29 +13,30 @@
 # Copyright (C) 1994, 1995, 1996 by Ralf Baechle
 # DECStation modifications by Paul M. Antoine, 1996
 #
-# $Id: Makefile,v 1.7 1997/06/30 15:52:03 ralf Exp $
+# $Id: Makefile,v 1.8 1997/08/08 18:11:35 miguel Exp $
 #
 
 #
 # Select the object file format to substitute into the linker script.
 #
 ifdef CONFIG_CPU_LITTLE_ENDIAN
-CROSS_COMPILE = mipsel-linux-
+CROSS_COMPILE	= mipsel-linux-
 ifdef CONFIG_MIPS_ECOFF
-oformat               = ecoff-littlemips
+oformat		= ecoff-littlemips
 else
-oformat               = elf32-littlemips
+oformat		= elf32-littlemips
 endif
 else
-CROSS_COMPILE = mips-linux-
+CROSS_COMPILE	= mips-linux-
 ifdef CONFIG_MIPS_ECOFF
-oformat               = ecoff-bigmips
+oformat		= ecoff-bigmips
 else
-oformat               = elf32-bigmips
+oformat		= elf32-bigmips
 endif
 endif
 
 LINKFLAGS	= -static -N
+MODFLAGS	+= -mlong-calls
 
 #
 # The new ELF GCC uses -G0 -mabicalls -fpic as default.  We don't need PIC
diff -u --recursive --new-file v2.1.50/linux/arch/mips/boot/Makefile linux/arch/mips/boot/Makefile
--- v2.1.50/linux/arch/mips/boot/Makefile	Thu Jun 26 12:33:36 1997
+++ linux/arch/mips/boot/Makefile	Sat Aug 16 09:51:07 1997
@@ -41,7 +41,6 @@
 	fi
 
 dep:
-	$(CPP) -M *.[cS] > .depend
 
 clean:
 	rm -f zImage zImage.tmp mkboot
diff -u --recursive --new-file v2.1.50/linux/arch/mips/config.in linux/arch/mips/config.in
--- v2.1.50/linux/arch/mips/config.in	Mon Aug  4 16:25:36 1997
+++ linux/arch/mips/config.in	Sat Aug 16 09:51:07 1997
@@ -27,6 +27,9 @@
 fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   bool 'Support for SGI workstations' CONFIG_SGI
+  if [ "$CONFIG_SGI" = "y" ]; then
+     bool 'Support for SGI graphic devices' CONFIG_SGI_GRAPHICS
+  fi
 fi
 bool 'Support for SNI RM200 PCI' CONFIG_SNI_RM200_PCI
 if [ "$CONFIG_DESKSTATION_RPC44" = "y" -o \
@@ -69,6 +72,7 @@
 fi
 if [ "$CONFIG_CPU_LITTLE_ENDIAN" = "n" ]; then
   define_bool CONFIG_BINFMT_IRIX y
+  define_bool CONFIG_FORWARD_KEYBOARD y
 fi
 define_bool CONFIG_BINFMT_ELF y
 define_bool CONFIG_BINFMT_AOUT n
@@ -93,12 +97,7 @@
   bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
 fi
 
-#
-# All SGI block devices are SCSI based AFAIK. -davem
-#
-if [ "$CONFIG_SGI" != "y" ]; then
-  source drivers/block/Config.in
-fi
+source drivers/block/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
   source net/Config.in
@@ -215,3 +214,5 @@
   int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 fi
 endmenu
+
+define_bool CONFIG_VGA_CONSOLE y
diff -u --recursive --new-file v2.1.50/linux/arch/mips/defconfig linux/arch/mips/defconfig
--- v2.1.50/linux/arch/mips/defconfig	Mon Aug  4 16:25:36 1997
+++ linux/arch/mips/defconfig	Sat Aug 16 09:51:07 1997
@@ -38,7 +38,7 @@
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSCTL=y
-# CONFIG_PNP_PARPORT is not set
+# CONFIG_PARPORT is not set
 
 #
 # Loadable module support
@@ -133,6 +133,7 @@
 # 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_SLIP is not set
@@ -154,9 +155,6 @@
 # Filesystems
 #
 # CONFIG_QUOTA is not set
-# CONFIG_DCACHE_PRELOAD is not set
-# CONFIG_OMIRR is not set
-# CONFIG_TRANS_NAMES is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_FAT_FS is not set
@@ -194,6 +192,7 @@
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
+# CONFIG_JOYSTICK is not set
 
 #
 # Sound
diff -u --recursive --new-file v2.1.50/linux/arch/mips/deskstation/hw-access.c linux/arch/mips/deskstation/hw-access.c
--- v2.1.50/linux/arch/mips/deskstation/hw-access.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/deskstation/hw-access.c	Sat Aug 16 09:51:07 1997
@@ -5,10 +5,13 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1997 by Ralf Baechle
+ *
+ * $Id: hw-access.c,v 1.2 1997/08/08 18:11:57 miguel Exp $
  */
 #include <linux/config.h>
 #include <linux/delay.h>
+#include <linux/kbdcntrlr.h>
 #include <linux/kernel.h>
 #include <linux/linkage.h>
 #include <linux/types.h>
@@ -194,3 +197,32 @@
 	rtc_write_data
 };
 #endif
+
+static unsigned char dtc_read_input(void)
+{
+	return inb(KBD_DATA_REG);
+}
+
+static void dtc_write_output(unsigned char val)
+{
+	outb(val, KBD_DATA_REG);
+}
+
+static void dtc_write_command(unsigned char val)
+{
+	outb(val, KBD_CNTL_REG);
+}
+
+static unsigned char dtc_read_status(void)
+{
+	return inb(KBD_STATUS_REG);
+}
+
+static void dtc_rm200_keyboard_setup(void)
+{
+	kbd_read_input = dtc_read_input;
+	kbd_write_output = dtc_write_output;
+	kbd_write_command = dtc_write_command;
+	kbd_read_status = dtc_read_status;
+	request_region(0x60, 16, "keyboard");
+}
diff -u --recursive --new-file v2.1.50/linux/arch/mips/deskstation/setup.c linux/arch/mips/deskstation/setup.c
--- v2.1.50/linux/arch/mips/deskstation/setup.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/deskstation/setup.c	Sat Aug 16 09:51:07 1997
@@ -6,6 +6,8 @@
  * for more details.
  *
  * Copyright (C) 1996, 1997 by Ralf Baechle
+ *
+ * $Id: setup.c,v 1.2 1997/08/08 18:11:59 miguel Exp $
  */
 #include <linux/config.h>
 #include <linux/init.h>
@@ -102,6 +104,7 @@
 #endif
 	}
 	fd_cacheflush = deskstation_fd_cacheflush;
+	keyboard_setup = dtc_keyboard_setup;
 	request_region(0x00,0x20,"dma1");
 	request_region(0x40,0x20,"timer");
 	request_region(0x70,0x10,"rtc");
diff -u --recursive --new-file v2.1.50/linux/arch/mips/jazz/g364.c linux/arch/mips/jazz/g364.c
--- v2.1.50/linux/arch/mips/jazz/g364.c	Mon Jul  7 08:18:53 1997
+++ linux/arch/mips/jazz/g364.c	Sat Aug 16 09:51:07 1997
@@ -45,13 +45,13 @@
 /* 
  * Various defines for the G364
  */
-#define G364_MEM_BASE   0xe0800000
-#define G364_PORT_BASE  0xe0200000
-#define ID_REG 		0xe0200000  	/* Read only */
-#define BOOT_REG 	0xe0280000
-#define TIMING_REG 	0xe0280108 	/* to 0x080170 - DON'T TOUCH! */
-#define MASK_REG 	0xe0280200
-#define CTLA_REG 	0xe0280300
+#define G364_MEM_BASE   0xe4400000
+#define G364_PORT_BASE  0xe4000000
+#define ID_REG 		0xe4000000  	/* Read only */
+#define BOOT_REG 	0xe4080000
+#define TIMING_REG 	0xe4080108 	/* to 0x080170 - DON'T TOUCH! */
+#define MASK_REG 	0xe4080200
+#define CTLA_REG 	0xe4080300
 #define CURS_TOGGLE 	0x800000
 #define BIT_PER_PIX	0x700000	/* bits 22 to 20 of Control A */
 #define DELAY_SAMPLE    0x080000
@@ -72,14 +72,14 @@
 #define INTL_STAND	0x000004
 #define SCRN_FORM	0x000002
 #define ENABLE_VTG	0x000001	
-#define TOP_REG 	0xe0280400
-#define CURS_PAL_REG 	0xe0280508 	/* to 0x080518 */
-#define CHKSUM_REG 	0xe0280600 	/* to 0x080610 - unused */
-#define CURS_POS_REG 	0xe0280638
-#define CLR_PAL_REG 	0xe0280800	/* to 0x080ff8 */
-#define CURS_PAT_REG 	0xe0281000	/* to 0x081ff8 */
-#define MON_ID_REG 	0xe0300000 	/* unused */
-#define RESET_REG 	0xe0380000  	/* Write only */
+#define TOP_REG 	0xe4080400
+#define CURS_PAL_REG 	0xe4080508 	/* to 0x080518 */
+#define CHKSUM_REG 	0xe4080600 	/* to 0x080610 - unused */
+#define CURS_POS_REG 	0xe4080638
+#define CLR_PAL_REG 	0xe4080800	/* to 0x080ff8 */
+#define CURS_PAT_REG 	0xe4081000	/* to 0x081ff8 */
+#define MON_ID_REG 	0xe4100000 	/* unused */
+#define RESET_REG 	0xe4180000  	/* Write only */
 
 /*
  * built-in font management constants
diff -u --recursive --new-file v2.1.50/linux/arch/mips/jazz/hw-access.c linux/arch/mips/jazz/hw-access.c
--- v2.1.50/linux/arch/mips/jazz/hw-access.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/jazz/hw-access.c	Sat Aug 16 09:51:07 1997
@@ -5,7 +5,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1995, 1996 by Ralf Baechle
+ * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
  */
 #include <linux/delay.h>
 #include <linux/linkage.h>
@@ -15,6 +15,7 @@
 #include <asm/vector.h>
 #include <asm/jazz.h>
 #include <asm/jazzdma.h>
+#include <asm/keyboard.h>
 #include <asm/pgtable.h>
 #include <asm/mc146818rtc.h>
 
@@ -146,3 +147,35 @@
 	rtc_read_data,
 	rtc_write_data
 };
+
+static volatile keyboard_hardware *jazz_kh = (keyboard_hardware *)JAZZ_KEYBOARD_ADDRESS;
+
+static unsigned char jazz_read_input(void)
+{
+	return jazz_kh->data;
+}
+
+static void jazz_write_output(unsigned char val)
+{
+	jazz_kh->data = val;
+}
+
+static void jazz_write_command(unsigned char val)
+{
+	jazz_kh->command = val;
+}
+
+static unsigned char jazz_read_status(void)
+{
+	return jazz_kh->command;
+}
+
+void jazz_keyboard_setup(void)
+{
+	kbd_read_input = jazz_read_input;
+	kbd_write_output = jazz_write_output;
+	kbd_write_command = jazz_write_command;
+	kbd_read_status = jazz_read_status;
+	request_region(0x60, 16, "keyboard");
+        r4030_write_reg16(JAZZ_IO_IRQ_ENABLE, r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) | JAZZ_IE_KEYBOARD);
+}
diff -u --recursive --new-file v2.1.50/linux/arch/mips/jazz/jazzdma.c linux/arch/mips/jazz/jazzdma.c
--- v2.1.50/linux/arch/mips/jazz/jazzdma.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/mips/jazz/jazzdma.c	Sat Aug 16 09:51:07 1997
@@ -514,3 +514,18 @@
   
     return residual;
 }
+
+/*
+ * Get DMA channel enable register
+ */
+int vdma_get_enable(int channel)
+{
+    int enable;
+    
+    enable = r4030_read_reg32(JAZZ_R4030_CHNL_ENABLE+(channel<<5));
+    
+    if (vdma_debug)
+	printk("vdma_get_enable: channel %d: enable=%d\n",channel,enable);
+    
+    return enable;
+}
diff -u --recursive --new-file v2.1.50/linux/arch/mips/jazz/setup.c linux/arch/mips/jazz/setup.c
--- v2.1.50/linux/arch/mips/jazz/setup.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/mips/jazz/setup.c	Sat Aug 16 09:51:07 1997
@@ -11,13 +11,16 @@
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
+#include <linux/mm.h>
 #include <asm/bootinfo.h>
+#include <asm/keyboard.h>
 #include <asm/irq.h>
 #include <asm/jazz.h>
 #include <asm/ptrace.h>
 #include <asm/reboot.h>
 #include <asm/vector.h>
 #include <asm/io.h>
+#include <asm/pgtable.h>
 
 /*
  * Initial irq handlers.
@@ -32,6 +35,7 @@
 extern asmlinkage void jazz_handle_int(void);
 extern asmlinkage void jazz_fd_cacheflush(const void *addr, size_t size);
 extern struct feature jazz_feature;
+extern void jazz_keyboard_setup(void);
 
 extern void jazz_machine_restart(char *command);
 extern void jazz_machine_halt(void);
@@ -94,8 +98,13 @@
 	}
     }
 
+        add_wired_entry (0x02000017, 0x03c00017, 0xe0000000, PM_64K);
+        add_wired_entry (0x02400017, 0x02440017, 0xe2000000, PM_16M);
+        add_wired_entry (0x01800017, 0x01000017, 0xe4000000, PM_4M);
+
 	irq_setup = jazz_irq_setup;
 	fd_cacheflush = jazz_fd_cacheflush;
+	keyboard_setup = jazz_keyboard_setup;
 	feature = &jazz_feature;			// Will go away
 	port_base = JAZZ_PORT_BASE;
 	isa_slot_offset = 0xe3000000;
diff -u --recursive --new-file v2.1.50/linux/arch/mips/kernel/gdb-stub.c linux/arch/mips/kernel/gdb-stub.c
--- v2.1.50/linux/arch/mips/kernel/gdb-stub.c	Mon Jul  7 08:18:53 1997
+++ linux/arch/mips/kernel/gdb-stub.c	Sat Aug 16 09:51:07 1997
@@ -12,7 +12,7 @@
  *
  *  Copyright (C) 1995 Andreas Busse
  *
- * $Id: gdb-stub.c,v 1.4 1997/06/30 15:52:25 ralf Exp $
+ * $Id: gdb-stub.c,v 1.5 1997/08/08 18:12:15 miguel Exp $
  */
 
 /*
@@ -67,12 +67,14 @@
  */
 
 #include <linux/string.h>
-#include <linux/signal.h>
 #include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
 
 #include <asm/asm.h>
 #include <asm/mipsregs.h>
-#include <asm/cachectl.h>
+#include <asm/pgtable.h>
 #include <asm/system.h>
 #include <asm/gdb-stub.h>
 
@@ -98,13 +100,11 @@
 
 static void getpacket(char *buffer);
 static void putpacket(char *buffer);
-static void set_mem_fault_trap(int enable);
 static int computeSignal(int tt);
 static int hex(unsigned char ch);
 static int hexToInt(char **ptr, int *intValue);
 static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault);
 void handle_exception(struct gdb_regs *regs);
-static void show_gdbregs(struct gdb_regs *regs);
 
 /*
  * BUFMAX defines the maximum number of characters in inbound/outbound buffers
@@ -241,6 +241,21 @@
  */
 static volatile int mem_err = 0;
 
+
+#if 0
+static void set_mem_fault_trap(int enable)
+{
+  mem_err = 0;
+
+#if 0
+  if (enable)
+    exceptionHandler(9, fltr_set_mem_err);
+  else
+    exceptionHandler(9, trap_low);
+#endif  
+}
+#endif /* dead code */
+
 /*
  * Convert the memory pointed to by mem into hex, placing result in buf.
  * Return a pointer to the last char put in buf (null), in case of mem fault,
@@ -362,19 +377,6 @@
   /* FIXME: Needs to be written... */
 }
 
-
-static void set_mem_fault_trap(int enable)
-{
-  mem_err = 0;
-
-#if 0
-  if (enable)
-    exceptionHandler(9, fltr_set_mem_err);
-  else
-    exceptionHandler(9, trap_low);
-#endif  
-}
-
 /*
  * Convert the MIPS hardware trap type code to a unix signal number.
  */
@@ -415,6 +417,38 @@
 	return (numChars);
 }
 
+
+#if 0
+/*
+ * Print registers (on target console)
+ * Used only to debug the stub...
+ */
+void show_gdbregs(struct gdb_regs * regs)
+{
+	/*
+	 * Saved main processor registers
+	 */
+	printk("$0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+	       regs->reg0, regs->reg1, regs->reg2, regs->reg3,
+               regs->reg4, regs->reg5, regs->reg6, regs->reg7);
+	printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+	       regs->reg8, regs->reg9, regs->reg10, regs->reg11,
+               regs->reg12, regs->reg13, regs->reg14, regs->reg15);
+	printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+	       regs->reg16, regs->reg17, regs->reg18, regs->reg19,
+               regs->reg20, regs->reg21, regs->reg22, regs->reg23);
+	printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+	       regs->reg24, regs->reg25, regs->reg26, regs->reg27,
+	       regs->reg28, regs->reg29, regs->reg30, regs->reg31);
+
+	/*
+	 * Saved cp0 registers
+	 */
+	printk("epc  : %08lx\nStatus: %08lx\nCause : %08lx\n",
+	       regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
+}
+#endif /* dead code */
+
 /*
  * This function does all command processing for interfacing to gdb.  It
  * returns 1 if you should skip the instruction at the trap address, 0
@@ -725,33 +759,4 @@
 			la	$8,0x80000001
 			lw	$9,0($8)
 	");
-}
-
-/*
- * Print registers (on target console)
- * Used only to debug the stub...
- */
-void show_gdbregs(struct gdb_regs * regs)
-{
-	/*
-	 * Saved main processor registers
-	 */
-	printk("$0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       regs->reg0, regs->reg1, regs->reg2, regs->reg3,
-               regs->reg4, regs->reg5, regs->reg6, regs->reg7);
-	printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       regs->reg8, regs->reg9, regs->reg10, regs->reg11,
-               regs->reg12, regs->reg13, regs->reg14, regs->reg15);
-	printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       regs->reg16, regs->reg17, regs->reg18, regs->reg19,
-               regs->reg20, regs->reg21, regs->reg22, regs->reg23);
-	printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
-	       regs->reg24, regs->reg25, regs->reg26, regs->reg27,
-	       regs->reg28, regs->reg29, regs->reg30, regs->reg31);
-
-	/*
-	 * Saved cp0 registers
-	 */
-	printk("epc  : %08lx\nStatus: %08lx\nCause : %08lx\n",
-	       regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
 }
diff -u --recursive --new-file v2.1.50/linux/arch/mips/kernel/irix5sys.h linux/arch/mips/kernel/irix5sys.h
--- v2.1.50/linux/arch/mips/kernel/irix5sys.h	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/irix5sys.h	Sat Aug 16 09:51:07 1997
@@ -1,4 +1,4 @@
-/* $Id: irix5sys.h,v 1.1 1997/06/06 09:32:29 ralf Exp $
+/* $Id: irix5sys.h,v 1.2 1997/08/08 18:12:17 miguel Exp $
  * irix5sys.h: 32-bit IRIX5 ABI system call table.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -u --recursive --new-file v2.1.50/linux/arch/mips/kernel/irixioctl.c linux/arch/mips/kernel/irixioctl.c
--- v2.1.50/linux/arch/mips/kernel/irixioctl.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/irixioctl.c	Sat Aug 16 09:51:07 1997
@@ -1,4 +1,4 @@
-/* $Id: irixioctl.c,v 1.1 1997/06/06 09:32:33 ralf Exp $
+/* $Id: irixioctl.c,v 1.2 1997/08/08 18:12:19 miguel Exp $
  * irixioctl.c: A fucking mess...
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
diff -u --recursive --new-file v2.1.50/linux/arch/mips/kernel/irixsig.c linux/arch/mips/kernel/irixsig.c
--- v2.1.50/linux/arch/mips/kernel/irixsig.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/irixsig.c	Sat Aug 16 09:51:07 1997
@@ -1,4 +1,4 @@
-/* $Id: irixsig.c,v 1.2 1997/06/13 10:11:22 ralf Exp $
+/* $Id: irixsig.c,v 1.4 1997/08/08 18:12:21 miguel Exp $
  * irixsig.c: WHEEE, IRIX signals!  YOW, am I compatable or what?!?!
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -142,7 +142,7 @@
 		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
 			current->exit_code = signr;
 			current->state = TASK_STOPPED;
-			notify_parent(current);
+			notify_parent(current, SIGCHLD);
 			schedule();
 			if (!(signr = current->exit_code))
 				continue;
@@ -180,7 +180,7 @@
 				current->exit_code = signr;
 				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & 
 						SA_NOCLDSTOP))
-					notify_parent(current);
+					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
 
@@ -593,7 +593,6 @@
 #define P_ALL    7
 
 extern int getrusage(struct task_struct *, int, struct rusage *);
-extern void release(struct task_struct * p);
 
 #define W_EXITED     1
 #define W_TRAPPED    2
@@ -680,7 +679,7 @@
 					REMOVE_LINKS(p);
 					p->p_pptr = p->p_opptr;
 					SET_LINKS(p);
-					notify_parent(p);
+					notify_parent(p, SIGCHLD);
 				} else
 					release(p);
 				goto end_waitsys;
diff -u --recursive --new-file v2.1.50/linux/arch/mips/kernel/irq.c linux/arch/mips/kernel/irq.c
--- v2.1.50/linux/arch/mips/kernel/irq.c	Mon Jul  7 08:18:53 1997
+++ linux/arch/mips/kernel/irq.c	Sat Aug 16 09:51:07 1997
@@ -11,7 +11,7 @@
  *
  * Mips support by Ralf Baechle and Andreas Busse
  *
- * $Id: irq.c,v 1.6 1997/06/30 15:52:34 ralf Exp $
+ * $Id: irq.c,v 1.7 1997/08/08 18:12:24 miguel Exp $
  */
 #include <linux/config.h>
 #include <linux/errno.h>
@@ -51,6 +51,9 @@
 static inline void mask_irq(unsigned int irq_nr)
 {
 	unsigned char mask;
+    
+        if (irq_nr >= 16)
+	    return;
 
 	mask = 1 << (irq_nr & 7);
 	if (irq_nr < 8) {
@@ -65,6 +68,9 @@
 static inline void unmask_irq(unsigned int irq_nr)
 {
 	unsigned char mask;
+
+        if (irq_nr >= 16)
+	    return;
 
 	mask = ~(1 << (irq_nr & 7));
 	if (irq_nr < 8) {
diff -u --recursive --new-file v2.1.50/linux/arch/mips/kernel/mips_ksyms.c linux/arch/mips/kernel/mips_ksyms.c
--- v2.1.50/linux/arch/mips/kernel/mips_ksyms.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/mips_ksyms.c	Sat Aug 16 09:51:07 1997
@@ -5,40 +5,69 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1997 by Ralf Baechle
+ *
+ * $Id: mips_ksyms.c,v 1.2 1997/08/08 18:12:26 miguel Exp $
  */
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
+#include <linux/in6.h>
+
+#include <asm/checksum.h>
 #include <asm/dma.h>
 #include <asm/floppy.h>
 #include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/sgihpc.h>
 #include <asm/softirq.h>
+#include <asm/uaccess.h>
 
 EXPORT_SYMBOL(EISA_bus);
 
 /*
  * String functions
  */
+EXPORT_SYMBOL_NOVERS(bcopy);
+EXPORT_SYMBOL_NOVERS(memcmp);
 EXPORT_SYMBOL_NOVERS(memset);
 EXPORT_SYMBOL_NOVERS(memcpy);
 EXPORT_SYMBOL_NOVERS(memmove);
-EXPORT_SYMBOL_NOVERS(bcopy);
+EXPORT_SYMBOL_NOVERS(strcat);
+EXPORT_SYMBOL_NOVERS(strchr);
+EXPORT_SYMBOL_NOVERS(strlen);
+EXPORT_SYMBOL_NOVERS(strncat);
+EXPORT_SYMBOL_NOVERS(strnlen);
+EXPORT_SYMBOL_NOVERS(strrchr);
+EXPORT_SYMBOL_NOVERS(strtok);
 
+EXPORT_SYMBOL(clear_page);
 EXPORT_SYMBOL(__mips_bh_counter);
 EXPORT_SYMBOL(local_irq_count);
 
+/*
+ * Userspace access stuff.
+ */
+EXPORT_SYMBOL(__copy_user);
+EXPORT_SYMBOL(active_ds);
+
 /* Networking helper routines. */
 EXPORT_SYMBOL(csum_partial_copy);
 
 /*
  * Functions to control caches.
  */
+EXPORT_SYMBOL(flush_page_to_ram);
 EXPORT_SYMBOL(fd_cacheflush);
 
 /*
  * Base address of ports for Intel style I/O.
  */
 EXPORT_SYMBOL(port_base);
+
+#ifdef CONFIG_SGI
+EXPORT_SYMBOL(hpc3c0);
+#endif
diff -u --recursive --new-file v2.1.50/linux/arch/mips/kernel/ptrace.c linux/arch/mips/kernel/ptrace.c
--- v2.1.50/linux/arch/mips/kernel/ptrace.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/ptrace.c	Sat Aug 16 09:51:07 1997
@@ -488,7 +488,7 @@
 		return;
 	current->exit_code = SIGTRAP;
 	current->state = TASK_STOPPED;
-	notify_parent(current);
+	notify_parent(current, SIGCHLD);
 	schedule();
 	/*
 	 * this isn't the same as continuing with a signal, but it will do
diff -u --recursive --new-file v2.1.50/linux/arch/mips/kernel/signal.c linux/arch/mips/kernel/signal.c
--- v2.1.50/linux/arch/mips/kernel/signal.c	Mon Jul  7 08:18:53 1997
+++ linux/arch/mips/kernel/signal.c	Sat Aug 16 09:51:07 1997
@@ -4,7 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *  Copyright (C) 1994, 1995, 1996  Ralf Baechle
  *
- * $Id: signal.c,v 1.7 1997/06/25 19:25:08 ralf Exp $
+ * $Id: signal.c,v 1.8 1997/08/08 18:12:30 miguel Exp $
  */
 #include <linux/config.h>
 #include <linux/sched.h>
@@ -292,7 +292,7 @@
 		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
 			current->exit_code = signr;
 			current->state = TASK_STOPPED;
-			notify_parent(current);
+			notify_parent(current, SIGCHLD);
 			schedule();
 			if (!(signr = current->exit_code))
 				continue;
@@ -332,7 +332,7 @@
 				current->exit_code = signr;
 				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & 
 						SA_NOCLDSTOP))
-					notify_parent(current);
+					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
 
diff -u --recursive --new-file v2.1.50/linux/arch/mips/kernel/syscall.c linux/arch/mips/kernel/syscall.c
--- v2.1.50/linux/arch/mips/kernel/syscall.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/mips/kernel/syscall.c	Sat Aug 16 09:51:07 1997
@@ -88,7 +88,7 @@
 		 *        possible.  Should help alot for battery powered
 		 *        R4200/4300i systems.
 		 */
-		if (wait_available && !need_resched)
+		if (wait_available && !resched_needed())
 			__asm__(".set\tmips3\n\t"
 				"wait\n\t"
 				".set\tmips0\n\t");
diff -u --recursive --new-file v2.1.50/linux/arch/mips/kernel/syscalls.h linux/arch/mips/kernel/syscalls.h
--- v2.1.50/linux/arch/mips/kernel/syscalls.h	Mon Aug  4 16:25:36 1997
+++ linux/arch/mips/kernel/syscalls.h	Sat Aug 16 09:51:07 1997
@@ -5,9 +5,9 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1995, 1996 by Ralf Baechle
+ * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
  *
- * $Id: syscalls.h,v 1.6 1997/07/20 15:32:25 ralf Exp $
+ * $Id: syscalls.h,v 1.7 1997/08/08 18:12:32 miguel Exp $
  */
 
 /*
@@ -208,5 +208,7 @@
 SYS(sys_query_module, 5)
 SYS(sys_poll, 3)
 SYS(sys_nfsservctl, 3)
+SYS(sys_setresgid, 3)				/* 4190 */
+SYS(sys_getresgid, 3)
 SYS(sys_setresgid, 3)				/* 4190 */
 SYS(sys_getresgid, 3)
diff -u --recursive --new-file v2.1.50/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c
--- v2.1.50/linux/arch/mips/kernel/sysirix.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/mips/kernel/sysirix.c	Sat Aug 16 09:51:07 1997
@@ -1,4 +1,4 @@
-/* $Id: sysirix.c,v 1.3 1997/07/20 15:32:25 ralf Exp $
+/* $Id: sysirix.c,v 1.4 1997/08/08 18:12:35 miguel Exp $
  * sysirix.c: IRIX system call emulation.
  *
  * Copyright (C) 1996 David S. Miller
@@ -751,6 +751,8 @@
 	}
 	error = 0;
 
+dput_and_out:
+	dput(dentry);
 out:
 	unlock_kernel();
 	return error;
@@ -1514,6 +1516,8 @@
 
 	error = 0;
 
+dput_and_out:
+	dput(dentry);
 out:
 	unlock_kernel();
 	return error;
@@ -1877,6 +1881,8 @@
 
 	error = 0;
 
+dput_and_out:
+	dput(dentry);
 out:
 	unlock_kernel();
 	return error;
diff -u --recursive --new-file v2.1.50/linux/arch/mips/kernel/sysmips.c linux/arch/mips/kernel/sysmips.c
--- v2.1.50/linux/arch/mips/kernel/sysmips.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/mips/kernel/sysmips.c	Sat Aug 16 09:51:07 1997
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
  *
- * $Id: sysmips.c,v 1.5 1997/07/20 15:32:27 ralf Exp $
+ * $Id: sysmips.c,v 1.6 1997/08/08 18:12:38 miguel Exp $
  */
 #include <linux/errno.h>
 #include <linux/linkage.h>
diff -u --recursive --new-file v2.1.50/linux/arch/mips/kernel/time.c linux/arch/mips/kernel/time.c
--- v2.1.50/linux/arch/mips/kernel/time.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/mips/kernel/time.c	Sat Aug 16 09:51:07 1997
@@ -6,7 +6,7 @@
  * This file contains the time handling details for PC-style clocks as
  * found in some MIPS systems.
  *
- * $Id: time.c,v 1.4 1997/06/30 15:52:40 ralf Exp $
+ * $Id: time.c,v 1.5 1997/08/08 18:12:39 miguel Exp $
  */
 #include <linux/errno.h>
 #include <linux/init.h>
diff -u --recursive --new-file v2.1.50/linux/arch/mips/kernel/traps.c linux/arch/mips/kernel/traps.c
--- v2.1.50/linux/arch/mips/kernel/traps.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/kernel/traps.c	Sat Aug 16 09:51:07 1997
@@ -196,6 +196,8 @@
 	/*
 	 * Assume it would be too dangerous to continue ...
 	 */
+	printk ("BE HANDLER\n");
+	show_regs (regs);
 	force_sig(SIGBUS, current);
 }
 
diff -u --recursive --new-file v2.1.50/linux/arch/mips/lib/Makefile linux/arch/mips/lib/Makefile
--- v2.1.50/linux/arch/mips/lib/Makefile	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/lib/Makefile	Sat Aug 16 09:51:07 1997
@@ -1,6 +1,12 @@
 #
 # Makefile for MIPS-specific library files..
 #
+# Many of these routines are just left over debugging trash of ancient
+# times when I just make my Tyne beep and so ...
+#
+# ...and for when I need to get the DECStation to use the boot prom to
+# do things... Paul M. Antoine.
+#
 
 .S.s:
 	$(CPP) $(CFLAGS) $< -o $*.s
@@ -8,8 +14,8 @@
 	$(CC) $(CFLAGS) -c $< -o $*.o
 
 L_TARGET = lib.a
-L_OBJS	= checksum.o copy_user.o csum.o dump_tlb.o io.o \
-	  memset.o memcpy.o strlen_user.o strncpy_user.o tags.o watch.o
+L_OBJS	= beep.o checksum.o copy_user.o csum.o dump_tlb.o io.o memset.o \
+	  memcpy.o strlen_user.o strncpy_user.o tags.o watch.o
 
 ifdef CONFIG_DECSTATION
 L_OBJS += pmaxcon.o pmaxio.o
diff -u --recursive --new-file v2.1.50/linux/arch/mips/lib/checksum.c linux/arch/mips/lib/checksum.c
--- v2.1.50/linux/arch/mips/lib/checksum.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/mips/lib/checksum.c	Sat Aug 16 09:51:07 1997
@@ -5,7 +5,7 @@
  *
  *		MIPS specific IP/TCP/UDP checksumming routines
  *
- * Authors:	Ralf Baechle, <ralf@waldorf-gmbh.de>
+ * Authors:	Ralf Baechle, <ralf@gnu.ai.mit.edu>
  *		Lots of code moved from tcp.c and ip.c; see those files
  *		for more names.
  *
@@ -14,7 +14,7 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  *
- * $Id: checksum.c,v 1.4 1997/07/03 09:43:16 ralf Exp $
+ * $Id: checksum.c,v 1.5 1997/08/08 18:12:51 miguel Exp $
  */
 #include <net/checksum.h>
 #include <linux/types.h>
diff -u --recursive --new-file v2.1.50/linux/arch/mips/lib/dump_tlb.c linux/arch/mips/lib/dump_tlb.c
--- v2.1.50/linux/arch/mips/lib/dump_tlb.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/lib/dump_tlb.c	Sat Aug 16 09:51:07 1997
@@ -16,12 +16,27 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 
+static char *region_map [] = {
+	"u", "s", "k", "!"
+};
+
+static char *cache_map [] = {
+	"c/nc/wt/nwa,",
+	"c/nc/wt/wa, ",
+	"uncached,   ",
+	"c/nc/wb,    "
+	"unknown,    ",
+	"unknown,    ",
+	"unknown,    ",
+	"unknown,    "
+};
+
 void
 dump_tlb(int first, int last)
 {
 	int	i;
 	int	wired;
-	unsigned int pagemask;
+	unsigned int pagemask, c0, c1, r;
 	unsigned long long entryhi, entrylo0, entrylo1;
 
 	wired = read_32bit_cp0_register(CP0_WIRED);
@@ -48,14 +63,25 @@
 			/*
 			 * Only print entries in use
 			 */
-			printk("\nIndex: %2d  %08x", i, pagemask);
+			printk("\nIndex: %2d pgmask=%08x ", i, pagemask);
+
+			r  = entryhi >> 62;
+			c0 = (entrylo0 >> 3) & 7;
+			c1 = (entrylo1 >> 3) & 7;
 
-			printk("  %08x %08x", (unsigned int)(entryhi >> 32),
-			                      (unsigned int) entryhi);
-			printk("  %08x %08x", (unsigned int)(entrylo0 >> 32),
-			                      (unsigned int) entrylo0);
-			printk("  %08x %08x", (unsigned int)(entrylo1 >> 32),
-			                      (unsigned int) entrylo1);
+			printk("%s vpn2=%08x "
+			       "[pfn=%06x c=%d d=%d v=%d g=%d]"
+			       "[pfn=%06x c=%d d=%d v=%d g=%d]",
+			       region_map [r], (entryhi >> 13) & 0xffffffff,
+			       (entrylo0 >> 6) & 0xffffff, c0,
+			       (entrylo0 & 4) ? 1 : 0,
+			       (entrylo0 & 2) ? 1 : 0,
+			       (entrylo0 & 1),
+			       (entrylo1 >> 6) & 0xffffff, c1,
+			       (entrylo1 & 4) ? 1 : 0,
+			       (entrylo1 & 2) ? 1 : 0,
+			       (entrylo1 & 1));
+			       
 		}
 	}
 	printk("\n");
diff -u --recursive --new-file v2.1.50/linux/arch/mips/mm/Makefile linux/arch/mips/mm/Makefile
--- v2.1.50/linux/arch/mips/mm/Makefile	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/mm/Makefile	Sat Aug 16 09:51:07 1997
@@ -11,4 +11,8 @@
 O_OBJS	 := extable.o init.o fault.o r4xx0.o r2300.o r6000.o tfp.o \
             andes.o loadmmu.o
 
+ifdef CONFIG_SGI
+O_OBJS   += umap.o
+endif
+
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.50/linux/arch/mips/mm/andes.c linux/arch/mips/mm/andes.c
--- v2.1.50/linux/arch/mips/mm/andes.c	Thu Jun 26 12:33:37 1997
+++ linux/arch/mips/mm/andes.c	Sat Aug 16 09:51:07 1997
@@ -1,4 +1,4 @@
-/* $Id: andes.c,v 1.1 1997/06/06 09:34:31 ralf Exp $
+/* $Id: andes.c,v 1.2 1997/08/08 18:13:01 miguel Exp $
  * andes.c: MMU and cache operations for the R10000 (ANDES).
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -79,6 +79,12 @@
 {
 }
 
+static void andes_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+				  unsigned long entryhi, unsigned long pagemask)
+{
+        /* XXX */
+}
+
 void ld_mmu_andes(void)
 {
 	flush_cache_all = andes_flush_cache_all;
@@ -92,6 +98,8 @@
 	flush_tlb_mm = andes_flush_tlb_mm;
 	flush_tlb_range = andes_flush_tlb_range;
 	flush_tlb_page = andes_flush_tlb_page;
+    
+        add_wired_entry = andes_add_wired_entry;
 
 	load_pgd = andes_load_pgd;
 	pgd_init = andes_pgd_init;
diff -u --recursive --new-file v2.1.50/linux/arch/mips/mm/fault.c linux/arch/mips/mm/fault.c
--- v2.1.50/linux/arch/mips/mm/fault.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/mips/mm/fault.c	Sat Aug 16 09:51:07 1997
@@ -117,7 +117,8 @@
 	 * terminate things with extreme prejudice.
 	 */
 	printk(KERN_ALERT "Unable to handle kernel paging request at virtual "
-	       "address %08lx, epc == %08lx\n", address, regs->cp0_epc);
+	       "address %08lx, epc == %08lx, ra == %08lx\n",
+	       address, regs->cp0_epc, regs->regs[31]);
 	die_if_kernel("Oops", regs, writeaccess);
 	do_exit(SIGKILL);
 out:
diff -u --recursive --new-file v2.1.50/linux/arch/mips/mm/loadmmu.c linux/arch/mips/mm/loadmmu.c
--- v2.1.50/linux/arch/mips/mm/loadmmu.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/mm/loadmmu.c	Sat Aug 16 09:51:07 1997
@@ -1,4 +1,4 @@
-/* $Id: loadmmu.c,v 1.1 1997/06/06 09:34:51 ralf Exp $
+/* $Id: loadmmu.c,v 1.2 1997/08/08 18:13:05 miguel Exp $
  * loadmmu.c: Setup cpu/cache specific function ptrs at boot time.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -41,6 +41,10 @@
 			 unsigned long address, pte_t pte);
 
 void (*show_regs)(struct pt_regs *);
+
+void (*add_wired_entry)(unsigned long entrylo0, unsigned long entrylo1,
+			unsigned long entryhi, unsigned long pagemask);
+
 asmlinkage void (*resume)(void *tsk);
 
 extern void ld_mmu_r2300(void);
diff -u --recursive --new-file v2.1.50/linux/arch/mips/mm/r2300.c linux/arch/mips/mm/r2300.c
--- v2.1.50/linux/arch/mips/mm/r2300.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/mips/mm/r2300.c	Sat Aug 16 09:51:07 1997
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: r2300.c,v 1.2 1997/06/30 15:52:51 ralf Exp $
+ * $Id: r2300.c,v 1.3 1997/08/08 18:13:06 miguel Exp $
  */
 
 #include <linux/kernel.h>
@@ -245,6 +245,14 @@
 	       (unsigned int) regs->cp0_cause);
 }
 
+static void r2300_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+				  unsigned long entryhi, unsigned long pagemask)
+{
+        /*
+	 * FIXME, to be done
+	 */
+}
+
 void ld_mmu_r2300(void)
 {
 	clear_page = r2300_clear_page;
@@ -267,6 +275,8 @@
 	update_mmu_cache = r2300_update_mmu_cache;
 
 	show_regs = r2300_show_regs;
+    
+        add_wired_entry = r2300_add_wired_entry;
 
 	flush_tlb_all();
 }
diff -u --recursive --new-file v2.1.50/linux/arch/mips/mm/r4xx0.c linux/arch/mips/mm/r4xx0.c
--- v2.1.50/linux/arch/mips/mm/r4xx0.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/mips/mm/r4xx0.c	Sat Aug 16 09:51:07 1997
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  *
- * $Id: r4xx0.c,v 1.4 1997/06/30 15:52:53 ralf Exp $
+ * $Id: r4xx0.c,v 1.5 1997/08/08 18:13:07 miguel Exp $
  */
 #include <linux/config.h>
 
@@ -1856,7 +1856,7 @@
 	set_entrylo1(0);
 	BARRIER;
 
-	entry = 0;
+	entry = get_wired();
 
 	/* Blast 'em all away. */
 	while(entry < NTLB_ENTRIES) {
@@ -1943,7 +1943,7 @@
 		int oldpid, newpid, idx;
 
 #ifdef DEBUG_TLB
-		printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page);
+               printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page);
 #endif
 		newpid = (vma->vm_mm->context & 0xff);
 		page &= (PAGE_MASK << 1);
@@ -2122,6 +2122,37 @@
 	printk("epc   : %08lx\nStatus: %08lx\nCause : %08lx\n",
 	       regs->cp0_epc, regs->cp0_status, regs->cp0_cause);
 }
+			
+static void r4k_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+				      unsigned long entryhi, unsigned long pagemask)
+{
+        unsigned long flags;
+        unsigned long wired;
+        unsigned long old_pagemask;
+        unsigned long old_ctx;
+
+        save_and_cli(flags);
+        /* Save old context and create impossible VPN2 value */
+        old_ctx = (get_entryhi() & 0xff);
+        old_pagemask = get_pagemask();
+        wired = get_wired();
+        set_wired (wired + 1);
+        set_index (wired);
+        BARRIER;    
+        set_pagemask (pagemask);
+        set_entryhi(entryhi);
+        set_entrylo0(entrylo0);
+        set_entrylo1(entrylo1);
+        BARRIER;    
+        tlb_write_indexed();
+        BARRIER;    
+    
+        set_entryhi(old_ctx);
+        BARRIER;    
+        set_pagemask (old_pagemask);
+        flush_tlb_all();    
+        restore_flags(flags);
+}
 
 /* Detect and size the various r4k caches. */
 static void probe_icache(unsigned long config)
@@ -2567,6 +2598,8 @@
 	update_mmu_cache = r4k_update_mmu_cache;
 
 	show_regs = r4k_show_regs;
+    
+        add_wired_entry = r4k_add_wired_entry;
 
 	flush_cache_all();
 	write_32bit_cp0_register(CP0_WIRED, 0);
diff -u --recursive --new-file v2.1.50/linux/arch/mips/mm/r6000.c linux/arch/mips/mm/r6000.c
--- v2.1.50/linux/arch/mips/mm/r6000.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/mm/r6000.c	Sat Aug 16 09:51:07 1997
@@ -1,4 +1,4 @@
-/* $Id: r6000.c,v 1.1 1997/06/06 09:35:31 ralf Exp $
+/* $Id: r6000.c,v 1.2 1997/08/08 18:13:11 miguel Exp $
  * r6000.c: MMU and cache routines for the R6000 processors.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -156,6 +156,12 @@
 	       (unsigned int) regs->cp0_cause);
 }
 
+static void r6000_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+				  unsigned long entryhi, unsigned long pagemask)
+{
+        /* XXX */
+}
+
 void ld_mmu_r6000(void)
 {
 	flush_cache_all = r6000_flush_cache_all;
@@ -175,6 +181,8 @@
 	update_mmu_cache = r6000_update_mmu_cache;
 
 	show_regs = r6000_show_regs;
+    
+        add_wired_entry = r6000_add_wired_entry;
 
 	flush_cache_all();
 	flush_tlb_all();
diff -u --recursive --new-file v2.1.50/linux/arch/mips/mm/tfp.c linux/arch/mips/mm/tfp.c
--- v2.1.50/linux/arch/mips/mm/tfp.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/mm/tfp.c	Sat Aug 16 09:51:07 1997
@@ -1,4 +1,4 @@
-/* $Id: tfp.c,v 1.1 1997/06/06 09:35:39 ralf Exp $
+/* $Id: tfp.c,v 1.2 1997/08/08 18:13:13 miguel Exp $
  * tfp.c: MMU and cache routines specific to the r8000 (TFP).
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -79,6 +79,12 @@
 {
 }
 
+static void tfp_add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
+				unsigned long entryhi, unsigned long pagemask)
+{
+        /* XXX */
+}
+
 void ld_mmu_tfp(void)
 {
 	flush_cache_all = tfp_flush_cache_all;
@@ -93,9 +99,11 @@
 	flush_tlb_range = tfp_flush_tlb_range;
 	flush_tlb_page = tfp_flush_tlb_page;
 
+        add_wired_entry = tfp_add_wired_entry;
+
 	load_pgd = tfp_load_pgd;
 	pgd_init = tfp_pgd_init;
-
+    
 	flush_cache_all();
 	flush_tlb_all();
 }
diff -u --recursive --new-file v2.1.50/linux/arch/mips/mm/umap.c linux/arch/mips/mm/umap.c
--- v2.1.50/linux/arch/mips/mm/umap.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/mips/mm/umap.c	Sat Aug 16 09:51:07 1997
@@ -0,0 +1,216 @@
+/*
+ * arch/mips/mm/umap.c
+ *
+ * (C) Copyright 1994 Linus Torvalds
+ *
+ * Changes:
+ *
+ * Modified from Linus source to removing active mappings from any
+ * task.  This is required for implementing the virtual graphics
+ * interface for direct rendering on the SGI - miguel.
+ *
+ * Added a routine to map a vmalloc()ed area into user space, this one
+ * is required by the /dev/shmiq driver - miguel.
+ */
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/shm.h>
+#include <linux/errno.h>
+#include <linux/mman.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <linux/swap.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+static inline void
+remove_mapping_pte_range (pmd_t *pmd, unsigned long address, unsigned long size)
+{
+	pte_t *pte;
+	unsigned long end;
+
+	if (pmd_none (*pmd))
+		return;
+	if (pmd_bad (*pmd)){
+		printk ("remove_graphics_pte_range: bad pmd (%08lx)\n", pmd_val (*pmd));
+		pmd_clear (pmd);
+		return;
+	}
+	pte = pte_offset (pmd, address);
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end > PMD_SIZE)
+		end = PMD_SIZE;
+	do {
+		pte_t entry = *pte;
+		if (pte_present (entry))
+			set_pte (pte, pte_modify (entry, PAGE_NONE));
+		address += PAGE_SIZE;
+		pte++;
+	} while (address < end);
+						  
+}
+
+static inline void
+remove_mapping_pmd_range (pgd_t *pgd, unsigned long address, unsigned long size)
+{
+	pmd_t *pmd;
+	unsigned long end;
+
+	if (pgd_none (*pgd))
+		return;
+
+	if (pgd_bad (*pgd)){
+		printk ("remove_graphics_pmd_range: bad pgd (%08lx)\n", pgd_val (*pgd));
+		pgd_clear (pgd);
+		return;
+	}
+	pmd = pmd_offset (pgd, address);
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	do {
+		remove_mapping_pte_range (pmd, address, end - address);
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	} while (address < end);
+		
+}
+
+/*
+ * This routine is called from the page fault handler to remove a
+ * range of active mappings at this point
+ */
+void
+remove_mapping (struct task_struct *task, unsigned long start, unsigned long end)
+{
+	unsigned long beg = start;
+	pgd_t *dir;
+
+	down (&task->mm->mmap_sem);
+	dir = pgd_offset (task->mm, start);
+	flush_cache_range (task->mm, beg, end);
+	while (start < end){
+		remove_mapping_pmd_range (dir, start, end - start);
+		start = (start + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	}
+	flush_tlb_range (task->mm, beg, end);
+	up (&task->mm->mmap_sem);
+}
+
+void *vmalloc_uncached (unsigned long size)
+{
+	return vmalloc_prot (size, PAGE_KERNEL_UNCACHED);
+}
+
+static inline void free_pte(pte_t page)
+{
+	if (pte_present(page)) {
+		unsigned long addr = pte_page(page);
+		if (MAP_NR(addr) >= max_mapnr || PageReserved(mem_map+MAP_NR(addr)))
+			return;
+		free_page(addr);
+		if (current->mm->rss <= 0)
+			return;
+		current->mm->rss--;
+		return;
+	}
+	swap_free(pte_val(page));
+}
+
+static inline void forget_pte(pte_t page)
+{
+	if (!pte_none(page)) {
+		printk("forget_pte: old mapping existed!\n");
+		free_pte(page);
+	}
+}
+
+/*
+ * maps a range of vmalloc()ed memory into the requested pages. the old
+ * mappings are removed. 
+ */
+static inline void
+vmap_pte_range (pte_t *pte, unsigned long address, unsigned long size, unsigned long vaddr)
+{
+	unsigned long end;
+	pgd_t *vdir;
+	pmd_t *vpmd;
+	pte_t *vpte;
+	
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end > PMD_SIZE)
+		end = PMD_SIZE;
+	do {
+		pte_t oldpage = *pte;
+		unsigned long page;
+		pte_clear(pte);
+
+		vdir = pgd_offset_k (vaddr);
+		vpmd = pmd_offset (vdir, vaddr);
+		vpte = pte_offset (vpmd, vaddr);
+		page = pte_page (*vpte);
+		
+		set_pte(pte, mk_pte_phys(page, PAGE_USERIO));
+		forget_pte(oldpage);
+		address += PAGE_SIZE;
+		vaddr += PAGE_SIZE;
+		pte++;
+	} while (address < end);
+}
+
+static inline int
+vmap_pmd_range (pmd_t *pmd, unsigned long address, unsigned long size, unsigned long vaddr)
+{
+	unsigned long end;
+
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	vaddr -= address;
+	do {
+		pte_t * pte = pte_alloc(pmd, address);
+		if (!pte)
+			return -ENOMEM;
+		vmap_pte_range(pte, address, end - address, address + vaddr);
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	} while (address < end);
+	return 0;
+}
+
+int
+vmap_page_range (unsigned long from, unsigned long size, unsigned long vaddr)
+{
+	int error = 0;
+	pgd_t * dir;
+	unsigned long beg = from;
+	unsigned long end = from + size;
+
+	vaddr -= from;
+	dir = pgd_offset(current->mm, from);
+	flush_cache_range(current->mm, beg, end);
+	while (from < end) {
+		pmd_t *pmd = pmd_alloc(dir, from);
+		error = -ENOMEM;
+		if (!pmd)
+			break;
+		error = vmap_pmd_range(pmd, from, end - from, vaddr + from);
+		if (error)
+			break;
+		from = (from + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	}
+	flush_tlb_range(current->mm, beg, end);
+	return error;
+}
diff -u --recursive --new-file v2.1.50/linux/arch/mips/sgi/kernel/setup.c linux/arch/mips/sgi/kernel/setup.c
--- v2.1.50/linux/arch/mips/sgi/kernel/setup.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/mips/sgi/kernel/setup.c	Sat Aug 16 09:51:08 1997
@@ -1,7 +1,9 @@
-/* $Id: setup.c,v 1.2 1997/06/30 15:26:24 ralf Exp $
+/*
  * setup.c: SGI specific setup, including init of the feature struct.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: setup.c,v 1.3 1997/08/08 18:13:22 miguel Exp $
  */
 #ifndef __GOGOGO__
 #error "... about to fuckup your Indy?"
@@ -9,6 +11,8 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 
+#include <asm/addrspace.h>
+#include <asm/keyboard.h>
 #include <asm/reboot.h>
 #include <asm/vector.h>
 #include <asm/sgialib.h>
@@ -26,6 +30,36 @@
 struct feature sgi_feature = {
 };
 
+static volatile struct hpc_keyb *sgi_kh = (struct hpc_keyb *) (KSEG1 + 0x1fbd9800 + 64);
+
+static unsigned char sgi_read_input(void)
+{
+	return sgi_kh->data;
+}
+
+static void sgi_write_output(unsigned char val)
+{
+	sgi_kh->data = val;
+}
+
+static void sgi_write_command(unsigned char val)
+{
+	sgi_kh->command = val;
+}
+
+static unsigned char sgi_read_status(void)
+{
+	return sgi_kh->command;
+}
+
+static void sgi_keyboard_setup(void)
+{
+	kbd_read_input = sgi_read_input;
+	kbd_write_output = sgi_write_output;
+	kbd_write_command = sgi_write_command;
+	kbd_read_status = sgi_read_status;
+}
+
 static void sgi_irq_setup(void)
 {
 	sgint_init();
@@ -52,6 +86,7 @@
 
 	irq_setup = sgi_irq_setup;
 	feature = &sgi_feature;
+	keyboard_setup = sgi_keyboard_setup;
 
 	_machine_restart = sgi_machine_restart;
 	_machine_halt = sgi_machine_halt;
diff -u --recursive --new-file v2.1.50/linux/arch/mips/sni/hw-access.c linux/arch/mips/sni/hw-access.c
--- v2.1.50/linux/arch/mips/sni/hw-access.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sni/hw-access.c	Sat Aug 16 09:51:08 1997
@@ -5,9 +5,12 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1997 by Ralf Baechle
+ *
+ * $Id: hw-access.c,v 1.2 1997/08/08 18:13:27 miguel Exp $
  */
 #include <linux/delay.h>
+#include <linux/kbdcntrlr.h>
 #include <linux/kernel.h>
 #include <linux/linkage.h>
 #include <linux/types.h>
@@ -15,6 +18,7 @@
 #include <asm/bootinfo.h>
 #include <asm/cachectl.h>
 #include <asm/dma.h>
+#include <asm/keyboard.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/mc146818rtc.h>
@@ -157,3 +161,32 @@
 	rtc_read_data,
 	rtc_write_data
 };
+
+static unsigned char sni_read_input(void)
+{
+	return inb(KBD_DATA_REG);
+}
+
+static void sni_write_output(unsigned char val)
+{
+	outb(val, KBD_DATA_REG);
+}
+
+static void sni_write_command(unsigned char val)
+{
+	outb(val, KBD_CNTL_REG);
+}
+
+static unsigned char sni_read_status(void)
+{
+	return inb(KBD_STATUS_REG);
+}
+
+void sni_rm200_keyboard_setup(void)
+{
+	kbd_read_input = sni_read_input;
+	kbd_write_output = sni_write_output;
+	kbd_write_command = sni_write_command;
+	kbd_read_status = sni_read_status;
+	request_region(0x60, 16, "keyboard");
+}
diff -u --recursive --new-file v2.1.50/linux/arch/mips/sni/setup.c linux/arch/mips/sni/setup.c
--- v2.1.50/linux/arch/mips/sni/setup.c	Thu Jun 26 12:33:38 1997
+++ linux/arch/mips/sni/setup.c	Sat Aug 16 09:51:08 1997
@@ -15,6 +15,7 @@
 #include <linux/timex.h>
 #include <linux/pci.h>
 #include <asm/bootinfo.h>
+#include <asm/keyboard.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/processor.h>
@@ -36,6 +37,7 @@
 extern asmlinkage void sni_rm200_pci_handle_int(void);
 extern asmlinkage void sni_fd_cacheflush(const void *addr, size_t size);
 extern struct feature sni_rm200_pci_feature;
+extern void sni_rm200_keyboard_setup(void);
 
 extern void sni_machine_restart(char *command);
 extern void sni_machine_halt(void);
@@ -127,6 +129,7 @@
 	fd_cacheflush = sni_fd_cacheflush;	// Will go away
 	feature = &sni_rm200_pci_feature;
 	port_base = SNI_PORT_BASE;
+	keyboard_setup = sni_rm200_keyboard_setup;
 
 	/*
 	 * Setup (E)ISA I/O memory access stuff
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/Makefile linux/arch/ppc/Makefile
--- v2.1.50/linux/arch/ppc/Makefile	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/Makefile	Sat Aug 16 09:51:08 1997
@@ -12,29 +12,30 @@
 #
 # Copyright (C) 1994 by Linus Torvalds
 # Changes for PPC by Gary Thomas
-# Modified by Cort Dougan
+# Modified by Cort Dougan and Paul Mackerras
 #
 
+ifeq ($(CONFIG_PMAC),y)
+KERNELBASE	=0xc0000000
+else
+KERNELBASE	=0x90000000
+endif
+
 # PowerPC (cross) tools
-SUFFIX		= 
-AS		= as$(SUFFIX)
-ASFLAGS		= 
-LD		= ld$(SUFFIX)
-LINKFLAGS	= -T arch/ppc/ld.script -Ttext 0x90000000 
-HOSTCC		= gcc
-CC		= gcc$(SUFFIX)
+ifneq ($(shell uname -m),ppc)
+CROSS_COMPILE 	=powerpc-eabi-
+endif
+
+ASFLAGS		=
+LINKFLAGS	= -T arch/ppc/vmlinux.lds -Ttext $(KERNELBASE) -Bstatic
 CFLAGSINC	= -D__KERNEL__ -I$(TOPDIR)/include -D__powerpc__
 CFLAGS		= $(CFLAGSINC) \
-		-Wstrict-prototypes -fomit-frame-pointer \
+		-Wall -Wstrict-prototypes -Wno-uninitialized \
 		-fno-builtin \
-		-finhibit-size-directive \
-		-O2 -fsigned-char -pipe -ffixed-r2 -mstring -mmultiple -msoft-float
-# -fverbose-asm 
+		-fsigned-char \
+		-msoft-float \
+		-O2 -pipe
 CPP		= $(CC) -E $(CFLAGS)
-AR		= ar$(SUFFIX)
-RANLIB		= ranlib$(SUFFIX)
-STRIP		= strip$(SUFFIX)
-NM		= nm$(SUFFIX)
 
 ifdef CONFIG_601
 CFLAGS := $(CFLAGS) -mcpu=601 -DCPU=601
@@ -55,59 +56,38 @@
 ARCHIVES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(ARCHIVES)
 CORE_FILES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(CORE_FILES)
 
+ifdef CONFIG_XMON
+SUBDIRS += arch/ppc/xmon
+CORE_FILES += arch/ppc/xmon/x.o
+endif
+
+ifdef CONFIG_PMAC
+MAKEBOOT = $(MAKE) -C arch/$(ARCH)/coffboot
+else
+# PReP systems
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+endif
 
 checks:
 	@$(MAKE) -C arch/$(ARCH)/kernel checks
 
-netboot: checks vmlinux
-	@$(MAKEBOOT) netboot
-
-znetboot: checks vmlinux
-	@$(MAKEBOOT) znetboot
-
-#rcpboot: checks vmlinux
-#	@$(MAKEBOOT) rcpboot
+BOOT_TARGETS = netboot znetboot zImage floppy install \
+	vmlinux.coff znetboot.initrd zImage.initrd
 
-zImage: checks vmlinux
-	@$(MAKEBOOT) zImage
+$(BOOT_TARGETS): checks vmlinux
+	@$(MAKEBOOT) $@
 
-floppy: checks vmlinux
-	@$(MAKEBOOT) floppy
-
-install: checks vmlinux
-	@$(MAKEBOOT) install
-
-vmlinux.coff : checks vmlinux
-	$(MAKE) -C arch/ppc/coffboot/ vmlinux.coff
-
-arch/ppc/kernel: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/ppc/kernel
-
-arch/ppc/mm: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/ppc/mm
-
-arch/ppc/lib: dummy
-	$(MAKE) linuxsubdirs SUBDIRS=arch/ppc/lib
-
-diffs:
-	arch/ppc/mkdiff
-
-tar:
-	arch/ppc/mktar
+tags:
+	etags */*.c include/{asm,linux}/*.h arch/ppc/kernel/*.{c,h}
 
 archclean:
-	rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h arch/ppc/kernel/checks TAGS
-	rm -f `find arch/ppc/ \( -name '*.[oas]' -o -name '*~' -o -name '#*#' \) -print`
-	rm -f `find include/asm-ppc/ \( -name '*.[oas]' -o -name '*~' -o -name '#*#' \) -print`
+	rm -f arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h
+	rm -f arch/ppc/kernel/checks
+	find arch/ppc/ -name '*.o' -exec /bin/rm -f '{}' \;
+	find arch/ppc/ -name '*~' -exec /bin/rm -f '{}' \;
+	find arch/ppc/ -name '*.a' -exec /bin/rm -f '{}' \;
 	@$(MAKEBOOT) clean
 
 archdep:
-	$(MAKE) -C arch/ppc/boot fastdep
-	$(MAKE) -C arch/ppc/kernel fastdep
-	$(MAKE) -C arch/ppc/mm fastdep
-	$(MAKE) -C arch/ppc/lib fastdep
-
-tags :
-	etags arch/ppc/*/*.c arch/ppc/*/*.S include/asm/* */*.c 
+	$(MAKEBOOT) fastdep
 
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile
--- v2.1.50/linux/arch/ppc/boot/Makefile	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/boot/Makefile	Sat Aug 16 09:51:08 1997
@@ -22,14 +22,15 @@
 	$(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $<
 
 
-ZLINKFLAGS = -T ../ld.script -Ttext 0x00800000
+ZLINKFLAGS = -T ../vmlinux.lds -Ttext 0x00800000
 GZIP_FLAGS = -v9
 
 SYSTEM = $(TOPDIR)/vmlinux
-
-OBJECTS = head.o inflate.o unzip.o misc.o vreset.o
-
+OBJECTS = head.o inflate.o unzip.o misc.o vreset.o #kbd.o
 CFLAGS = -O2 -DSTDC_HEADERS -I$(TOPDIR)/include
+OBJCOPY = objcopy
+OBJCOPY_ARGS = -O elf32-powerpc
+
 
 all:	$(TOPDIR)/zImage
 
@@ -39,41 +40,40 @@
 find_name : find_name.c
 	$(HOSTCC) $(CFLAGSINC) -o find_name find_name.c
 
-mk_type41: mk_type41.c
-	$(HOSTCC) $(CFLAGSINC) -o mk_type41 mk_type41.c
-
-piggyback: piggyback.c
-	$(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
-
 floppy: $(TOPDIR)/vmlinux zImage 
 	dd if=$(TOPDIR)/zImage of=/dev/fd0H1440 bs=64b
 
-netboot : $(TOPDIR)/vmlinux mkprep
-	mkprep $(TOPDIR)/vmlinux $(TOPDIR)/netboot
+floppy.initrd: $(TOPDIR)/vmlinux zImage 
+	dd if=$(TOPDIR)/zImage.initrd of=/dev/fd0H1440 bs=64b
 
-znetboot : zvmlinux mkprep
-	mkprep zvmlinux $(TOPDIR)/znetboot
-	cp $(TOPDIR)/znetboot /usr/local/tftpboot/vmlinux
+znetboot : zImage mkprep
+	cp $(TOPDIR)/zImage /usr/local/tftpboot/vmlinux
 
-rcpboot : znetboot
-	rcp $(TOPDIR)/znetboot charon:/usr/tftpboot/vmlinux
+znetboot.initrd : zImage.initrd mkprep
+	cp $(TOPDIR)/zImage.initrd /usr/local/tftpboot/vmlinux
 
 zImage: zvmlinux mkprep
 	mkprep -pbp zvmlinux $(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) mkprep  find_name
-	mkprep $(TOPDIR)/vmlinux -|gzip ${GZIP_FLAGS}|mkprep -asm - -|$(AS) -o piggy.o
-	$(LD) $(ZLINKFLAGS) -o zvmlinux $(OBJECTS) piggy.o
-	rm -f piggy.o
+zImage.initrd: zvmlinux.initrd mkprep
+	mkprep -pbp zvmlinux.initrd $(TOPDIR)/zImage.initrd
+
+zvmlinux: $(OBJECTS) $(SYSTEM) mkprep  find_name vmlinux.gz
+	$(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS)
+	$(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=vmlinux.gz \
+		zvmlinux.tmp $@
+	rm zvmlinux.tmp
+
+vmlinux.gz: $(TOPDIR)/vmlinux
+	dd bs=64k skip=1 if=$(TOPDIR)/vmlinux | gzip -vf9 - > vmlinux.gz
+
+zvmlinux.initrd: zvmlinux
+	$(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz \
+		zvmlinux $@
 
 clean:
-	rm -f piggyback zvmlinux mk_type41 mkprep mkboot find_name
-	rm -f $(TOPDIR)/{zImage,znetboot,netboot}
+	rm -f vmlinux* znetboot* zImage* zvmlinux* mkprep find_name
+	rm -f $(TOPDIR)/{zImage*,znetboot*,zvmlinux*,vmlinux*}
 
 fastdep:
 	$(TOPDIR)/scripts/mkdep *.[Sch] > .depend
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/boot/head.S linux/arch/ppc/boot/head.S
--- v2.1.50/linux/arch/ppc/boot/head.S	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/boot/head.S	Sat Aug 16 09:51:08 1997
@@ -13,17 +13,6 @@
 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
@@ -48,7 +37,9 @@
 	mtlr	r21
 	mtctr	r22
 	bctr			/* Jump to code */
-/* Relocate code to final resting spot */
+/* 
+ * no matter where we're loaded, move ourselves to -Ttext address
+ */
 relocate:
 	mflr	r3		/* Compute code bias */
 	subi	r3,r3,4
@@ -98,13 +89,26 @@
 	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
+	lis	r6,cmd_line@h
+	ori	r6,r6,cmd_line@l
+	subi	r7,r7,1
+00:	lbzu	r2,1(r12)
+	cmpi	0,r2,0
+	bne	00b
+
+	/* r4,r5 have initrd_start, size */
+	lis	r2,initrd_start@h
+	ori	r2,r2,initrd_start@l
+	lwz	r4,0(r2)
+	lis	r2,initrd_end@h
+	ori	r2,r2,initrd_end@l
+	lwz	r5,0(r2)
+		
+	li	r9,0x00c		/* Kernel code starts here */
+	mtlr	r9
 	blr	
 hang:
 	b	hang	
@@ -141,6 +145,45 @@
 	mtspr	HID0,r3
 	blr
 
+/*
+ * Delay for a number of microseconds
+ * -- Use the BUS timer (assumes 66MHz)
+ */
+	.globl	udelay
+udelay:		
+	mfspr	r4,PVR
+	srwi	r4,r4,16
+	cmpi	0,r4,1		/* 601 ? */
+	bne	.udelay_not_601
+00:	li	r0,86	/* Instructions / microsecond? */
+	mtctr	r0
+10:	addi	r0,r0,0 /* NOP */
+	bdnz	10b
+	subic.	r3,r3,1
+	bne	00b
+	blr
+
+.udelay_not_601:		
+	mulli	r4,r3,1000	/* nanoseconds */
+	addi	r4,r4,59
+	li	r5,60
+	divw	r4,r4,r5	/* BUS ticks */
+1:	mftbu	r5
+	mftb	r6
+	mftbu	r7
+	cmp	0,r5,r7
+	bne	1b		/* Get [synced] base time */
+	addc	r9,r6,r4	/* Compute end time */
+	addze	r8,r5
+2:	mftbu	r5
+	cmp	0,r5,r8
+	blt	2b
+	bgt	3f
+	mftb	r6
+	cmp	0,r6,r9
+	blt	2b
+3:	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
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/boot/misc.c linux/arch/ppc/boot/misc.c
--- v2.1.50/linux/arch/ppc/boot/misc.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/boot/misc.c	Sat Aug 16 09:51:08 1997
@@ -8,13 +8,23 @@
  * puts by Nick Holloway 1993
  *
  * Adapted for PowerPC by Gary Thomas
+ * Updated and modified by Cort Dougan (cort@cs.nmt.edu)
  */
 
 #include "gzip.h"
 #include "lzw.h"
 #include "asm/residual.h"
+#include <elf.h>
 
 RESIDUAL hold_residual;
+unsigned long initrd_start = 0, initrd_end = 0;
+char *zimage_start;
+int zimage_size;
+extern char input_data[];
+extern int input_len;
+void cksum_text(void);
+void verify_data(unsigned long load_addr);
+
 void dump_buf(unsigned char *p, int s);
 #define EOF -1
 
@@ -26,8 +36,7 @@
 unsigned insize;
 unsigned inptr;
 
-extern char input_data[];
-extern int input_len;
+char cmd_line[256];
 
 int input_ptr;
 
@@ -56,6 +65,9 @@
 int orig_x, orig_y;
 
 void puts(const char *);
+void putc(const char c);
+void puthex(unsigned long val);
+void _bcopy(char *src, char *dst, int len);
 
 void *malloc(int size)
 {
@@ -77,7 +89,7 @@
 	 */
           
 	if (free_mem_ptr < (long)&end) {
-		if (free_mem_ptr > (long)&input_data[input_ptr])
+		if (free_mem_ptr > (long)&zimage_start[input_ptr])
 			error("\nOut of memory\n");
 
 		return p;
@@ -87,7 +99,7 @@
 #endif	
 	return p;
 	puts("large kernel, low 1M tight...");
-	free_mem_ptr = (long)input_data;
+	free_mem_ptr = (long)zimage_start;
 	}
 }
 
@@ -114,6 +126,53 @@
 	for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
 		vidmem[i] = ' ';
 }
+#if 0
+tstc(void)
+{
+	return (CRT_tstc() );
+}
+
+getc(void)
+{
+	while (1) {
+		if (CRT_tstc()) return (CRT_getc());
+	}
+}
+#endif
+void 
+putc(const char c)
+{
+	int x,y;
+
+	x = orig_x;
+	y = orig_y;
+
+	if ( c == '\n' ) {
+		x = 0;
+		if ( ++y >= lines ) {
+			scroll();
+			y--;
+		}
+	} else if (c == '\b') {
+		if (x > 0) {
+			x--;
+		}
+	} else {
+		vidmem [ ( x + cols * y ) * 2 ] = c; 
+		if ( ++x >= cols ) {
+			x = 0;
+			if ( ++y >= lines ) {
+				scroll();
+				y--;
+			}
+		}
+	}
+
+	cursor(x, y);
+
+	orig_x = x;
+	orig_y = y;
+}
 
 void puts(const char *s)
 {
@@ -229,10 +288,10 @@
     insize = 0;
     do {
 	len = INBUFSIZ-insize;
-	if (len > (input_len-input_ptr+1)) len=input_len-input_ptr+1;
+	if (len > (zimage_size-input_ptr+1)) len=zimage_size-input_ptr+1;
         if (len == 0 || len == EOF) break;
 
-        for (i=0;i<len;i++) inbuf[insize+i] = input_data[input_ptr+i];
+        for (i=0;i<len;i++) inbuf[insize+i] = zimage_start[input_ptr+i];
 	insize += len;
 	input_ptr += len;
     } while (insize < INBUFSIZ);
@@ -313,7 +372,14 @@
 unsigned long
 decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, RESIDUAL *residual)
 {
-  unsigned long TotalMemory;
+  int timer;
+  char *cp, ch;
+  Elf32_Ehdr *eh;
+  Elf32_Shdr *sh, *strtab_shdr;
+  char *strtab;
+  unsigned long i;
+
+  
   output_data = (char *)0x0;	/* Points to 0 */
   lines = 25;
   cols = 80;
@@ -339,33 +405,102 @@
   clear_bufs();
   makecrc();
 
-  puts("Loaded at ");  puthex(load_addr);  puts(", ");  puthex(num_words);  puts(" words");
-  puts(", cksum = ");  puthex(cksum);  puts("\n");
+  puts("Loaded at: ");  puthex(load_addr); puts(" ");  puthex(num_words+load_addr);
+  puts("\n");
+  /*puts("Relocated to start: ");  puthex(start); puts(" ");
+  puthex(num_words+start);
+  puts("\n");*/
+  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;
+    _bcopy((char *)residual, (char *)&hold_residual, sizeof(hold_residual));
+    puts("Residual data at: ");  puthex((unsigned long)residual); puts(" ");
+    puthex((unsigned long)(residual->ResidualLength + residual));  puts("\n");
   }
 
-  puts("Uncompressing Linux...");
+  /*
+   * Take care of initrd if we have one
+   */
+  /*
+   * the _actual_ load addr is 64k (elf hdr size) lower but the
+   * firmware gives us the starting exec point not the load ptr
+   * -- Cort
+   */
+  eh = (Elf32_Ehdr *)(load_addr - 65536);
+  sh = (Elf32_Shdr *)((unsigned long)eh + eh->e_shoff );
+  /*puts("Entry point: "); puthex(eh->e_entry); puts("\n");*/
+  
+  /* find string table */
+  for ( i = 0 ; i <= eh->e_shnum ; i++,sh++)
+  {
+	  /*puts("Section: "); puthex(i);
+	  puts(" type: "); puthex(sh->sh_type);
+	  puts(" offset: "); puthex(sh->sh_offset);
+	  puts("\n");*/
+
+	  if ( sh->sh_type == SHT_STRTAB )
+	  {
+		  strtab_shdr = sh;
+		  strtab = (char *)(sh->sh_offset + (unsigned long)eh);
+		  /*puts("Found strtab at: "); puthex((unsigned long)strtab);
+		  puts("\n");*/
+		  break;
+	  }
+  }  
 
-  method = get_method(0);
+  /* find the initrd and image sections */
+  if ( strtab_shdr )
+  {
+	  sh = (Elf32_Shdr *)((unsigned long)eh + eh->e_shoff );
+	  for ( i = 0 ; i <= eh->e_shnum ; i++,sh++)
+	  {
+		  if ( !memcmp("initrd", (char *)(strtab+sh->sh_name), 6 ) )
+		  {
+			  initrd_start = (unsigned long)eh + sh->sh_offset;
+			  initrd_end =  initrd_start + sh->sh_size;
+			  puts("Found initrd at: "); puthex(initrd_start);
+			  puts(" "); puthex(initrd_end);
+			  puts("\n");
+		  }
+		  if ( !memcmp("image", (char *)(strtab+sh->sh_name), 5 ) )
+		  {
+			  zimage_start = (char *)((unsigned long)eh + sh->sh_offset);
+			  zimage_size =  sh->sh_size;
+			  puts("Found zimage at: "); puthex((unsigned long)zimage_start);
+			  puts(" "); puthex((unsigned long)(zimage_size+zimage_start));
+			  puts("\n");
+		  }
+	  }
+  }
+  else
+  {
+	  puts("Couldn't find string table for boot image!\n");
+  }
+  
+  /* relocate initrd */
+  if ( initrd_start )
+  {
+	  memcpy ((void *)0x00D00000,(void *)initrd_start,
+		  initrd_end - initrd_start );
+	  initrd_end = 0x00D00000 + initrd_end - initrd_start;
+	  initrd_start = 0x00D00000;
+	  puts("Moved initrd to: "); puthex(initrd_start);
+	  puts(" "); puthex(initrd_end); puts("\n");
+  }
 
+  /* make the moto firmware print something */
+  
+  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;
+  return (unsigned long)&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);
@@ -407,14 +542,14 @@
 {
   unsigned int *ptr, len, cksum, cnt;
   cksum = cnt = 0;
-  ptr = input_data;
+  ptr = (unsigned int *)zimage_start;
   puts("Checksums: ");
-  for (len = 0;  len < input_len;  len += 4) {
+  for (len = 0;  len < zimage_size;  len += 4) {
     cksum ^= *ptr++;
     if (len && ((len & 0x0FFF) == 0)) {
       if (cnt == 0) {
 	puts("\n  [");
-	puthex(ptr-1);
+	puthex((unsigned long)ptr-1);
 	puts("] ");
       }
       puthex(cksum);
@@ -429,7 +564,7 @@
   puts("Data cksum = ");  puthex(cksum);  puts("\n");
 }
 
-cksum_text()
+void cksum_text(void)
 {
   extern int start, etext;
   unsigned int *ptr, len, text_len, cksum, cnt;
@@ -442,7 +577,7 @@
     if (len && ((len & 0x0FFF) == 0)) {
       if (cnt == 0) {
 	puts("\n  [");
-	puthex(ptr-1);
+	puthex((unsigned long)ptr-1);
 	puts("] ");
       }
       puthex(cksum);
@@ -457,24 +592,24 @@
   puts("TEXT cksum = ");  puthex(cksum);  puts("\n");
 }
 
-verify_data(unsigned long load_addr)
+void 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) {
+  copy_ptr = (unsigned int *)zimage_start;
+  orig_ptr = (unsigned int *)(load_addr + ((unsigned int)zimage_start - (unsigned int)&start));
+  for (len = 0;  len < zimage_size;  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) {
+  copy_ptr = (unsigned int *)zimage_start;
+  orig_ptr = (unsigned int *)(load_addr + ((unsigned int)zimage_start - (unsigned int)&start));
+  for (len = 0;  len < zimage_size;  len += 4) {
     if (*copy_ptr++ != *orig_ptr++) {
-      dump_buf(copy_ptr-1, 128);
-      dump_buf(orig_ptr-1, 128);
+      dump_buf((unsigned char *) (copy_ptr-1), 128);
+      dump_buf((unsigned char *) (orig_ptr-1), 128);
       puts("Total errors = ");  puthex(errors*4);  puts("\n");
       while (1) ;
     }    
@@ -486,9 +621,9 @@
   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) {
+  copy_ptr = (unsigned int *)zimage_start;
+  orig_ptr = (unsigned int *)(load_addr + ((unsigned int)zimage_start - (unsigned int)&start));
+  for (len = 0;  len < zimage_size;  len += 4) {
     if (*copy_ptr++ != *orig_ptr++) {
       errors++;
     }    
@@ -532,7 +667,7 @@
    }
    while (s > 0)
    {
-      puthex(p);  puts(": ");
+      puthex((unsigned long)p);  puts(": ");
       for (i = 0;  i < 16;  i++)
       {
          if (i < s)
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/boot/mkprep.c linux/arch/ppc/boot/mkprep.c
--- v2.1.50/linux/arch/ppc/boot/mkprep.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/boot/mkprep.c	Sat Aug 16 09:51:08 1997
@@ -131,17 +131,18 @@
   argptr++;
 
   /* skip elf header in input file */
-  lseek(in_fd, elfhdr_size, SEEK_SET);
+  if ( !prep )
+	  lseek(in_fd, elfhdr_size, SEEK_SET);
   
   /* write prep partition if necessary */
   if ( prep )
-    write_prep_partition( in_fd, out_fd );
+	  write_prep_partition( in_fd, out_fd );
 
   /* write input image to bootimage */
   if ( asmoutput )
-    write_asm_data( in_fd, out_fd );
+	  write_asm_data( in_fd, out_fd );
   else
-    copy_image(in_fd, out_fd);
+	  copy_image(in_fd, out_fd);
   
   return 0;
 }
@@ -161,28 +162,11 @@
   }
   
   bzero( block, sizeof block );
-
  
-  /* set entry point and boot image size */
-  *entry = cpu_to_le32(0x400);
-  /* need use size - elfheader? */
+  /* set entry point and boot image size skipping over elf header */
+  *entry = cpu_to_le32(0x400+65536);
   *length = cpu_to_le32(info.st_size+0x400);
 
-  /*
-   * Writes the "boot record", which contains the partition table, to the
-   * diskette, followed by the dummy PC boot block and load image descriptor
-   * block.  It returns the number of bytes it has written to the load
-   * image.
-   *
-   * The boot record is the first block of the diskette and identifies the
-   * "PReP" partition.  The "PReP" partition contains the "load image" starting
-   * at offset zero within the partition.  The first block of the load image is
-   * a dummy PC boot block.  The second block is the "load image descriptor"
-   * which contains the size of the load image and the entry point into the
-   * image.  The actual boot image starts at offset 1024 bytes (third sector)
-   * in the partition.
-   */
-  
   /* sets magic number for msdos partition (used by linux) */
   block[510] = 0x55;
   block[511] = 0xAA;
@@ -220,7 +204,7 @@
   /* This has to be 0 on the PowerStack? */   
   pe->beginning_sector  = cpu_to_le32(0);
 #endif    
-/*pe->number_of_sectors = cpu_to_le32(2*18*80-1);*/
+  pe->number_of_sectors = cpu_to_le32(2*18*80-1);
 
   write( out, block, sizeof(block) );
   write( out, entry, sizeof(*entry) );
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/coffboot/Makefile linux/arch/ppc/coffboot/Makefile
--- v2.1.50/linux/arch/ppc/coffboot/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/coffboot/Makefile	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,50 @@
+# Makefile for making XCOFF bootable images for booting on PowerMacs
+# using Open Firmware.
+#
+# Paul Mackerras	January 1997
+
+# PowerPC (cross) tools
+ifneq ($(shell uname -m),ppc)
+CROSS_COMPILE 	=powerpc-eabi-
+endif
+
+HOSTCC	= gcc
+HOSTCFLAGS = -O -I$(TOPDIR)/include
+
+CC	= $(CROSS_COMPILE)gcc
+LD	= $(CROSS_COMPILE)ld
+CFLAGS	= -O -fno-builtin -I$(TOPDIR)/include
+OBJCOPY = $(CROSS_COMPILE)objcopy
+OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment \
+	--add-section=image=zImage
+LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic
+GZIP = gzip -9
+
+OBJS = crt0.o start.o main.o misc.o string.o zlib.o
+LIBS = $(TOPDIR)/lib/lib.a
+
+vmlinux.coff: coffboot hack-coff zImage
+	$(OBJCOPY) $(OBJCOPY_ARGS) coffboot $@
+	./hack-coff $@
+
+vmlinux.coff.initrd: coffboot hack-coff zImage ramdisk.image.gz
+	$(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=ramdisk.image.gz \
+		coffboot $@
+	./hack-coff $@
+
+coffboot: $(OBJS) ld.script
+	$(LD) -o coffboot $(LD_ARGS) $(OBJS) $(LIBS)
+
+zImage: $(TOPDIR)/vmlinux elfextract
+	./elfextract $(TOPDIR)/vmlinux | $(GZIP) >zImage
+
+hack-coff: hack-coff.c
+	$(HOSTCC) $(HOSTCFLAGS) -o hack-coff hack-coff.c
+
+elfextract: elfextract.c
+	$(HOSTCC) $(HOSTCFLAGS) -o elfextract elfextract.c
+
+clean:
+	rm -f elfextract hack-coff coffboot zImage vmlinux.coff
+
+fastdep:
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/coffboot/crt0.S linux/arch/ppc/coffboot/crt0.S
--- v2.1.50/linux/arch/ppc/coffboot/crt0.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/coffboot/crt0.S	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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.
+ */
+	.text
+	.globl	_start
+_start:
+	.long	__start,0,0
+
+	.globl	__start
+__start:
+	lis	9,_start@h
+	lis	8,_etext@ha
+	addi	8,8,_etext@l
+1:	dcbf	0,9
+	icbi	0,9
+	addi	9,9,0x20
+	cmplwi	0,9,8
+	blt	1b
+	b	start
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/coffboot/elfextract.c linux/arch/ppc/coffboot/elfextract.c
--- v2.1.50/linux/arch/ppc/coffboot/elfextract.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/coffboot/elfextract.c	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,98 @@
+/*
+ * Extract the loadable program segment from an elf file.
+ *
+ * Copyright 1996 Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <stdio.h>
+#include <linux/elf.h>
+
+FILE *fi, *fo;
+char *ni, *no;
+char buf[65536];
+
+void
+rd(void *buf, int len)
+{
+    int nr;
+
+    nr = fread(buf, 1, len, fi);
+    if (nr == len)
+	return;
+    if (ferror(fi))
+	fprintf(stderr, "%s: read error\n", ni);
+    else
+	fprintf(stderr, "%s: short file\n", ni);
+    exit(1);
+}
+
+main(int ac, char **av)
+{
+    unsigned nb, len;
+    Elf32_Ehdr eh;
+    Elf32_Phdr ph;
+
+    if (ac > 3 || ac > 1 && av[1][0] == '-') {
+	fprintf(stderr, "Usage: %s [elf-file [image-file]]\n", av[0]);
+	exit(0);
+    }
+
+    fi = stdin;
+    ni = "(stdin)";
+    fo = stdout;
+    no = "(stdout)";
+
+    if (ac > 1) {
+	ni = av[1];
+	fi = fopen(ni, "rb");
+	if (fi == NULL) {
+	    perror(ni);
+	    exit(1);
+	}
+    }
+
+    rd(&eh, sizeof(eh));
+    if (eh.e_ident[EI_MAG0] != ELFMAG0
+	|| eh.e_ident[EI_MAG1] != ELFMAG1
+	|| eh.e_ident[EI_MAG2] != ELFMAG2
+	|| eh.e_ident[EI_MAG3] != ELFMAG3) {
+	fprintf(stderr, "%s: not an ELF file\n", ni);
+	exit(1);
+    }
+
+    fseek(fi, eh.e_phoff + (eh.e_phnum - 1) * sizeof(ph), 0);
+    rd(&ph, sizeof(ph));
+    if (ph.p_type != PT_LOAD) {
+	fprintf(stderr, "%s: doesn't have a loadable segment\n", ni);
+	exit(1);
+    }
+
+    if (ac > 2) {
+	no = av[2];
+	fo = fopen(no, "wb");
+	if (fo == NULL) {
+	    perror(no);
+	    exit(1);
+	}
+    }
+
+    fseek(fi, ph.p_offset, 0);
+    for (len = ph.p_filesz; len != 0; len -= nb) {
+	nb = len;
+	if (nb > sizeof(buf))
+	    nb = sizeof(buf);
+	rd(buf, nb);
+	if (fwrite(buf, 1, nb, fo) != nb) {
+	    fprintf(stderr, "%s: write error\n", no);
+	    exit(1);
+	}
+    }
+
+    fclose(fo);
+    fclose(fi);
+    exit(0);
+}
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/coffboot/hack-coff.c linux/arch/ppc/coffboot/hack-coff.c
--- v2.1.50/linux/arch/ppc/coffboot/hack-coff.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/coffboot/hack-coff.c	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,79 @@
+/*
+ * hack-coff.c - hack the header of an xcoff file to fill in
+ * a few fields needed by the Open Firmware xcoff loader on
+ * Power Macs but not initialized by objcopy.
+ *
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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.
+ */
+#include <stdio.h>
+#include "rs6000.h"
+
+#define AOUT_MAGIC	0x010b
+
+#define get_16be(x)	((((unsigned char *)(x))[0] << 8) \
+			 + ((unsigned char *)(x))[1])
+#define put_16be(x, v)	(((unsigned char *)(x))[0] = (v) >> 8, \
+			 ((unsigned char *)(x))[1] = (v) & 0xff)
+#define get_32be(x)	((((unsigned char *)(x))[0] << 24) \
+			 + (((unsigned char *)(x))[1] << 16) \
+			 + (((unsigned char *)(x))[2] << 8) \
+			 + ((unsigned char *)(x))[3])
+
+main(int ac, char **av)
+{
+    int fd;
+    int i, nsect;
+    int aoutsz;
+    struct external_filehdr fhdr;
+    AOUTHDR aout;
+    struct external_scnhdr shdr;
+
+    if (ac != 2) {
+	fprintf(stderr, "Usage: hack-coff coff-file\n");
+	exit(1);
+    }
+    if ((fd = open(av[1], 2)) == -1) {
+	perror(av[2]);
+	exit(1);
+    }
+    if (read(fd, &fhdr, sizeof(fhdr)) != sizeof(fhdr))
+	goto readerr;
+    i = get_16be(fhdr.f_magic);
+    if (i != U802TOCMAGIC && i != U802WRMAGIC && i != U802ROMAGIC) {
+	fprintf(stderr, "%s: not an xcoff file\n", av[1]);
+	exit(1);
+    }
+    aoutsz = get_16be(fhdr.f_opthdr);
+    if (read(fd, &aout, aoutsz) != aoutsz)
+	goto readerr;
+    nsect = get_16be(fhdr.f_nscns);
+    for (i = 0; i < nsect; ++i) {
+	if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr))
+	    goto readerr;
+	if (strcmp(shdr.s_name, ".text") == 0) {
+	    put_16be(aout.o_snentry, i+1);
+	    put_16be(aout.o_sntext, i+1);
+	} else if (strcmp(shdr.s_name, ".data") == 0) {
+	    put_16be(aout.o_sndata, i+1);
+	} else if (strcmp(shdr.s_name, ".bss") == 0) {
+	    put_16be(aout.o_snbss, i+1);
+	}
+    }
+    put_16be(aout.magic, AOUT_MAGIC);
+    if (lseek(fd, (long) sizeof(struct external_filehdr), 0) == -1
+	|| write(fd, &aout, aoutsz) != aoutsz) {
+	fprintf(stderr, "%s: write error\n", av[1]);
+	exit(1);
+    }
+    close(fd);
+    exit(0);
+
+readerr:
+    fprintf(stderr, "%s: read error or file too short\n", av[1]);
+    exit(1);
+}
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/coffboot/ld.script linux/arch/ppc/coffboot/ld.script
--- v2.1.50/linux/arch/ppc/coffboot/ld.script	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/coffboot/ld.script	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,68 @@
+OUTPUT_ARCH(powerpc)
+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)
+    *(.rodata)
+    *(.rodata1)
+    *(.got1)
+  }
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+  _etext = .;
+  PROVIDE (etext = .);
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x0FFF) & 0xFFFFF000;
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.got.plt) *(.got)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  _edata  =  .;
+  PROVIDE (edata = .);
+  __bss_start = .;
+  .bss       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  _end = . ;
+  PROVIDE (end = .);
+}
+
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/coffboot/main.c linux/arch/ppc/coffboot/main.c
--- v2.1.50/linux/arch/ppc/coffboot/main.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/coffboot/main.c	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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.
+ */
+#include "nonstdio.h"
+#include "rs6000.h"
+#include "zlib.h"
+
+extern void *finddevice(const char *);
+extern int getprop(void *, const char *, void *, int);
+void gunzip(void *, int, unsigned char *, int *);
+
+#define get_16be(x)	(*(unsigned short *)(x))
+#define get_32be(x)	(*(unsigned *)(x))
+
+#define RAM_START	0xc0000000
+#define RAM_END		0xc0800000	/* only 8M mapped with BATs */
+
+#define RAM_FREE	0xc0540000	/* after image of coffboot */
+
+char *avail_ram;
+char *end_avail;
+
+coffboot(int a1, int a2, void *prom)
+{
+    void *options;
+    unsigned loadbase;
+    struct external_filehdr *eh;
+    struct external_scnhdr *sp;
+    struct external_scnhdr *isect, *rsect;
+    int ns, oh, i;
+    unsigned sa, len;
+    void *dst;
+    unsigned char *im;
+    unsigned initrd_start, initrd_size;
+
+    printf("coffboot starting\n");
+    options = finddevice("/options");
+    if (options == (void *) -1)
+	exit();
+    if (getprop(options, "load-base", &loadbase, sizeof(loadbase))
+	!= sizeof(loadbase)) {
+	printf("error getting load-base\n");
+	exit();
+    }
+    setup_bats();
+
+    eh = (struct external_filehdr *) loadbase;
+    ns = get_16be(eh->f_nscns);
+    oh = get_16be(eh->f_opthdr);
+
+    sp = (struct external_scnhdr *) (loadbase + sizeof(struct external_filehdr) + oh);
+    isect = rsect = NULL;
+    for (i = 0; i < ns; ++i, ++sp) {
+	if (strcmp(sp->s_name, "image") == 0)
+	    isect = sp;
+	else if (strcmp(sp->s_name, "initrd") == 0)
+	    rsect = sp;
+    }
+    if (isect == NULL) {
+	printf("image section not found\n");
+	exit();
+    }
+
+    if (rsect != NULL && (initrd_size = get_32be(rsect->s_size)) != 0) {
+	initrd_start = (RAM_END - initrd_size) & ~0xFFF;
+	a1 = initrd_start;
+	a2 = initrd_size;
+	printf("initial ramdisk at %x (%u bytes)\n",
+	       initrd_start, initrd_size);
+	memcpy((char *) initrd_start,
+	       (char *) (loadbase + get_32be(rsect->s_scnptr)),
+	       initrd_size);
+	end_avail = (char *) initrd_start;
+    } else {
+	end_avail = (char *) RAM_END;
+    }
+	
+    im = (unsigned char *)(loadbase + get_32be(isect->s_scnptr));
+    len = get_32be(isect->s_size);
+    dst = (void *) RAM_START;
+
+    if (im[0] == 0x1f && im[1] == 0x8b) {
+	void *cp = (void *) RAM_FREE;
+	avail_ram = (void *) (RAM_FREE + ((len + 7) & -8));
+	memcpy(cp, im, len);
+	printf("gunzipping... ");
+	gunzip(dst, 0x400000, cp, &len);
+	printf("done\n");
+
+    } else {
+	memmove(dst, im, len);
+    }
+
+    flush_cache(dst, len);
+
+    sa = *(unsigned *)dst + RAM_START;
+    printf("start address = 0x%x\n", sa);
+
+#if 0
+    pause();
+#endif
+    (*(void (*)())sa)(a1, a2, prom);
+
+    printf("returned?\n");
+
+    pause();
+}
+
+void *zalloc(void *x, unsigned items, unsigned size)
+{
+    void *p = avail_ram;
+
+    size *= items;
+    size = (size + 7) & -8;
+    avail_ram += size;
+    if (avail_ram > end_avail) {
+	printf("oops... out of memory\n");
+	pause();
+    }
+    return p;
+}
+
+void zfree(void *x, void *addr, unsigned nb)
+{
+}
+
+#define HEAD_CRC	2
+#define EXTRA_FIELD	4
+#define ORIG_NAME	8
+#define COMMENT		0x10
+#define RESERVED	0xe0
+
+#define DEFLATED	8
+
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+{
+    z_stream s;
+    int r, i, flags;
+
+    /* skip header */
+    i = 10;
+    flags = src[3];
+    if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+	printf("bad gzipped data\n");
+	exit();
+    }
+    if ((flags & EXTRA_FIELD) != 0)
+	i = 12 + src[10] + (src[11] << 8);
+    if ((flags & ORIG_NAME) != 0)
+	while (src[i++] != 0)
+	    ;
+    if ((flags & COMMENT) != 0)
+	while (src[i++] != 0)
+	    ;
+    if ((flags & HEAD_CRC) != 0)
+	i += 2;
+    if (i >= *lenp) {
+	printf("gunzip: ran out of data in header\n");
+	exit();
+    }
+
+    s.zalloc = zalloc;
+    s.zfree = zfree;
+    r = inflateInit2(&s, -MAX_WBITS);
+    if (r != Z_OK) {
+	printf("inflateInit2 returned %d\n", r);
+	exit();
+    }
+    s.next_in = src + i;
+    s.avail_in = *lenp - i;
+    s.next_out = dst;
+    s.avail_out = dstlen;
+    r = inflate(&s, Z_FINISH);
+    if (r != Z_OK && r != Z_STREAM_END) {
+	printf("inflate returned %d\n", r);
+	exit();
+    }
+    *lenp = s.next_out - (unsigned char *) dst;
+    inflateEnd(&s);
+}
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/coffboot/misc.S linux/arch/ppc/coffboot/misc.S
--- v2.1.50/linux/arch/ppc/coffboot/misc.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/coffboot/misc.S	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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.
+ */
+	.text
+
+/*
+ * Use the BAT0 registers to map the 1st 8MB of RAM to 0xc0000000.
+ */
+	.globl	setup_bats
+setup_bats:
+	mfpvr	3
+	rlwinm	3,3,16,16,31		/* r3 = 1 for 601, 4 for 604 */
+	cmpi	0,3,1
+	lis	4,0xc000
+	bne	4f
+	ori	4,4,4			/* set up BAT registers for 601 */
+	li	5,0x7f
+	b	5f
+4:	ori	4,4,0xff		/* set up BAT registers for 604 */
+	li	5,2
+	mtdbatu	0,4
+	mtdbatl	0,5
+5:	mtibatu	0,4
+	mtibatl	0,5
+	isync
+	blr
+
+/*
+ * Flush the dcache and invalidate the icache for a range of addresses.
+ *
+ * flush_cache(addr, len)
+ */
+	.global	flush_cache
+flush_cache:
+	addi	4,4,0x1f	/* len = (len + 0x1f) / 0x20 */
+	rlwinm.	4,4,27,5,31
+	mtctr	4
+	beqlr
+1:	dcbf	0,3
+	icbi	0,3
+	addi	3,3,0x20
+	bdnz	1b
+	sync
+	isync
+	blr
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/coffboot/nonstdio.h linux/arch/ppc/coffboot/nonstdio.h
--- v2.1.50/linux/arch/ppc/coffboot/nonstdio.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/coffboot/nonstdio.h	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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.
+ */
+typedef int	FILE;
+extern FILE *stdin, *stdout;
+#define NULL	((void *)0)
+#define EOF	(-1)
+#define fopen(n, m)	NULL
+#define fflush(f)	0
+#define fclose(f)	0
+extern char *fgets();
+
+#define perror(s)	printf("%s: no files!\n", (s))
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/coffboot/rs6000.h linux/arch/ppc/coffboot/rs6000.h
--- v2.1.50/linux/arch/ppc/coffboot/rs6000.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/coffboot/rs6000.h	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,243 @@
+/* IBM RS/6000 "XCOFF" file definitions for BFD.
+   Copyright (C) 1990, 1991 Free Software Foundation, Inc.
+   FIXME: Can someone provide a transliteration of this name into ASCII?
+   Using the following chars caused a compiler warning on HIUX (so I replaced
+   them with octal escapes), and isn't useful without an understanding of what
+   character set it is.
+   Written by Mimi Ph\373\364ng-Th\345o V\365 of IBM
+   and John Gilmore of Cygnus Support.  */
+
+/********************** FILE HEADER **********************/
+
+struct external_filehdr {
+	char f_magic[2];	/* magic number			*/
+	char f_nscns[2];	/* number of sections		*/
+	char f_timdat[4];	/* time & date stamp		*/
+	char f_symptr[4];	/* file pointer to symtab	*/
+	char f_nsyms[4];	/* number of symtab entries	*/
+	char f_opthdr[2];	/* sizeof(optional hdr)		*/
+	char f_flags[2];	/* flags			*/
+};
+
+        /* IBM RS/6000 */
+#define U802WRMAGIC     0730    /* writeable text segments **chh**      */
+#define U802ROMAGIC     0735    /* readonly sharable text segments      */
+#define U802TOCMAGIC    0737    /* readonly text segments and TOC       */
+
+#define BADMAG(x)	\
+	((x).f_magic != U802ROMAGIC && (x).f_magic != U802WRMAGIC && \
+	 (x).f_magic != U802TOCMAGIC)
+
+#define	FILHDR	struct external_filehdr
+#define	FILHSZ	20
+
+
+/********************** AOUT "OPTIONAL HEADER" **********************/
+
+
+typedef struct 
+{
+  unsigned char	magic[2];	/* type of file			*/
+  unsigned char	vstamp[2];	/* version stamp		*/
+  unsigned char	tsize[4];	/* text size in bytes, padded to FW bdry */
+  unsigned char	dsize[4];	/* initialized data "  "	*/
+  unsigned char	bsize[4];	/* uninitialized data "   "	*/
+  unsigned char	entry[4];	/* entry pt.			*/
+  unsigned char	text_start[4];	/* base of text used for this file */
+  unsigned char	data_start[4];	/* base of data used for this file */
+  unsigned char	o_toc[4];	/* address of TOC */
+  unsigned char	o_snentry[2];	/* section number of entry point */
+  unsigned char	o_sntext[2];	/* section number of .text section */
+  unsigned char	o_sndata[2];	/* section number of .data section */
+  unsigned char	o_sntoc[2];	/* section number of TOC */
+  unsigned char	o_snloader[2];	/* section number of .loader section */
+  unsigned char	o_snbss[2];	/* section number of .bss section */
+  unsigned char	o_algntext[2];	/* .text alignment */
+  unsigned char	o_algndata[2];	/* .data alignment */
+  unsigned char	o_modtype[2];	/* module type (??) */
+  unsigned char o_cputype[2];	/* cpu type */
+  unsigned char	o_maxstack[4];	/* max stack size (??) */
+  unsigned char o_maxdata[4];	/* max data size (??) */
+  unsigned char	o_resv2[12];	/* reserved */
+}
+AOUTHDR;
+
+#define AOUTSZ 72
+#define SMALL_AOUTSZ (28)
+#define AOUTHDRSZ 72
+
+#define	RS6K_AOUTHDR_OMAGIC	0x0107	/* old: text & data writeable */
+#define	RS6K_AOUTHDR_NMAGIC	0x0108	/* new: text r/o, data r/w */
+#define	RS6K_AOUTHDR_ZMAGIC	0x010B	/* paged: text r/o, both page-aligned */
+
+
+/********************** SECTION HEADER **********************/
+
+
+struct external_scnhdr {
+	char		s_name[8];	/* section name			*/
+	char		s_paddr[4];	/* physical address, aliased s_nlib */
+	char		s_vaddr[4];	/* virtual address		*/
+	char		s_size[4];	/* section size			*/
+	char		s_scnptr[4];	/* file ptr to raw data for section */
+	char		s_relptr[4];	/* file ptr to relocation	*/
+	char		s_lnnoptr[4];	/* file ptr to line numbers	*/
+	char		s_nreloc[2];	/* number of relocation entries	*/
+	char		s_nlnno[2];	/* number of line number entries*/
+	char		s_flags[4];	/* flags			*/
+};
+
+/*
+ * names of "special" sections
+ */
+#define _TEXT	".text"
+#define _DATA	".data"
+#define _BSS	".bss"
+#define _PAD	".pad"
+#define _LOADER	".loader"
+
+#define	SCNHDR	struct external_scnhdr
+#define	SCNHSZ	40
+
+/* XCOFF uses a special .loader section with type STYP_LOADER.  */
+#define STYP_LOADER 0x1000
+
+/* XCOFF uses a special .debug section with type STYP_DEBUG.  */
+#define STYP_DEBUG 0x2000
+
+/* XCOFF handles line number or relocation overflow by creating
+   another section header with STYP_OVRFLO set.  */
+#define STYP_OVRFLO 0x8000
+
+/********************** LINE NUMBERS **********************/
+
+/* 1 line number entry for every "breakpointable" source line in a section.
+ * Line numbers are grouped on a per function basis; first entry in a function
+ * grouping will have l_lnno = 0 and in place of physical address will be the
+ * symbol table index of the function name.
+ */
+struct external_lineno {
+	union {
+		char l_symndx[4];	/* function name symbol index, iff l_lnno == 0*/
+		char l_paddr[4];	/* (physical) address of line number	*/
+	} l_addr;
+	char l_lnno[2];	/* line number		*/
+};
+
+
+#define	LINENO	struct external_lineno
+#define	LINESZ	6
+
+
+/********************** SYMBOLS **********************/
+
+#define E_SYMNMLEN	8	/* # characters in a symbol name	*/
+#define E_FILNMLEN	14	/* # characters in a file name		*/
+#define E_DIMNUM	4	/* # array dimensions in auxiliary entry */
+
+struct external_syment 
+{
+  union {
+    char e_name[E_SYMNMLEN];
+    struct {
+      char e_zeroes[4];
+      char e_offset[4];
+    } e;
+  } e;
+  char e_value[4];
+  char e_scnum[2];
+  char e_type[2];
+  char e_sclass[1];
+  char e_numaux[1];
+};
+
+
+
+#define N_BTMASK	(017)
+#define N_TMASK		(060)
+#define N_BTSHFT	(4)
+#define N_TSHIFT	(2)
+  
+
+union external_auxent {
+	struct {
+		char x_tagndx[4];	/* str, un, or enum tag indx */
+		union {
+			struct {
+			    char  x_lnno[2]; /* declaration line number */
+			    char  x_size[2]; /* str/union/array size */
+			} x_lnsz;
+			char x_fsize[4];	/* size of function */
+		} x_misc;
+		union {
+			struct {		/* if ISFCN, tag, or .bb */
+			    char x_lnnoptr[4];	/* ptr to fcn line # */
+			    char x_endndx[4];	/* entry ndx past block end */
+			} x_fcn;
+			struct {		/* if ISARY, up to 4 dimen. */
+			    char x_dimen[E_DIMNUM][2];
+			} x_ary;
+		} x_fcnary;
+		char x_tvndx[2];		/* tv index */
+	} x_sym;
+
+	union {
+		char x_fname[E_FILNMLEN];
+		struct {
+			char x_zeroes[4];
+			char x_offset[4];
+		} x_n;
+	} x_file;
+
+	struct {
+		char x_scnlen[4];			/* section length */
+		char x_nreloc[2];	/* # relocation entries */
+		char x_nlinno[2];	/* # line numbers */
+	} x_scn;
+
+        struct {
+		char x_tvfill[4];	/* tv fill value */
+		char x_tvlen[2];	/* length of .tv */
+		char x_tvran[2][2];	/* tv range */
+	} x_tv;		/* info about .tv section (in auxent of symbol .tv)) */
+
+	struct {
+		unsigned char x_scnlen[4];
+		unsigned char x_parmhash[4];
+		unsigned char x_snhash[2];
+		unsigned char x_smtyp[1];
+		unsigned char x_smclas[1];
+		unsigned char x_stab[4];
+		unsigned char x_snstab[2];
+	} x_csect;
+
+};
+
+#define	SYMENT	struct external_syment
+#define	SYMESZ	18	
+#define	AUXENT	union external_auxent
+#define	AUXESZ	18
+#define DBXMASK 0x80		/* for dbx storage mask */
+#define SYMNAME_IN_DEBUG(symptr) ((symptr)->n_sclass & DBXMASK)
+
+
+
+/********************** RELOCATION DIRECTIVES **********************/
+
+
+struct external_reloc {
+  char r_vaddr[4];
+  char r_symndx[4];
+  char r_size[1];
+  char r_type[1];
+};
+
+
+#define RELOC struct external_reloc
+#define RELSZ 10
+
+#define DEFAULT_DATA_SECTION_ALIGNMENT 4
+#define DEFAULT_BSS_SECTION_ALIGNMENT 4
+#define DEFAULT_TEXT_SECTION_ALIGNMENT 4
+/* For new sections we havn't heard of before */
+#define DEFAULT_SECTION_ALIGNMENT 4
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/coffboot/start.c linux/arch/ppc/coffboot/start.c
--- v2.1.50/linux/arch/ppc/coffboot/start.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/coffboot/start.c	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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.
+ */
+#include <stdarg.h>
+
+int (*prom)();
+
+void *chosen_handle;
+void *stdin;
+void *stdout;
+void *stderr;
+
+void exit(void);
+void *finddevice(const char *name);
+int getprop(void *phandle, const char *name, void *buf, int buflen);
+
+void
+start(int a1, int a2, void *promptr)
+{
+    prom = (int (*)()) promptr;
+    chosen_handle = finddevice("/chosen");
+    if (chosen_handle == (void *) -1)
+	exit();
+    if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
+	exit();
+    stderr = stdout;
+    if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
+	exit();
+
+    coffboot(a1, a2, promptr);
+    for (;;)
+	exit();
+}
+
+int
+write(void *handle, void *ptr, int nb)
+{
+    struct prom_args {
+	char *service;
+	int nargs;
+	int nret;
+	void *ihandle;
+	void *addr;
+	int len;
+	int actual;
+    } args;
+
+    args.service = "write";
+    args.nargs = 3;
+    args.nret = 1;
+    args.ihandle = handle;
+    args.addr = ptr;
+    args.len = nb;
+    args.actual = -1;
+    (*prom)(&args);
+    return args.actual;
+}
+
+int
+read(void *handle, void *ptr, int nb)
+{
+    struct prom_args {
+	char *service;
+	int nargs;
+	int nret;
+	void *ihandle;
+	void *addr;
+	int len;
+	int actual;
+    } args;
+
+    args.service = "read";
+    args.nargs = 3;
+    args.nret = 1;
+    args.ihandle = handle;
+    args.addr = ptr;
+    args.len = nb;
+    args.actual = -1;
+    (*prom)(&args);
+    return args.actual;
+}
+
+void
+exit()
+{
+    struct prom_args {
+	char *service;
+    } args;
+
+    for (;;) {
+	args.service = "exit";
+	(*prom)(&args);
+    }
+}
+
+void
+pause()
+{
+    struct prom_args {
+	char *service;
+    } args;
+
+    args.service = "enter";
+    (*prom)(&args);
+}
+
+void *
+finddevice(const char *name)
+{
+    struct prom_args {
+	char *service;
+	int nargs;
+	int nret;
+	const char *devspec;
+	void *phandle;
+    } args;
+
+    args.service = "finddevice";
+    args.nargs = 1;
+    args.nret = 1;
+    args.devspec = name;
+    args.phandle = (void *) -1;
+    (*prom)(&args);
+    return args.phandle;
+}
+
+int
+getprop(void *phandle, const char *name, void *buf, int buflen)
+{
+    struct prom_args {
+	char *service;
+	int nargs;
+	int nret;
+	void *phandle;
+	const char *name;
+	void *buf;
+	int buflen;
+	int size;
+    } args;
+
+    args.service = "getprop";
+    args.nargs = 4;
+    args.nret = 1;
+    args.phandle = phandle;
+    args.name = name;
+    args.buf = buf;
+    args.buflen = buflen;
+    args.size = -1;
+    (*prom)(&args);
+    return args.size;
+}
+
+int
+putc(int c, void *f)
+{
+    char ch = c;
+
+    if (c == '\n')
+	putc('\r', f);
+    return write(f, &ch, 1) == 1? c: -1;
+}
+
+int
+putchar(int c)
+{
+    return putc(c, stdout);
+}
+
+int
+fputs(char *str, void *f)
+{
+    int n = strlen(str);
+
+    return write(f, str, n) == n? 0: -1;
+}
+
+int
+readchar()
+{
+    char ch;
+
+    for (;;) {
+	switch (read(stdin, &ch, 1)) {
+	case 1:
+	    return ch;
+	case -1:
+	    printk("read(stdin) returned -1\r\n");
+	    return -1;
+	}
+    }
+}
+
+static char line[256];
+static char *lineptr;
+static int lineleft;
+
+int
+getchar()
+{
+    int c;
+
+    if (lineleft == 0) {
+	lineptr = line;
+	for (;;) {
+	    c = readchar();
+	    if (c == -1 || c == 4)
+		break;
+	    if (c == '\r' || c == '\n') {
+		*lineptr++ = '\n';
+		putchar('\n');
+		break;
+	    }
+	    switch (c) {
+	    case 0177:
+	    case '\b':
+		if (lineptr > line) {
+		    putchar('\b');
+		    putchar(' ');
+		    putchar('\b');
+		    --lineptr;
+		}
+		break;
+	    case 'U' & 0x1F:
+		while (lineptr > line) {
+		    putchar('\b');
+		    putchar(' ');
+		    putchar('\b');
+		    --lineptr;
+		}
+		break;
+	    default:
+		if (lineptr >= &line[sizeof(line) - 1])
+		    putchar('\a');
+		else {
+		    putchar(c);
+		    *lineptr++ = c;
+		}
+	    }
+	}
+	lineleft = lineptr - line;
+	lineptr = line;
+    }
+    if (lineleft == 0)
+	return -1;
+    --lineleft;
+    return *lineptr++;
+}
+
+extern int vsprintf(char *buf, const char *fmt, va_list args);
+static char sprint_buf[1024];
+
+void
+printk(char *fmt, ...)
+{
+	va_list args;
+	int n;
+
+	va_start(args, fmt);
+	n = vsprintf(sprint_buf, fmt, args);
+	va_end(args);
+	write(stdout, sprint_buf, n);
+}
+
+int
+printf(char *fmt, ...)
+{
+	va_list args;
+	int n;
+
+	va_start(args, fmt);
+	n = vsprintf(sprint_buf, fmt, args);
+	va_end(args);
+	write(stdout, sprint_buf, n);
+	return n;
+}
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/coffboot/string.S linux/arch/ppc/coffboot/string.S
--- v2.1.50/linux/arch/ppc/coffboot/string.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/coffboot/string.S	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,206 @@
+/*
+ * String handling functions for PowerPC.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#define r0	0
+#define r3	3
+#define r4	4
+#define r5	5
+#define r6	6
+#define r7	7
+#define r8	8
+
+	.globl	strcpy
+strcpy:
+	addi	r5,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	stbu	r0,1(r5)
+	bne	1b
+	blr
+
+	.globl	strncpy
+strncpy:
+	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+	addi	r6,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	stbu	r0,1(r6)
+	bdnzf	2,1b		/* dec ctr, branch if ctr != 0 && !cr0.eq */
+	blr
+
+	.globl	strcat
+strcat:
+	addi	r5,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r0,1(r5)
+	cmpwi	0,r0,0
+	bne	1b
+	addi	r5,r5,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	stbu	r0,1(r5)
+	bne	1b
+	blr
+
+	.globl	strcmp
+strcmp:
+	addi	r5,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r3,1(r5)
+	cmpwi	1,r3,0
+	lbzu	r0,1(r4)
+	subf.	r3,r0,r3
+	beqlr	1
+	beq	1b
+	blr
+
+	.globl	strlen
+strlen:
+	addi	r4,r3,-1
+1:	lbzu	r0,1(r4)
+	cmpwi	0,r0,0
+	bne	1b
+	subf	r3,r3,r4
+	blr
+
+	.globl	memset
+memset:
+	rlwimi	r4,r4,8,16,23
+	rlwimi	r4,r4,16,0,15
+	addi	r6,r3,-4
+	cmplwi	0,r5,4
+	blt	7f
+	stwu	r4,4(r6)
+	beqlr
+	andi.	r0,r6,3
+	add	r5,r0,r5
+	subf	r6,r0,r6
+	rlwinm	r0,r5,32-2,2,31
+	mtctr	r0
+	bdz	6f
+1:	stwu	r4,4(r6)
+	bdnz	1b
+6:	andi.	r5,r5,3
+7:	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+	addi	r6,r6,3
+8:	stbu	r4,1(r6)
+	bdnz	8b
+	blr
+
+	.globl	bcopy
+bcopy:
+	mr	r6,r3
+	mr	r3,r4
+	mr	r4,r6
+	b	memcpy
+
+	.globl	memmove
+memmove:
+	cmplw	0,r3,r4
+	bgt	backwards_memcpy
+	/* fall through */
+
+	.globl	memcpy
+memcpy:
+	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */
+	addi	r6,r3,-4
+	addi	r4,r4,-4
+	beq	2f			/* if less than 8 bytes to do */
+	andi.	r0,r6,3			/* get dest word aligned */
+	mtctr	r7
+	bne	5f
+1:	lwz	r7,4(r4)
+	lwzu	r8,8(r4)
+	stw	r7,4(r6)
+	stwu	r8,8(r6)
+	bdnz	1b
+	andi.	r5,r5,7
+2:	cmplwi	0,r5,4
+	blt	3f
+	lwzu	r0,4(r4)
+	addi	r5,r5,-4
+	stwu	r0,4(r6)
+3:	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+	addi	r4,r4,3
+	addi	r6,r6,3
+4:	lbzu	r0,1(r4)
+	stbu	r0,1(r6)
+	bdnz	4b
+	blr
+5:	subfic	r0,r0,4
+	mtctr	r0
+6:	lbz	r7,4(r4)
+	addi	r4,r4,1
+	stb	r7,4(r6)
+	addi	r6,r6,1
+	bdnz	6b
+	subf	r5,r0,r5
+	rlwinm.	r7,r5,32-3,3,31
+	beq	2b
+	mtctr	r7
+	b	1b
+
+	.globl	backwards_memcpy
+backwards_memcpy:
+	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */
+	add	r6,r3,r5
+	add	r4,r4,r5
+	beq	2f
+	andi.	r0,r6,3
+	mtctr	r7
+	bne	5f
+1:	lwz	r7,-4(r4)
+	lwzu	r8,-8(r4)
+	stw	r7,-4(r6)
+	stwu	r8,-8(r6)
+	bdnz	1b
+	andi.	r5,r5,7
+2:	cmplwi	0,r5,4
+	blt	3f
+	lwzu	r0,-4(r4)
+	subi	r5,r5,4
+	stwu	r0,-4(r6)
+3:	cmpwi	0,r5,0
+	beqlr
+	mtctr	r5
+4:	lbzu	r0,-1(r4)
+	stbu	r0,-1(r6)
+	bdnz	4b
+	blr
+5:	mtctr	r0
+6:	lbzu	r7,-1(r4)
+	stbu	r7,-1(r6)
+	bdnz	6b
+	subf	r5,r0,r5
+	rlwinm.	r7,r5,32-3,3,31
+	beq	2b
+	mtctr	r7
+	b	1b
+
+	.globl	memcmp
+memcmp:
+	cmpwi	0,r5,0
+	blelr
+	mtctr	r5
+	addi	r6,r3,-1
+	addi	r4,r4,-1
+1:	lbzu	r3,1(r6)
+	lbzu	r0,1(r4)
+	subf.	r3,r0,r3
+	bdnzt	2,1b
+	blr
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/coffboot/zlib.c linux/arch/ppc/coffboot/zlib.c
--- v2.1.50/linux/arch/ppc/coffboot/zlib.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/coffboot/zlib.c	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,2143 @@
+/*
+ * This file is derived from various .h and .c files from the zlib-0.95
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets.  See zlib.h for conditions of
+ * distribution and use.
+ *
+ * Changes that have been made include:
+ * - changed functions not used outside this file to "local"
+ * - added minCompression parameter to deflateInit2
+ * - added Z_PACKET_FLUSH (see zlib.h for details)
+ * - added inflateIncomp
+ *
+ * $Id: zlib.c,v 1.1 1997/07/31 07:16:14 paulus Exp $
+ */
+
+/*+++++*/
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* From: zutil.h,v 1.9 1995/05/03 17:27:12 jloup Exp */
+
+#define _Z_UTIL_H
+
+#include "zlib.h"
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+#define FAR
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+extern char *z_errmsg[]; /* indexed by 1-zlib_error */
+
+#define ERR_RETURN(strm,err) return (strm->msg=z_errmsg[1-err], err)
+/* To be used only when the state is known to be valid */
+
+#ifndef NULL
+#define NULL	((void *) 0)
+#endif
+
+        /* common constants */
+
+#define DEFLATED   8
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+         /* functions */
+
+#include <string.h>
+#define zmemcpy memcpy
+#define zmemzero(dest, len)	memset(dest, 0, len)
+
+/* Diagnostic functions */
+#ifdef DEBUG_ZLIB
+#  include <stdio.h>
+#  ifndef verbose
+#    define verbose 0
+#  endif
+#  define Assert(cond,msg) {if(!(cond)) z_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
+
+
+typedef uLong (*check_func) OF((uLong check, Bytef *buf, uInt len));
+
+/* voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); */
+/* void   zcfree  OF((voidpf opaque, voidpf ptr)); */
+
+#define ZALLOC(strm, items, size) \
+           (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr, size)	\
+	   (*((strm)->zfree))((strm)->opaque, (voidpf)(addr), (size))
+#define TRY_FREE(s, p, n) {if (p) ZFREE(s, p, n);}
+
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/*+++++*/
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+local inflate_blocks_statef * inflate_blocks_new OF((
+    z_stream *z,
+    check_func c,               /* check function */
+    uInt w));                   /* window size */
+
+local int inflate_blocks OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    int));                      /* initial return code */
+
+local void inflate_blocks_reset OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    uLongf *));                  /* check value on output */
+
+local int inflate_blocks_free OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    uLongf *));                  /* check value on output */
+
+local int inflate_addhistory OF((
+    inflate_blocks_statef *,
+    z_stream *));
+
+local int inflate_packet_flush OF((
+    inflate_blocks_statef *));
+
+/*+++++*/
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+   that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+  union {
+    struct {
+      Byte Exop;        /* number of extra bits or operation */
+      Byte Bits;        /* number of bits in this code or subcode */
+    } what;
+    uInt Nalloc;	/* number of these allocated here */
+    Bytef *pad;         /* pad structure to a power of 2 (4 bytes for */
+  } word;               /*  16-bit, 8 bytes for 32-bit machines) */
+  union {
+    uInt Base;          /* literal, length base, or distance base */
+    inflate_huft *Next; /* pointer to next level of table */
+  } more;
+};
+
+#ifdef DEBUG_ZLIB
+  local uInt inflate_hufts;
+#endif
+
+local int inflate_trees_bits OF((
+    uIntf *,                    /* 19 code lengths */
+    uIntf *,                    /* bits tree desired/actual depth */
+    inflate_huft * FAR *,       /* bits tree result */
+    z_stream *));               /* for zalloc, zfree functions */
+
+local int inflate_trees_dynamic OF((
+    uInt,                       /* number of literal/length codes */
+    uInt,                       /* number of distance codes */
+    uIntf *,                    /* that many (total) code lengths */
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *,       /* distance tree result */
+    z_stream *));               /* for zalloc, zfree functions */
+
+local int inflate_trees_fixed OF((
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *));     /* distance tree result */
+
+local int inflate_trees_free OF((
+    inflate_huft *,             /* tables to free */
+    z_stream *));               /* for zfree function */
+
+
+/*+++++*/
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+local inflate_codes_statef *inflate_codes_new OF((
+    uInt, uInt,
+    inflate_huft *, inflate_huft *,
+    z_stream *));
+
+local int inflate_codes OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    int));
+
+local void inflate_codes_free OF((
+    inflate_codes_statef *,
+    z_stream *));
+
+
+/*+++++*/
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* inflate private state */
+struct internal_state {
+
+  /* mode */
+  enum {
+      METHOD,   /* waiting for method byte */
+      FLAG,     /* waiting for flag byte */
+      BLOCKS,   /* decompressing blocks */
+      CHECK4,   /* four check bytes to go */
+      CHECK3,   /* three check bytes to go */
+      CHECK2,   /* two check bytes to go */
+      CHECK1,   /* one check byte to go */
+      DONE,     /* finished check, done */
+      BAD}      /* got an error--stay here */
+    mode;               /* current inflate mode */
+
+  /* mode dependent information */
+  union {
+    uInt method;        /* if FLAGS, method byte */
+    struct {
+      uLong was;                /* computed check value */
+      uLong need;               /* stream check value */
+    } check;            /* if CHECK, check values to compare */
+    uInt marker;        /* if BAD, inflateSync's marker bytes count */
+  } sub;        /* submode */
+
+  /* mode independent information */
+  int  nowrap;          /* flag for no wrapper */
+  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
+  inflate_blocks_statef 
+    *blocks;            /* current inflate_blocks state */
+
+};
+
+
+int inflateReset(z)
+z_stream *z;
+{
+  uLong c;
+
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->total_in = z->total_out = 0;
+  z->msg = Z_NULL;
+  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+  inflate_blocks_reset(z->state->blocks, z, &c);
+  Trace((stderr, "inflate: reset\n"));
+  return Z_OK;
+}
+
+
+int inflateEnd(z)
+z_stream *z;
+{
+  uLong c;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->blocks != Z_NULL)
+    inflate_blocks_free(z->state->blocks, z, &c);
+  ZFREE(z, z->state, sizeof(struct internal_state));
+  z->state = Z_NULL;
+  Trace((stderr, "inflate: end\n"));
+  return Z_OK;
+}
+
+
+int inflateInit2(z, w)
+z_stream *z;
+int w;
+{
+  /* initialize state */
+  if (z == Z_NULL)
+    return Z_STREAM_ERROR;
+/*  if (z->zalloc == Z_NULL) z->zalloc = zcalloc; */
+/*  if (z->zfree == Z_NULL) z->zfree = zcfree; */
+  if ((z->state = (struct internal_state FAR *)
+       ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+    return Z_MEM_ERROR;
+  z->state->blocks = Z_NULL;
+
+  /* handle undocumented nowrap option (no zlib header or check) */
+  z->state->nowrap = 0;
+  if (w < 0)
+  {
+    w = - w;
+    z->state->nowrap = 1;
+  }
+
+  /* set window size */
+  if (w < 8 || w > 15)
+  {
+    inflateEnd(z);
+    return Z_STREAM_ERROR;
+  }
+  z->state->wbits = (uInt)w;
+
+  /* create inflate_blocks state */
+  if ((z->state->blocks =
+       inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, 1 << w))
+      == Z_NULL)
+  {
+    inflateEnd(z);
+    return Z_MEM_ERROR;
+  }
+  Trace((stderr, "inflate: allocated\n"));
+
+  /* reset state */
+  inflateReset(z);
+  return Z_OK;
+}
+
+
+int inflateInit(z)
+z_stream *z;
+{
+  return inflateInit2(z, DEF_WBITS);
+}
+
+
+#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int inflate(z, f)
+z_stream *z;
+int f;
+{
+  int r;
+  uInt b;
+
+  if (z == Z_NULL || z->next_in == Z_NULL)
+    return Z_STREAM_ERROR;
+  r = Z_BUF_ERROR;
+  while (1) switch (z->state->mode)
+  {
+    case METHOD:
+      NEEDBYTE
+      if (((z->state->sub.method = NEXTBYTE) & 0xf) != DEFLATED)
+      {
+        z->state->mode = BAD;
+        z->msg = "unknown compression method";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+      {
+        z->state->mode = BAD;
+        z->msg = "invalid window size";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      z->state->mode = FLAG;
+    case FLAG:
+      NEEDBYTE
+      if ((b = NEXTBYTE) & 0x20)
+      {
+        z->state->mode = BAD;
+        z->msg = "invalid reserved bit";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if (((z->state->sub.method << 8) + b) % 31)
+      {
+        z->state->mode = BAD;
+        z->msg = "incorrect header check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Trace((stderr, "inflate: zlib header ok\n"));
+      z->state->mode = BLOCKS;
+    case BLOCKS:
+      r = inflate_blocks(z->state->blocks, z, r);
+      if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
+	  r = inflate_packet_flush(z->state->blocks);
+      if (r == Z_DATA_ERROR)
+      {
+        z->state->mode = BAD;
+        z->state->sub.marker = 0;       /* can try inflateSync */
+        break;
+      }
+      if (r != Z_STREAM_END)
+        return r;
+      r = Z_OK;
+      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+      if (z->state->nowrap)
+      {
+        z->state->mode = DONE;
+        break;
+      }
+      z->state->mode = CHECK4;
+    case CHECK4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = CHECK3;
+    case CHECK3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = CHECK2;
+    case CHECK2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = CHECK1;
+    case CHECK1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+
+      if (z->state->sub.check.was != z->state->sub.check.need)
+      {
+        z->state->mode = BAD;
+        z->msg = "incorrect data check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Trace((stderr, "inflate: zlib check ok\n"));
+      z->state->mode = DONE;
+    case DONE:
+      return Z_STREAM_END;
+    case BAD:
+      return Z_DATA_ERROR;
+    default:
+      return Z_STREAM_ERROR;
+  }
+
+ empty:
+  if (f != Z_PACKET_FLUSH)
+    return r;
+  z->state->mode = BAD;
+  z->state->sub.marker = 0;       /* can try inflateSync */
+  return Z_DATA_ERROR;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS).  On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+
+int inflateIncomp(z)
+z_stream *z;
+{
+    if (z->state->mode != BLOCKS)
+	return Z_DATA_ERROR;
+    return inflate_addhistory(z->state->blocks, z);
+}
+
+
+int inflateSync(z)
+z_stream *z;
+{
+  uInt n;       /* number of bytes to look at */
+  Bytef *p;     /* pointer to bytes */
+  uInt m;       /* number of marker bytes found in a row */
+  uLong r, w;   /* temporaries to save total_in and total_out */
+
+  /* set up */
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->mode != BAD)
+  {
+    z->state->mode = BAD;
+    z->state->sub.marker = 0;
+  }
+  if ((n = z->avail_in) == 0)
+    return Z_BUF_ERROR;
+  p = z->next_in;
+  m = z->state->sub.marker;
+
+  /* search */
+  while (n && m < 4)
+  {
+    if (*p == (Byte)(m < 2 ? 0 : 0xff))
+      m++;
+    else if (*p)
+      m = 0;
+    else
+      m = 4 - m;
+    p++, n--;
+  }
+
+  /* restore */
+  z->total_in += p - z->next_in;
+  z->next_in = p;
+  z->avail_in = n;
+  z->state->sub.marker = m;
+
+  /* return no joy or set up to restart on a new block */
+  if (m != 4)
+    return Z_DATA_ERROR;
+  r = z->total_in;  w = z->total_out;
+  inflateReset(z);
+  z->total_in = r;  z->total_out = w;
+  z->state->mode = BLOCKS;
+  return Z_OK;
+}
+
+#undef NEEDBYTE
+#undef NEXTBYTE
+
+/*+++++*/
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+  /* mode */
+  enum {
+      TYPE,     /* get type bits (3, including end bit) */
+      LENS,     /* get lengths for stored */
+      STORED,   /* processing stored block */
+      TABLE,    /* get table lengths */
+      BTREE,    /* get bit lengths tree for a dynamic block */
+      DTREE,    /* get length, distance trees for a dynamic block */
+      CODES,    /* processing fixed or dynamic block */
+      DRY,      /* output remaining window bytes */
+      DONEB,     /* finished last block, done */
+      BADB}      /* got a data error--stuck here */
+    mode;               /* current inflate_block mode */
+
+  /* mode dependent information */
+  union {
+    uInt left;          /* if STORED, bytes left to copy */
+    struct {
+      uInt table;               /* table lengths (14 bits) */
+      uInt index;               /* index into blens (or border) */
+      uIntf *blens;             /* bit lengths of codes */
+      uInt bb;                  /* bit length tree depth */
+      inflate_huft *tb;         /* bit length decoding tree */
+      int nblens;		/* # elements allocated at blens */
+    } trees;            /* if DTREE, decoding info for trees */
+    struct {
+      inflate_huft *tl, *td;    /* trees to free */
+      inflate_codes_statef 
+         *codes;
+    } decode;           /* if CODES, current state */
+  } sub;                /* submode */
+  uInt last;            /* true if this block is the last block */
+
+  /* mode independent information */
+  uInt bitk;            /* bits in bit buffer */
+  uLong bitb;           /* bit buffer */
+  Bytef *window;        /* sliding window */
+  Bytef *end;           /* one byte after sliding window */
+  Bytef *read;          /* window read pointer */
+  Bytef *write;         /* window write pointer */
+  check_func checkfn;   /* check function */
+  uLong check;          /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/*   update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/*   get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/*   output bytes */
+#define WAVAIL (q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/*   load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/* And'ing with mask[n] masks the lower n bits */
+local uInt inflate_mask[] = {
+    0x0000,
+    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+/* copy as much as possible from the sliding window to the output area */
+local int inflate_flush OF((
+    inflate_blocks_statef *,
+    z_stream *,
+    int));
+
+/*+++++*/
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+local int inflate_fast OF((
+    uInt,
+    uInt,
+    inflate_huft *,
+    inflate_huft *,
+    inflate_blocks_statef *,
+    z_stream *));
+
+
+/*+++++*/
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local uInt 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};
+
+/*
+   Notes beyond the 1.93a appnote.txt:
+
+   1. Distance pointers never point before the beginning of the output
+      stream.
+   2. Distance pointers can point back across blocks, up to 32k away.
+   3. There is an implied maximum of 7 bits for the bit length table and
+      15 bits for the actual data.
+   4. If only one code exists, then it is encoded using one bit.  (Zero
+      would be more efficient, but perhaps a little confusing.)  If two
+      codes exist, they are coded using one bit each (0 and 1).
+   5. There is no way of sending zero distance codes--a dummy must be
+      sent if there are none.  (History: a pre 2.0 version of PKZIP would
+      store blocks with no distance codes, but this was discovered to be
+      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
+      zero distance codes, which is sent as one code of zero bits in
+      length.
+   6. There are up to 286 literal/length codes.  Code 256 represents the
+      end-of-block.  Note however that the static length tree defines
+      288 codes just to fill out the Huffman codes.  Codes 286 and 287
+      cannot be used though, since there is no length base or extra bits
+      defined for them.  Similarily, there are up to 30 distance codes.
+      However, static trees define 32 codes (all 5 bits) to fill out the
+      Huffman codes, but the last two had better not show up in the data.
+   7. Unzip can check dynamic Huffman blocks for complete code sets.
+      The exception is that a single code would not be complete (see #4).
+   8. The five bits following the block type is really the number of
+      literal codes sent minus 257.
+   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+      (1+6+6).  Therefore, to output three times the length, you output
+      three codes (1+1+1), whereas to output four times the same length,
+      you only need two codes (1+3).  Hmm.
+  10. In the tree reconstruction algorithm, Code = Code + Increment
+      only if BitLength(i) is not zero.  (Pretty obvious.)
+  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
+  12. Note: length code 284 can represent 227-258, but length code 285
+      really is 258.  The last length deserves its own, short code
+      since it gets used a lot in very redundant files.  The length
+      258 is special since 258 - 3 (the min match length) is 255.
+  13. The literal/length and distance code bit lengths are read as a
+      single stream of lengths.  It is possible (and advantageous) for
+      a repeat code (16, 17, or 18) to go across the boundary between
+      the two sets of lengths.
+ */
+
+
+local void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_stream *z;
+uLongf *c;
+{
+  if (s->checkfn != Z_NULL)
+    *c = s->check;
+  if (s->mode == BTREE || s->mode == DTREE)
+    ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt));
+  if (s->mode == CODES)
+  {
+    inflate_codes_free(s->sub.decode.codes, z);
+    inflate_trees_free(s->sub.decode.td, z);
+    inflate_trees_free(s->sub.decode.tl, z);
+  }
+  s->mode = TYPE;
+  s->bitk = 0;
+  s->bitb = 0;
+  s->read = s->write = s->window;
+  if (s->checkfn != Z_NULL)
+    s->check = (*s->checkfn)(0L, Z_NULL, 0);
+  Trace((stderr, "inflate:   blocks reset\n"));
+}
+
+
+local inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_stream *z;
+check_func c;
+uInt w;
+{
+  inflate_blocks_statef *s;
+
+  if ((s = (inflate_blocks_statef *)ZALLOC
+       (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
+    return s;
+  if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+  {
+    ZFREE(z, s, sizeof(struct inflate_blocks_state));
+    return Z_NULL;
+  }
+  s->end = s->window + w;
+  s->checkfn = c;
+  s->mode = TYPE;
+  Trace((stderr, "inflate:   blocks allocated\n"));
+  inflate_blocks_reset(s, z, &s->check);
+  return s;
+}
+
+
+local int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+  uInt t;               /* temporary storage */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input based on current state */
+  while (1) switch (s->mode)
+  {
+    case TYPE:
+      NEEDBITS(3)
+      t = (uInt)b & 7;
+      s->last = t & 1;
+      switch (t >> 1)
+      {
+        case 0:                         /* stored */
+          Trace((stderr, "inflate:     stored block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          t = k & 7;                    /* go to byte boundary */
+          DUMPBITS(t)
+          s->mode = LENS;               /* get length of stored block */
+          break;
+        case 1:                         /* fixed */
+          Trace((stderr, "inflate:     fixed codes block%s\n",
+                 s->last ? " (last)" : ""));
+          {
+            uInt bl, bd;
+            inflate_huft *tl, *td;
+
+            inflate_trees_fixed(&bl, &bd, &tl, &td);
+            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+            if (s->sub.decode.codes == Z_NULL)
+            {
+              r = Z_MEM_ERROR;
+              LEAVE
+            }
+            s->sub.decode.tl = Z_NULL;  /* don't try to free these */
+            s->sub.decode.td = Z_NULL;
+          }
+          DUMPBITS(3)
+          s->mode = CODES;
+          break;
+        case 2:                         /* dynamic */
+          Trace((stderr, "inflate:     dynamic codes block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          s->mode = TABLE;
+          break;
+        case 3:                         /* illegal */
+          DUMPBITS(3)
+          s->mode = BADB;
+          z->msg = "invalid block type";
+          r = Z_DATA_ERROR;
+          LEAVE
+      }
+      break;
+    case LENS:
+      NEEDBITS(32)
+      if (((~b) >> 16) != (b & 0xffff))
+      {
+        s->mode = BADB;
+        z->msg = "invalid stored block lengths";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+      s->sub.left = (uInt)b & 0xffff;
+      b = k = 0;                      /* dump bits */
+      Tracev((stderr, "inflate:       stored length %u\n", s->sub.left));
+      s->mode = s->sub.left ? STORED : TYPE;
+      break;
+    case STORED:
+      if (n == 0)
+        LEAVE
+      NEEDOUT
+      t = s->sub.left;
+      if (t > n) t = n;
+      if (t > m) t = m;
+      zmemcpy(q, p, t);
+      p += t;  n -= t;
+      q += t;  m -= t;
+      if ((s->sub.left -= t) != 0)
+        break;
+      Tracev((stderr, "inflate:       stored end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      s->mode = s->last ? DRY : TYPE;
+      break;
+    case TABLE:
+      NEEDBITS(14)
+      s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+      {
+        s->mode = BADB;
+        z->msg = "too many length or distance symbols";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+#endif
+      t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+      if (t < 19)
+        t = 19;
+      if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+      {
+        r = Z_MEM_ERROR;
+        LEAVE
+      }
+      s->sub.trees.nblens = t;
+      DUMPBITS(14)
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       table sizes ok\n"));
+      s->mode = BTREE;
+    case BTREE:
+      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+      {
+        NEEDBITS(3)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+        DUMPBITS(3)
+      }
+      while (s->sub.trees.index < 19)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+      s->sub.trees.bb = 7;
+      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+                             &s->sub.trees.tb, z);
+      if (t != Z_OK)
+      {
+        r = t;
+        if (r == Z_DATA_ERROR)
+          s->mode = BADB;
+        LEAVE
+      }
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       bits tree ok\n"));
+      s->mode = DTREE;
+    case DTREE:
+      while (t = s->sub.trees.table,
+             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+      {
+        inflate_huft *h;
+        uInt i, j, c;
+
+        t = s->sub.trees.bb;
+        NEEDBITS(t)
+        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+        t = h->word.what.Bits;
+        c = h->more.Base;
+        if (c < 16)
+        {
+          DUMPBITS(t)
+          s->sub.trees.blens[s->sub.trees.index++] = c;
+        }
+        else /* c == 16..18 */
+        {
+          i = c == 18 ? 7 : c - 14;
+          j = c == 18 ? 11 : 3;
+          NEEDBITS(t + i)
+          DUMPBITS(t)
+          j += (uInt)b & inflate_mask[i];
+          DUMPBITS(i)
+          i = s->sub.trees.index;
+          t = s->sub.trees.table;
+          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+              (c == 16 && i < 1))
+          {
+            s->mode = BADB;
+            z->msg = "invalid bit length repeat";
+            r = Z_DATA_ERROR;
+            LEAVE
+          }
+          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+          do {
+            s->sub.trees.blens[i++] = c;
+          } while (--j);
+          s->sub.trees.index = i;
+        }
+      }
+      inflate_trees_free(s->sub.trees.tb, z);
+      s->sub.trees.tb = Z_NULL;
+      {
+        uInt bl, bd;
+        inflate_huft *tl, *td;
+        inflate_codes_statef *c;
+
+        bl = 9;         /* must be <= 9 for lookahead assumptions */
+        bd = 6;         /* must be <= 9 for lookahead assumptions */
+        t = s->sub.trees.table;
+        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+                                  s->sub.trees.blens, &bl, &bd, &tl, &td, z);
+        if (t != Z_OK)
+        {
+          if (t == (uInt)Z_DATA_ERROR)
+            s->mode = BADB;
+          r = t;
+          LEAVE
+        }
+        Tracev((stderr, "inflate:       trees ok\n"));
+        if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+        {
+          inflate_trees_free(td, z);
+          inflate_trees_free(tl, z);
+          r = Z_MEM_ERROR;
+          LEAVE
+        }
+        ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt));
+        s->sub.decode.codes = c;
+        s->sub.decode.tl = tl;
+        s->sub.decode.td = td;
+      }
+      s->mode = CODES;
+    case CODES:
+      UPDATE
+      if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+        return inflate_flush(s, z, r);
+      r = Z_OK;
+      inflate_codes_free(s->sub.decode.codes, z);
+      inflate_trees_free(s->sub.decode.td, z);
+      inflate_trees_free(s->sub.decode.tl, z);
+      LOAD
+      Tracev((stderr, "inflate:       codes end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      if (!s->last)
+      {
+        s->mode = TYPE;
+        break;
+      }
+      if (k > 7)              /* return unused byte, if any */
+      {
+        Assert(k < 16, "inflate_codes grabbed too many bytes")
+        k -= 8;
+        n++;
+        p--;                    /* can always return one */
+      }
+      s->mode = DRY;
+    case DRY:
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      s->mode = DONEB;
+    case DONEB:
+      r = Z_STREAM_END;
+      LEAVE
+    case BADB:
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+}
+
+
+local int inflate_blocks_free(s, z, c)
+inflate_blocks_statef *s;
+z_stream *z;
+uLongf *c;
+{
+  inflate_blocks_reset(s, z, c);
+  ZFREE(z, s->window, s->end - s->window);
+  ZFREE(z, s, sizeof(struct inflate_blocks_state));
+  Trace((stderr, "inflate:   blocks freed\n"));
+  return Z_OK;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS).  On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+local int inflate_addhistory(s, z)
+inflate_blocks_statef *s;
+z_stream *z;
+{
+    uLong b;              /* bit buffer */  /* NOT USED HERE */
+    uInt k;               /* bits in bit buffer */ /* NOT USED HERE */
+    uInt t;               /* temporary storage */
+    Bytef *p;             /* input data pointer */
+    uInt n;               /* bytes available there */
+    Bytef *q;             /* output window write pointer */
+    uInt m;               /* bytes to end of window or read pointer */
+
+    if (s->read != s->write)
+	return Z_STREAM_ERROR;
+    if (s->mode != TYPE)
+	return Z_DATA_ERROR;
+
+    /* we're ready to rock */
+    LOAD
+    /* while there is input ready, copy to output buffer, moving
+     * pointers as needed.
+     */
+    while (n) {
+	t = n;  /* how many to do */
+	/* is there room until end of buffer? */
+	if (t > m) t = m;
+	/* update check information */
+	if (s->checkfn != Z_NULL)
+	    s->check = (*s->checkfn)(s->check, q, t);
+	zmemcpy(q, p, t);
+	q += t;
+	p += t;
+	n -= t;
+	z->total_out += t;
+	s->read = q;    /* drag read pointer forward */
+/*      WRAP  */ 	/* expand WRAP macro by hand to handle s->read */
+	if (q == s->end) {
+	    s->read = q = s->window;
+	    m = WAVAIL;
+	}
+    }
+    UPDATE
+    return Z_OK;
+}
+
+
+/*
+ * At the end of a Deflate-compressed PPP packet, we expect to have seen
+ * a `stored' block type value but not the (zero) length bytes.
+ */
+local int inflate_packet_flush(s)
+    inflate_blocks_statef *s;
+{
+    if (s->mode != LENS)
+	return Z_DATA_ERROR;
+    s->mode = TYPE;
+    return Z_OK;
+}
+
+
+/*+++++*/
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+    uIntf *,            /* code lengths in bits */
+    uInt,               /* number of codes */
+    uInt,               /* number of "simple" codes */
+    uIntf *,            /* list of base values for non-simple codes */
+    uIntf *,            /* list of extra bits for non-simple codes */
+    inflate_huft * FAR*,/* result: starting table */
+    uIntf *,            /* maximum lookup bits (returns actual) */
+    z_stream *));       /* for zalloc function */
+
+local voidpf falloc OF((
+    voidpf,             /* opaque pointer (not used) */
+    uInt,               /* number of items */
+    uInt));             /* size of item */
+
+local void ffree OF((
+    voidpf q,           /* opaque pointer (not used) */
+    voidpf p,           /* what to free (not used) */
+    uInt n));		/* number of bytes (not used) */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local uInt 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};
+        /* actually lengths - 2; also see note #13 above about 258 */
+local uInt 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, 192, 192}; /* 192==invalid */
+local uInt 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};
+local uInt 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};
+
+/*
+   Huffman code decoding is performed using a multi-level table lookup.
+   The fastest way to decode is to simply build a lookup table whose
+   size is determined by the longest code.  However, the time it takes
+   to build this table can also be a factor if the data being decoded
+   is not very long.  The most common codes are necessarily the
+   shortest codes, so those codes dominate the decoding time, and hence
+   the speed.  The idea is you can have a shorter table that decodes the
+   shorter, more probable codes, and then point to subsidiary tables for
+   the longer codes.  The time it costs to decode the longer codes is
+   then traded against the time it takes to make longer tables.
+
+   This results of this trade are in the variables lbits and dbits
+   below.  lbits is the number of bits the first level table for literal/
+   length codes can decode in one step, and dbits is the same thing for
+   the distance codes.  Subsequent tables are also less than or equal to
+   those sizes.  These values may be adjusted either when all of the
+   codes are shorter than that, in which case the longest code length in
+   bits is used, or when the shortest code is *longer* than the requested
+   table size, in which case the length of the shortest code in bits is
+   used.
+
+   There are two different values for the two tables, since they code a
+   different number of possibilities each.  The literal/length table
+   codes 286 possible values, or in a flat code, a little over eight
+   bits.  The distance table codes 30 possible values, or a little less
+   than five bits, flat.  The optimum values for speed end up being
+   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+   The optimum values may differ though from machine to machine, and
+   possibly even between compilers.  Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15         /* maximum bit length of any code */
+#define N_MAX 288       /* maximum number of codes in any set */
+
+#ifdef DEBUG_ZLIB
+  uInt inflate_hufts;
+#endif
+
+local int huft_build(b, n, s, d, e, t, m, zs)
+uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
+uInt n;                 /* number of codes (assumed <= N_MAX) */
+uInt s;                 /* number of simple-valued codes (0..s-1) */
+uIntf *d;               /* list of base values for non-simple codes */
+uIntf *e;               /* list of extra bits for non-simple codes */  
+inflate_huft * FAR *t;  /* result: starting table */
+uIntf *m;               /* maximum lookup bits, returns actual */
+z_stream *zs;           /* for zalloc function */
+/* Given a list of code lengths and a maximum table size, make a set of
+   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
+   if the given code set is incomplete (the tables are still built in this
+   case), Z_DATA_ERROR if the input is invalid (all zero length codes or an
+   over-subscribed set of lengths), or Z_MEM_ERROR if not enough memory. */
+{
+
+  uInt a;                       /* counter for codes of length k */
+  uInt c[BMAX+1];               /* bit length count table */
+  uInt f;                       /* i repeats in table every f entries */
+  int g;                        /* maximum code length */
+  int h;                        /* table level */
+  register uInt i;              /* counter, current code */
+  register uInt j;              /* counter */
+  register int k;               /* number of bits in current code */
+  int l;                        /* bits per table (returned in m) */
+  register uIntf *p;            /* pointer into c[], b[], or v[] */
+  inflate_huft *q;              /* points to current table */
+  struct inflate_huft_s r;      /* table entry for structure assignment */
+  inflate_huft *u[BMAX];        /* table stack */
+  uInt v[N_MAX];                /* values in order of bit length */
+  register int w;               /* bits before this table == (l * h) */
+  uInt x[BMAX+1];               /* bit offsets, then code stack */
+  uIntf *xp;                    /* pointer into x */
+  int y;                        /* number of dummy codes added */
+  uInt z;                       /* number of entries in current table */
+
+
+  /* Generate counts for each bit length */
+  p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+  C4                            /* clear c[]--assume BMAX+1 is 16 */
+  p = b;  i = n;
+  do {
+    c[*p++]++;                  /* assume all entries <= BMAX */
+  } while (--i);
+  if (c[0] == n)                /* null input--all zero length codes */
+  {
+    *t = (inflate_huft *)Z_NULL;
+    *m = 0;
+    return Z_OK;
+  }
+
+
+  /* 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 ((uInt)l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((uInt)l > i)
+    l = i;
+  *m = l;
+
+
+  /* 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 Z_DATA_ERROR;
+  if ((y -= c[i]) < 0)
+    return Z_DATA_ERROR;
+  c[i] += y;
+
+
+  /* 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++);
+  }
+
+
+  /* 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);
+
+
+  /* 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] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */
+  q = (inflate_huft *)Z_NULL;   /* ditto */
+  z = 0;                        /* ditto */
+
+  /* go through the bit lengths (k already is bits in shortest code) */
+  for (; k <= g; k++)
+  {
+    a = c[k];
+    while (a--)
+    {
+      /* here i is the Huffman code of length k bits for value *p */
+      /* make tables up to required level */
+      while (k > w + l)
+      {
+        h++;
+        w += l;                 /* previous table always l bits */
+
+        /* compute minimum size table less than or equal to l bits */
+        z = (z = g - w) > (uInt)l ? l : z;      /* table size upper limit */
+        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
+        {                       /* too few codes for k-w bit table */
+          f -= a + 1;           /* deduct codes from patterns left */
+          xp = c + k;
+          if (j < z)
+            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 */
+            }
+        }
+        z = 1 << j;             /* table entries for j-bit table */
+
+        /* allocate and link in new table */
+        if ((q = (inflate_huft *)ZALLOC
+             (zs,z + 1,sizeof(inflate_huft))) == Z_NULL)
+        {
+          if (h)
+            inflate_trees_free(u[0], zs);
+          return Z_MEM_ERROR;   /* not enough memory */
+        }
+	q->word.Nalloc = z + 1;
+#ifdef DEBUG_ZLIB
+        inflate_hufts += z + 1;
+#endif
+        *t = q + 1;             /* link to list for huft_free() */
+        *(t = &(q->next)) = Z_NULL;
+        u[h] = ++q;             /* table starts after link */
+
+        /* connect to last table, if there is one */
+        if (h)
+        {
+          x[h] = i;             /* save pattern for backing up */
+          r.bits = (Byte)l;     /* bits to dump before this table */
+          r.exop = (Byte)j;     /* bits in this table */
+          r.next = q;           /* pointer to this table */
+          j = i >> (w - l);     /* (get around Turbo C bug) */
+          u[h-1][j] = r;        /* connect to last table */
+        }
+      }
+
+      /* set up table entry in r */
+      r.bits = (Byte)(k - w);
+      if (p >= v + n)
+        r.exop = 128 + 64;      /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
+        r.base = *p++;          /* simple code is just the value */
+      }
+      else
+      {
+        r.exop = (Byte)e[*p - s] + 16 + 64; /* non-simple--look up in lists */
+        r.base = d[*p++ - s];
+      }
+
+      /* 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;
+      }
+    }
+  }
+
+
+  /* Return Z_BUF_ERROR if we were given an incomplete table */
+  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+local int inflate_trees_bits(c, bb, tb, z)
+uIntf *c;               /* 19 code lengths */
+uIntf *bb;              /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+z_stream *z;            /* for zfree function */
+{
+  int r;
+
+  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z);
+  if (r == Z_DATA_ERROR)
+    z->msg = "oversubscribed dynamic bit lengths tree";
+  else if (r == Z_BUF_ERROR)
+  {
+    inflate_trees_free(*tb, z);
+    z->msg = "incomplete dynamic bit lengths tree";
+    r = Z_DATA_ERROR;
+  }
+  return r;
+}
+
+
+local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
+uInt nl;                /* number of literal/length codes */
+uInt nd;                /* number of distance codes */
+uIntf *c;               /* that many (total) code lengths */
+uIntf *bl;              /* literal desired/actual bit depth */
+uIntf *bd;              /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+z_stream *z;            /* for zfree function */
+{
+  int r;
+
+  /* build literal/length tree */
+  if ((r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z)) != Z_OK)
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = "oversubscribed literal/length tree";
+    else if (r == Z_BUF_ERROR)
+    {
+      inflate_trees_free(*tl, z);
+      z->msg = "incomplete literal/length tree";
+      r = Z_DATA_ERROR;
+    }
+    return r;
+  }
+
+  /* build distance tree */
+  if ((r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z)) != Z_OK)
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = "oversubscribed literal/length tree";
+    else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+      r = Z_OK;
+    }
+#else
+      inflate_trees_free(*td, z);
+      z->msg = "incomplete literal/length tree";
+      r = Z_DATA_ERROR;
+    }
+    inflate_trees_free(*tl, z);
+    return r;
+#endif
+  }
+
+  /* done */
+  return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+local int fixed_lock = 0;
+local int fixed_built = 0;
+#define FIXEDH 530      /* number of hufts used by fixed tables */
+local uInt fixed_left = FIXEDH;
+local inflate_huft fixed_mem[FIXEDH];
+local uInt fixed_bl;
+local uInt fixed_bd;
+local inflate_huft *fixed_tl;
+local inflate_huft *fixed_td;
+
+
+local voidpf falloc(q, n, s)
+voidpf q;        /* opaque pointer (not used) */
+uInt n;         /* number of items */
+uInt s;         /* size of item */
+{
+  Assert(s == sizeof(inflate_huft) && n <= fixed_left,
+         "inflate_trees falloc overflow");
+  if (q) s++; /* to make some compilers happy */
+  fixed_left -= n;
+  return (voidpf)(fixed_mem + fixed_left);
+}
+
+
+local void ffree(q, p, n)
+voidpf q;
+voidpf p;
+uInt n;
+{
+  Assert(0, "inflate_trees ffree called!");
+  if (q) q = p; /* to make some compilers happy */
+}
+
+
+local int inflate_trees_fixed(bl, bd, tl, td)
+uIntf *bl;               /* literal desired/actual bit depth */
+uIntf *bd;               /* distance desired/actual bit depth */
+inflate_huft * FAR *tl;  /* literal/length tree result */
+inflate_huft * FAR *td;  /* distance tree result */
+{
+  /* build fixed tables if not built already--lock out other instances */
+  while (++fixed_lock > 1)
+    fixed_lock--;
+  if (!fixed_built)
+  {
+    int k;              /* temporary variable */
+    unsigned c[288];    /* length list for huft_build */
+    z_stream z;         /* for falloc function */
+
+    /* set up fake z_stream for memory routines */
+    z.zalloc = falloc;
+    z.zfree = ffree;
+    z.opaque = Z_NULL;
+
+    /* literal table */
+    for (k = 0; k < 144; k++)
+      c[k] = 8;
+    for (; k < 256; k++)
+      c[k] = 9;
+    for (; k < 280; k++)
+      c[k] = 7;
+    for (; k < 288; k++)
+      c[k] = 8;
+    fixed_bl = 7;
+    huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z);
+
+    /* distance table */
+    for (k = 0; k < 30; k++)
+      c[k] = 5;
+    fixed_bd = 5;
+    huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z);
+
+    /* done */
+    fixed_built = 1;
+  }
+  fixed_lock--;
+  *bl = fixed_bl;
+  *bd = fixed_bd;
+  *tl = fixed_tl;
+  *td = fixed_td;
+  return Z_OK;
+}
+
+
+local int inflate_trees_free(t, z)
+inflate_huft *t;        /* table to free */
+z_stream *z;            /* for zfree function */
+/* 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 inflate_huft *p, *q;
+
+  /* Go through linked list, freeing from the malloced (t[-1]) address. */
+  p = t;
+  while (p != Z_NULL)
+  {
+    q = (--p)->next;
+    ZFREE(z, p, p->word.Nalloc * sizeof(inflate_huft));
+    p = q;
+  } 
+  return Z_OK;
+}
+
+/*+++++*/
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+  /* mode */
+  enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+      START,    /* x: set up for LEN */
+      LEN,      /* i: get length/literal/eob next */
+      LENEXT,   /* i: getting length extra (have base) */
+      DIST,     /* i: get distance next */
+      DISTEXT,  /* i: getting distance extra */
+      COPY,     /* o: copying bytes in window, waiting for space */
+      LIT,      /* o: got literal, waiting for output space */
+      WASH,     /* o: got eob, possibly still output waiting */
+      END,      /* x: got eob and all data flushed */
+      BADCODE}  /* x: got error */
+    mode;               /* current inflate_codes mode */
+
+  /* mode dependent information */
+  uInt len;
+  union {
+    struct {
+      inflate_huft *tree;       /* pointer into tree */
+      uInt need;                /* bits needed */
+    } code;             /* if LEN or DIST, where in tree */
+    uInt lit;           /* if LIT, literal */
+    struct {
+      uInt get;                 /* bits to get for extra */
+      uInt dist;                /* distance back to copy from */
+    } copy;             /* if EXT or COPY, where and how much */
+  } sub;                /* submode */
+
+  /* mode independent information */
+  Byte lbits;           /* ltree bits decoded per branch */
+  Byte dbits;           /* dtree bits decoder per branch */
+  inflate_huft *ltree;          /* literal/length/eob tree */
+  inflate_huft *dtree;          /* distance tree */
+
+};
+
+
+local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl, *td;
+z_stream *z;
+{
+  inflate_codes_statef *c;
+
+  if ((c = (inflate_codes_statef *)
+       ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
+  {
+    c->mode = START;
+    c->lbits = (Byte)bl;
+    c->dbits = (Byte)bd;
+    c->ltree = tl;
+    c->dtree = td;
+    Tracev((stderr, "inflate:       codes new\n"));
+  }
+  return c;
+}
+
+
+local int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+  uInt j;               /* temporary storage */
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  Bytef *f;             /* pointer to copy strings from */
+  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input and output based on current state */
+  while (1) switch (c->mode)
+  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+    case START:         /* x: set up for LEN */
+#ifndef SLOW
+      if (m >= 258 && n >= 10)
+      {
+        UPDATE
+        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+        LOAD
+        if (r != Z_OK)
+        {
+          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+          break;
+        }
+      }
+#endif /* !SLOW */
+      c->sub.code.need = c->lbits;
+      c->sub.code.tree = c->ltree;
+      c->mode = LEN;
+    case LEN:           /* i: get length/literal/eob next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e == 0)               /* literal */
+      {
+        c->sub.lit = t->base;
+        Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                 "inflate:         literal '%c'\n" :
+                 "inflate:         literal 0x%02x\n", t->base));
+        c->mode = LIT;
+        break;
+      }
+      if (e & 16)               /* length */
+      {
+        c->sub.copy.get = e & 15;
+        c->len = t->base;
+        c->mode = LENEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t->next;
+        break;
+      }
+      if (e & 32)               /* end of block */
+      {
+        Tracevv((stderr, "inflate:         end of block\n"));
+        c->mode = WASH;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = "invalid literal/length code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case LENEXT:        /* i: getting length extra (have base) */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->len += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      c->sub.code.need = c->dbits;
+      c->sub.code.tree = c->dtree;
+      Tracevv((stderr, "inflate:         length %u\n", c->len));
+      c->mode = DIST;
+    case DIST:          /* i: get distance next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e & 16)               /* distance */
+      {
+        c->sub.copy.get = e & 15;
+        c->sub.copy.dist = t->base;
+        c->mode = DISTEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t->next;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = "invalid distance code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case DISTEXT:       /* i: getting distance extra */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->sub.copy.dist += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      Tracevv((stderr, "inflate:         distance %u\n", c->sub.copy.dist));
+      c->mode = COPY;
+    case COPY:          /* o: copying bytes in window, waiting for space */
+#ifndef __TURBOC__ /* Turbo C bug for following expression */
+      f = (uInt)(q - s->window) < c->sub.copy.dist ?
+          s->end - (c->sub.copy.dist - (q - s->window)) :
+          q - c->sub.copy.dist;
+#else
+      f = q - c->sub.copy.dist;
+      if ((uInt)(q - s->window) < c->sub.copy.dist)
+        f = s->end - (c->sub.copy.dist - (q - s->window));
+#endif
+      while (c->len)
+      {
+        NEEDOUT
+        OUTBYTE(*f++)
+        if (f == s->end)
+          f = s->window;
+        c->len--;
+      }
+      c->mode = START;
+      break;
+    case LIT:           /* o: got literal, waiting for output space */
+      NEEDOUT
+      OUTBYTE(c->sub.lit)
+      c->mode = START;
+      break;
+    case WASH:          /* o: got eob, possibly more output */
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      c->mode = END;
+    case END:
+      r = Z_STREAM_END;
+      LEAVE
+    case BADCODE:       /* x: got error */
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+}
+
+
+local void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_stream *z;
+{
+  ZFREE(z, c, sizeof(struct inflate_codes_state));
+  Tracev((stderr, "inflate:       codes free\n"));
+}
+
+/*+++++*/
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* copy as much as possible from the sliding window to the output area */
+local int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_stream *z;
+int r;
+{
+  uInt n;
+  Bytef *p, *q;
+
+  /* local copies of source and destination pointers */
+  p = z->next_out;
+  q = s->read;
+
+  /* compute number of bytes to copy as far as end of window */
+  n = (uInt)((q <= s->write ? s->write : s->end) - q);
+  if (n > z->avail_out) n = z->avail_out;
+  if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+  /* update counters */
+  z->avail_out -= n;
+  z->total_out += n;
+
+  /* update check information */
+  if (s->checkfn != Z_NULL)
+    s->check = (*s->checkfn)(s->check, q, n);
+
+  /* copy as far as end of window */
+  zmemcpy(p, q, n);
+  p += n;
+  q += n;
+
+  /* see if more to copy at beginning of window */
+  if (q == s->end)
+  {
+    /* wrap pointers */
+    q = s->window;
+    if (s->write == s->end)
+      s->write = s->window;
+
+    /* compute bytes to copy */
+    n = (uInt)(s->write - q);
+    if (n > z->avail_out) n = z->avail_out;
+    if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+    /* update counters */
+    z->avail_out -= n;
+    z->total_out += n;
+
+    /* update check information */
+    if (s->checkfn != Z_NULL)
+      s->check = (*s->checkfn)(s->check, q, n);
+
+    /* copy */
+    zmemcpy(p, q, n);
+    p += n;
+    q += n;
+  }
+
+  /* update pointers */
+  z->next_out = p;
+  s->read = q;
+
+  /* done */
+  return r;
+}
+
+
+/*+++++*/
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {n+=(c=k>>3);p-=c;k&=7;}
+
+/* Called with number of bytes left to write in window at least 258
+   (the maximum string length) and number of input bytes available
+   at least ten.  The ten bytes are six bytes for the longest length/
+   distance pair plus four bytes for overloading the bit buffer. */
+
+local int inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl, *td;
+inflate_blocks_statef *s;
+z_stream *z;
+{
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  uInt ml;              /* mask for literal/length tree */
+  uInt md;              /* mask for distance tree */
+  uInt c;               /* bytes to copy */
+  uInt d;               /* distance back to copy from */
+  Bytef *r;             /* copy source pointer */
+
+  /* load input, output, bit values */
+  LOAD
+
+  /* initialize masks */
+  ml = inflate_mask[bl];
+  md = inflate_mask[bd];
+
+  /* do until not enough input or output space for fast loop */
+  do {                          /* assume called with m >= 258 && n >= 10 */
+    /* get literal/length code */
+    GRABBITS(20)                /* max bits for literal/length code */
+    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+    {
+      DUMPBITS(t->bits)
+      Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                "inflate:         * literal '%c'\n" :
+                "inflate:         * literal 0x%02x\n", t->base));
+      *q++ = (Byte)t->base;
+      m--;
+      continue;
+    }
+    do {
+      DUMPBITS(t->bits)
+      if (e & 16)
+      {
+        /* get extra bits for length */
+        e &= 15;
+        c = t->base + ((uInt)b & inflate_mask[e]);
+        DUMPBITS(e)
+        Tracevv((stderr, "inflate:         * length %u\n", c));
+
+        /* decode distance base of block to copy */
+        GRABBITS(15);           /* max bits for distance code */
+        e = (t = td + ((uInt)b & md))->exop;
+        do {
+          DUMPBITS(t->bits)
+          if (e & 16)
+          {
+            /* get extra bits to add to distance base */
+            e &= 15;
+            GRABBITS(e)         /* get extra bits (up to 13) */
+            d = t->base + ((uInt)b & inflate_mask[e]);
+            DUMPBITS(e)
+            Tracevv((stderr, "inflate:         * distance %u\n", d));
+
+            /* do the copy */
+            m -= c;
+            if ((uInt)(q - s->window) >= d)     /* offset before dest */
+            {                                   /*  just copy */
+              r = q - d;
+              *q++ = *r++;  c--;        /* minimum count is three, */
+              *q++ = *r++;  c--;        /*  so unroll loop a little */
+            }
+            else                        /* else offset after destination */
+            {
+              e = d - (q - s->window);  /* bytes from offset to end */
+              r = s->end - e;           /* pointer to offset */
+              if (c > e)                /* if source crosses, */
+              {
+                c -= e;                 /* copy to end of window */
+                do {
+                  *q++ = *r++;
+                } while (--e);
+                r = s->window;          /* copy rest from start of window */
+              }
+            }
+            do {                        /* copy all or what's left */
+              *q++ = *r++;
+            } while (--c);
+            break;
+          }
+          else if ((e & 64) == 0)
+            e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop;
+          else
+          {
+            z->msg = "invalid distance code";
+            UNGRAB
+            UPDATE
+            return Z_DATA_ERROR;
+          }
+        } while (1);
+        break;
+      }
+      if ((e & 64) == 0)
+      {
+        if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0)
+        {
+          DUMPBITS(t->bits)
+          Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                    "inflate:         * literal '%c'\n" :
+                    "inflate:         * literal 0x%02x\n", t->base));
+          *q++ = (Byte)t->base;
+          m--;
+          break;
+        }
+      }
+      else if (e & 32)
+      {
+        Tracevv((stderr, "inflate:         * end of block\n"));
+        UNGRAB
+        UPDATE
+        return Z_STREAM_END;
+      }
+      else
+      {
+        z->msg = "invalid literal/length code";
+        UNGRAB
+        UPDATE
+        return Z_DATA_ERROR;
+      }
+    } while (1);
+  } while (m >= 258 && n >= 10);
+
+  /* not enough input or output--restore pointers and return */
+  UNGRAB
+  UPDATE
+  return Z_OK;
+}
+
+
+/*+++++*/
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* From: zutil.c,v 1.8 1995/05/03 17:27:12 jloup Exp */
+
+char *zlib_version = ZLIB_VERSION;
+
+char *z_errmsg[] = {
+"stream end",          /* Z_STREAM_END    1 */
+"",                    /* Z_OK            0 */
+"file error",          /* Z_ERRNO        (-1) */
+"stream error",        /* Z_STREAM_ERROR (-2) */
+"data error",          /* Z_DATA_ERROR   (-3) */
+"insufficient memory", /* Z_MEM_ERROR    (-4) */
+"buffer error",        /* Z_BUF_ERROR    (-5) */
+""};
+
+
+/*+++++*/
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* From: adler32.c,v 1.6 1995/05/03 17:27:08 jloup Exp */
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf)  {s1 += *buf++; s2 += s1;}
+#define DO2(buf)  DO1(buf); DO1(buf);
+#define DO4(buf)  DO2(buf); DO2(buf);
+#define DO8(buf)  DO4(buf); DO4(buf);
+#define DO16(buf) DO8(buf); DO8(buf);
+
+/* ========================================================================= */
+uLong adler32(adler, buf, len)
+    uLong adler;
+    Bytef *buf;
+    uInt len;
+{
+    unsigned long s1 = adler & 0xffff;
+    unsigned long s2 = (adler >> 16) & 0xffff;
+    int k;
+
+    if (buf == Z_NULL) return 1L;
+
+    while (len > 0) {
+        k = len < NMAX ? len : NMAX;
+        len -= k;
+        while (k >= 16) {
+            DO16(buf);
+            k -= 16;
+        }
+        if (k != 0) do {
+            DO1(buf);
+        } while (--k);
+        s1 %= BASE;
+        s2 %= BASE;
+    }
+    return (s2 << 16) | s1;
+}
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/coffboot/zlib.h linux/arch/ppc/coffboot/zlib.h
--- v2.1.50/linux/arch/ppc/coffboot/zlib.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/coffboot/zlib.h	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,432 @@
+/*	$Id: zlib.h,v 1.1 1997/07/31 07:16:15 paulus Exp $	*/
+
+/*
+ * This file is derived from zlib.h and zconf.h from the zlib-0.95
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets.
+ */
+
+/*
+ *  ==FILEVERSION 960122==
+ *
+ * This marker is used by the Linux installation script to determine
+ * whether an up-to-date version of this file is already installed.
+ */
+
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 0.95, Aug 16th, 1995.
+
+  Copyright (C) 1995 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  gzip@prep.ai.mit.edu    madler@alumni.caltech.edu
+ */
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+/* #include "zconf.h" */	/* included directly here */
+
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* From: zconf.h,v 1.12 1995/05/03 17:27:12 jloup Exp */
+
+/*
+     The library does not install any signal handler. It is recommended to
+  add at least a handler for SIGSEGV when decompressing; the library checks
+  the consistency of the input data whenever possible but may go nuts
+  for some forms of corrupted input.
+ */
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ * Compile with -DUNALIGNED_OK if it is OK to access shorts or ints
+ * at addresses which are not a multiple of their size.
+ * Under DOS, -DFAR=far or -DFAR=__far may be needed.
+ */
+
+#ifndef STDC
+#  if defined(MSDOS) || defined(__STDC__) || defined(__cplusplus)
+#    define STDC
+#  endif
+#endif
+
+#ifdef	__MWERKS__ /* Metrowerks CodeWarrior declares fileno() in unix.h */
+#  include <unix.h>
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            1 << (windowBits+2)   +  1 << (memLevel+9)
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+typedef unsigned char  Byte;  /* 8 bits */
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+typedef Byte FAR Bytef;
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void FAR *voidpf;
+   typedef void     *voidp;
+#else
+   typedef Byte FAR *voidpf;
+   typedef Byte     *voidp;
+#endif
+
+/* end of original zconf.h */
+
+#define ZLIB_VERSION "0.95P"
+
+/* 
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms may be added later and will have the same
+  stream interface.
+
+     For compression the application must provide the output buffer and
+  may optionally provide the input buffer for optimization. For decompression,
+  the application must provide the input buffer and may optionally provide
+  the output buffer for optimization.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address, uInt nbytes));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidp      opaque;  /* private data object passed to zalloc and zfree */
+
+    Byte     data_type; /* best guess about the data type: ascii or binary */
+
+} z_stream;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1
+#define Z_FULL_FLUSH    2
+#define Z_SYNC_FLUSH    3 /* experimental: partial_flush + byte align */
+#define Z_FINISH        4
+#define Z_PACKET_FLUSH	5
+/* See deflate() below for the usage of these constants */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+/* error codes for the compression/decompression functions */
+
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_DEFAULT_STRATEGY    0
+
+#define Z_BINARY   0
+#define Z_ASCII    1
+#define Z_UNKNOWN  2
+/* Used to set the data_type field */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+extern char *zlib_version;
+/* The application can compare zlib_version and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is
+   not compatible with the zlib.h header file used by the application.
+ */
+
+                        /* basic functions */
+
+extern int inflateInit OF((z_stream *strm));
+/* 
+     Initializes the internal stream state for decompression. The fields
+   zalloc and zfree must be initialized before by the caller.  If zalloc and
+   zfree are set to Z_NULL, inflateInit updates them to use default allocation
+   functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory.  msg is set to null if there is no error message.
+   inflateInit does not perform any decompression: this will be done by
+   inflate().
+*/
+
+
+extern int inflate OF((z_stream *strm, int flush));
+/*
+  Performs one or both of the following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() always provides as much output as possible
+    (until there is no more input data or no more space in the output buffer).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate().
+
+    If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
+  inflate flushes as much output as possible to the output buffer. The
+  flushing behavior of inflate is not specified for values of the flush
+  parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
+  current implementation actually flushes as much output as possible
+  anyway.  For Z_PACKET_FLUSH, inflate checks that once all the input data
+  has been consumed, it is expecting to see the length field of a stored
+  block; if not, it returns Z_DATA_ERROR.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster routine
+  may be used for the single inflate() call.
+
+    inflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if the end of the
+  compressed data has been reached and all uncompressed output has been
+  produced, Z_DATA_ERROR if the input data was corrupted, Z_STREAM_ERROR if
+  the stream structure was inconsistent (for example if next_in or next_out
+  was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no
+  progress is possible or if there was not enough room in the output buffer
+  when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then
+  call inflateSync to look for a good compression block.  */
+
+
+extern int inflateEnd OF((z_stream *strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* advanced functions */
+
+extern int inflateInit2 OF((z_stream *strm,
+                            int  windowBits));
+/*   
+     This is another version of inflateInit with more compression options. The
+   fields next_out, zalloc and zfree must be initialized before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library (the value 16 will be allowed soon). The
+   default value is 15 if inflateInit is used instead. If a compressed stream
+   with a larger window size is given as input, inflate() will return with
+   the error code Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     If next_out is not null, the library will use this buffer for the history
+   buffer; the buffer must either be large enough to hold the entire output
+   data, or have at least 1<<windowBits bytes.  If next_out is null, the
+   library will allocate its own buffer (and leave next_out null). next_in
+   need not be provided here but must be provided by the application for the
+   next call of inflate().
+
+     If the history buffer is provided by the application, next_out must
+   never be changed by the application since the decompressor maintains
+   history information inside this buffer from call to call; the application
+   can only reset next_out to the beginning of the history buffer when
+   avail_out is zero and all output has been consumed.
+
+      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+   not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+   windowBits < 8). msg is set to null if there is no error message.
+   inflateInit2 does not perform any decompression: this will be done by
+   inflate().
+*/
+
+extern int inflateSync OF((z_stream *strm));
+/* 
+    Skips invalid compressed data until the special marker (see deflate()
+  above) can be found, or until all available input is skipped. No output
+  is provided.
+
+    inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no marker has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+extern int inflateReset OF((z_stream *strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+extern int inflateIncomp OF((z_stream *strm));
+/*
+     This function adds the data at next_in (avail_in bytes) to the output
+   history without performing any output.  There must be no pending output,
+   and the decompressor must be expecting to see the start of a block.
+   Calling this function is equivalent to decompressing a stored block
+   containing the data at next_in (except that the data is not output).
+*/
+
+                        /* checksum functions */
+
+/*
+     This function is not related to compression but is exported
+   anyway because it might be useful in applications using the
+   compression library.
+*/
+
+extern uLong adler32 OF((uLong adler, Bytef *buf, uInt len));
+
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+#ifndef _Z_UTIL_H
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+#endif /* _ZLIB_H */
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.1.50/linux/arch/ppc/config.in	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/config.in	Sat Aug 16 09:51:08 1997
@@ -1,9 +1,13 @@
-#
+# $Id: config.in,v 1.16 1997/08/11 08:37:49 cort Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
 mainmenu_name "Linux/PowerPC Kernel Configuration"
 
+mainmenu_option next_comment
+comment 'Platform support'
+define_bool CONFIG_PPC y
+
 if [ "`uname`" != "Linux" ]; then
   define_bool CONFIG_CROSSCOMPILE y
 else
@@ -12,25 +16,28 @@
 
 bool 'Build PowerMac Kernel (not PReP)?' CONFIG_PMAC
 bool 'Build PReP Kernel (not PowerMac)?' CONFIG_PREP
-bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
-bool 'Used Harddrive LED on IBM 83x workstations as heartbeat?' CONFIG_HEARTBEAT
-bool 'Used PowerPC specific powersaving?' CONFIG_POWERSAVING
+
 choice 'Processor type' \
 	"Common		CONFIG_MCOMMON \
 	 601		CONFIG_M601	\
 	 603		CONFIG_M603	\
 	 604		CONFIG_M604" Common
+endmenu
 
+mainmenu_option next_comment
+comment 'General setup'
+
+bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
 bool 'Enable loadable module support' CONFIG_MODULES
 if [ "$CONFIG_MODULES" = "y" ]; then
   bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
   bool 'Kernel daemon support (e.g. autoload of modules)' CONFIG_KERNELD
 fi
 
-
-mainmenu_option next_comment
 define_bool CONFIG_PCI y
-bool 'PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
+if [ "$CONFIG_PREP" = "y" ]; then
+  bool 'PCI bridge optimization' CONFIG_PCI_OPTIMIZE
+fi
 bool 'Networking support' CONFIG_NET
 bool 'Sysctl support' CONFIG_SYSCTL
 bool 'System V IPC' CONFIG_SYSVIPC
@@ -41,6 +48,22 @@
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
 
+if [ "$CONFIG_PMAC" = "y" ]; then
+  define_bool CONFIG_PMAC_CONSOLE y
+  define_bool CONFIG_MAC_KEYBOARD y
+  define_bool CONFIG_MAC_FLOPPY	y
+  bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
+  bool 'Include xmon kernel debugger' CONFIG_XMON
+fi
+
+if [ "$CONFIG_PMAC_CONSOLE" = "y" ]; then
+  bool 'Support for ATI Mach64 display cards' CONFIG_ATY_VIDEO
+  bool 'Support for IMS Twin Turbo display card' CONFIG_IMSTT_VIDEO
+else
+  define_bool CONFIG_VGA_CONSOLE y
+fi
+
+endmenu
 
 source drivers/pnp/Config.in
 source drivers/block/Config.in
@@ -83,6 +106,7 @@
 endmenu
 
 source fs/Config.in
+
 source drivers/char/Config.in
 
 mainmenu_option next_comment
@@ -93,12 +117,12 @@
 fi
 endmenu
 
-mainmenu_option next_comment
+#mainmenu_option next_comment
 #comment 'Kernel hacking'
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
 #bool 'Kernel profiling support' CONFIG_PROFILE
 #if [ "$CONFIG_PROFILE" = "y" ]; then
 #  int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 #fi
-endmenu
+#endmenu
 
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/defconfig linux/arch/ppc/defconfig
--- v2.1.50/linux/arch/ppc/defconfig	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/defconfig	Sat Aug 16 09:51:08 1997
@@ -1,30 +1,31 @@
 #
 # Automatically generated by make menuconfig: don't edit
 #
+
+#
+# Platform support
+#
 CONFIG_NATIVE=y
 # CONFIG_PMAC is not set
 CONFIG_PREP=y
-# CONFIG_HEARTBEAT is not set
-# CONFIG_POWERSAVING is not set
 CONFIG_MCOMMON=y
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KERNELD=y
 CONFIG_PCI=y
 CONFIG_PCI_OPTIMIZE=y
 CONFIG_NET=y
 CONFIG_SYSCTL=y
 CONFIG_SYSVIPC=y
-# CONFIG_BINFMT_JAVA is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_BINFMT_JAVA is not set
 
 #
 # Plug and Play support
@@ -46,10 +47,10 @@
 # CONFIG_BLK_DEV_RZ1000 is not set
 # CONFIG_BLK_DEV_TRITON is not set
 # CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
-# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_BLK_DEV_EZ is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -100,7 +101,6 @@
 # CONFIG_SCSI_ULTRASTOR is not set
 # CONFIG_SCSI_MESH is not set
 # CONFIG_SCSI_MAC53C94 is not set
-# CONFIG_SCSI_QLOGIC_PMAC is not set
 
 #
 # Network device support
@@ -117,6 +117,7 @@
 # CONFIG_IP_ACCT is not set
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_PCTCP is not set
 # CONFIG_INET_RARP is not set
 CONFIG_PATH_MTU_DISCOVERY=y
@@ -155,6 +156,7 @@
 # CONFIG_DEC_ELCP is not set
 # CONFIG_DGRS is not set
 # CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_TLAN is not set
 # CONFIG_ES3210 is not set
 # CONFIG_ZNET is not set
 # CONFIG_NET_POCKET is not set
@@ -183,16 +185,13 @@
 # CONFIG_QUOTA is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_EXT2_FS=y
-CONFIG_BEXT2_FS=y
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
 # CONFIG_VFAT_FS is not set
 # CONFIG_UMSDOS_FS is not set
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-# CONFIG_RNFS_BOOTP is not set
-# CONFIG_RNFS_RARP is not set
+# CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
@@ -205,7 +204,6 @@
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_UFS_FS is not set
 CONFIG_MAC_PARTITION=y
-CONFIG_HFS_FS=y
 
 #
 # Character devices
@@ -213,12 +211,7 @@
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_SERIAL=y
-CONFIG_SERIAL_EXTENDED=y
-# CONFIG_SERIAL_MANY_PORTS is not set
-# CONFIG_SERIAL_SHARE_IRQ is not set
-# CONFIG_SERIAL_MULTIPORT is not set
-# CONFIG_HUB6 is not set
-# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 # CONFIG_PRINTER is not set
 CONFIG_MOUSE=y
@@ -227,13 +220,39 @@
 # CONFIG_MS_BUSMOUSE is not set
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_FTAPE is not set
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
+# CONFIG_NVRAM is not set
+# CONFIG_JOYSTICK is not set
 
 #
 # Sound
 #
-# CONFIG_SOUND is not set
+#CONFIG_SOUND=y
+# CONFIG_PAS is not set
+# CONFIG_SB is not set
+# CONFIG_ADLIB is not set
+# CONFIG_GUS is not set
+# CONFIG_MPU401 is not set
+# CONFIG_PSS is not set
+# CONFIG_GUS16 is not set
+# CONFIG_GUSMAX is not set
+# CONFIG_MSS is not set
+# CONFIG_SSCAPE is not set
+# CONFIG_TRIX is not set
+# CONFIG_MAD16 is not set
+CONFIG_CS4232=y
+# CONFIG_MAUI is not set
+# CONFIG_YM3812 is not set
+CS4232_BASE=830
+CS4232_IRQ=10
+CS4232_DMA=6
+CS4232_DMA2=7
+CS4232_MPU_BASE=330
+CS4232_MPU_IRQ=9
+# CONFIG_LOWLEVEL_SOUND is not set
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- v2.1.50/linux/arch/ppc/kernel/Makefile	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/Makefile	Sat Aug 16 09:51:08 1997
@@ -7,40 +7,25 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
-.c.s:
-	$(CC) $(CFLAGS) -S $<
-.s.o:
-	$(AS) $(ASFLAGS) -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.S.s:
-	$(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
 .S.o:
-	$(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
-	$(AS) $(ASFLAGS) -o $*.o $*.s
-	rm $*.s
+	$(CC) -D__ASSEMBLY__ -c $< -o $*.o
 
-HOST_CC = gcc
-
-OBJS  = misc.o port_io.o pci.o traps.o process.o \
-	signal.o syscalls.o ptrace.o ksyms.o irq.o bitops.o strcase.o ppc_htab.o
+O_TARGET := kernel.o
+O_OBJS := misc.o traps.o process.o signal.o syscalls.o \
+	  align.o ptrace.o irq.o bitops.o ppc_htab.o idle.o prom.o \
+	  time.o prep_time.o pmac_time.o \
+	  setup.o pmac_setup.o pmac_support.o \
+	  pci.o prep_pci.o pmac_pci.o
+OX_OBJS := ppc_ksyms.o
 
 all: head.o kernel.o
+
 head.o: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h
 
 ifeq ($(CONFIG_PREP),y)
-OBJS += prep_setup.o prep_time.o
-endif
-
-ifeq ($(CONFIG_PMAC),y)
-OBJS += pmac_setup.o pmac_support.o align.o pmac_time.o
+O_OBJS += prep_setup.o #prep_time.o
 endif
 
-ifeq ($(CONFIG_MODULES),y)
-OBJS = ksyms.o
-endif
-
-
 ppc_defs.h: mk_defs.c ppc_defs.head \
 		$(TOPDIR)/include/asm/mmu.h \
 		$(TOPDIR)/include/asm/processor.h \
@@ -53,24 +38,6 @@
 
 checks: checks.c
 	$(HOSTCC) ${CFLAGS} -o checks checks.c
-	checks
+	./checks
 
-kernel.o: $(OBJS)
-	$(LD) -r -o kernel.o $(OBJS)
-
-fastdep:
-	$(TOPDIR)/scripts/mkdep *.[Sch] > .depend
-
-dep:
-	$(CPP) -M *.S *.c > .depend
-
-modules: 
-
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/checks.c linux/arch/ppc/kernel/checks.c
--- v2.1.50/linux/arch/ppc/kernel/checks.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/checks.c	Sat Aug 16 09:51:08 1997
@@ -25,7 +25,7 @@
 int main(void)
 {
 	int ret = 0;
-	
+#if 0
 	if ( sizeof(struct thread_struct) % 16 )
 	{
 		printf("Thread struct is not modulo 16 bytes: "
@@ -34,6 +34,7 @@
 			sizeof(struct thread_struct)%16);
 		ret = -1;
 	}
+#endif	
 
 	if ( sizeof(struct pt_regs) % 16 )
 	{
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- v2.1.50/linux/arch/ppc/kernel/head.S	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/head.S	Sat Aug 16 09:51:08 1997
@@ -45,14 +45,13 @@
 
 #define TOPHYS(x)	(x - KERNELBASE)
 
-
 /* this is a very kludgey way of loading up the BATs on the
    prep system.  I'll kill this horrible macro and write
    something clean when I have a chance -- Cort
  */	
 #define LOAD_BATS(RA,RB) \
 	mfspr	RA,PVR		; \
-	srwi	r5,r5,16	; \
+	srwi	RA,RA,16	; \
 	cmpi	0,RA,1		; \
 	beq	199f		; \
 	/* load bats for 60x */	; \
@@ -132,21 +131,10 @@
 	mtspr	DBAT3L,RB	; \
 200:
 	
-
-
-	
 	.text
 	.globl	_stext
 _stext:
 
-#ifdef CONFIG_PREP	
-	. = 0x100
-_GLOBAL(HardReset)
-	b	_start
-
-#endif /* CONFIG_PREP */
-
-#ifdef CONFIG_PMAC
 /*
  * _start is defined this way because the XCOFF loader in the OpenFirmware
  * on the powermac expects the entry point to be a procedure descriptor.
@@ -156,7 +144,7 @@
 _start:
 	.long	TOPHYS(__start),0,0
 
-/*
+/* PMAC
  * Enter here with the kernel text, data and bss loaded starting at
  * 0, running with virtual == physical mapping.
  * r5 points to the prom entry point (the client interface handler
@@ -165,41 +153,81 @@
  * pointer (r1) points to just below the end of the half-meg region
  * from 0x380000 - 0x400000, which is mapped in already.
  */
+/* PREP
+ * This is jumped to on prep systems right after the kernel is relocated
+ * to its proper place in memory by the boot loader.  The expected layout
+ * of the regs is:	
+ *   r3: ptr to residual data
+ *   r4: initrd_start or if no initrd then 0
+ *   r5: initrd_end - unused if r4 is 0
+ *   r6: Start of command line string
+ *   r7: End of command line string
+ *
+ * This just gets a minimal mmu environment setup so we can call
+ * start_here() to do the real work.
+ * -- Cort	
+ */
+	
 	.globl	__start
 __start:
 
 /*
- * Use the first pair of BAT registers to map the 1st 8MB
+ * Use the first pair of BAT registers to map the 1st 16MB
  * of RAM to KERNELBASE.
  */
 	mfspr	r9,PVR
 	rlwinm	r9,r9,16,16,31		/* r9 = 1 for 601, 4 for 604 */
 	cmpi	0,r9,1
-	lis	r7,KERNELBASE@h
+	lis	r11,KERNELBASE@h
 	bne	4f
-	ori	r7,r7,4			/* set up BAT registers for 601 */
+	ori	r11,r11,4		/* set up BAT registers for 601 */
 	li	r8,0x7f
+	oris	r9,r11,0x800000@h	/* set up BAT reg for 2nd 8M */
+	oris	r10,r8,0x800000@h	/* set up BAT reg for 2nd 8M */
+	mtspr	IBAT1U,r9
+	mtspr	IBAT1L,r10
 	b	5f
-4:	ori	r7,r7,0xff		/* set up BAT registers for 604 */
+4:	ori	r11,r11,0x1ff		/* set up BAT registers for 604 */
 	li	r8,2
-	mtspr	DBAT0U,r7
+	mtspr	DBAT0U,r11
 	mtspr	DBAT0L,r8
-5:	mtspr	IBAT0U,r7
+5:	mtspr	IBAT0U,r11
 	mtspr	IBAT0L,r8
 	isync
 
+#if 0	
 /*
  * Now we have the 1st 8M of RAM mapped at KERNELBASE, so we can
  * refer to addresses of data items, procedures, etc. normally.
  */
-	lis	r7,start_here@ha	/* jump up to our copy at KERNELBASE */
-	addi	r7,r7,start_here@l
-	mtlr	r7
+	lis	r10,start_here@ha	/* jump up to our copy at KERNELBASE */
+	addi	r10,r10,start_here@l
+	mtlr	r10
 	blr
-#endif /* CONFIG_PMAC */
-
-
+#endif
+/*
+ * we now have the 1st 16M of ram mapped with the bats.
+ * prep needs the mmu to be turned on here, but pmac already has it on.
+ * this shouldn't bother the pmac since it just gets turned on again
+ * as we jump to our code at KERNELBASE. -- Cort
+ */
+	mfmsr	r0
+	ori	r0,r0,MSR_DR|MSR_IR
+	mtspr	SRR1,r0
+	lis	r0,start_here@h
+	ori	r0,r0,start_here@l
+	mtspr	SRR0,r0
+	SYNC
+	rfi				/* enables MMU */
+		
 
+/*
+ * GCC sometimes accesses words at negative offsets from the stack
+ * pointer, although the SysV ABI says it shouldn't.  To cope with
+ * this, we leave this much untouched space on the stack on exception
+ * entry.
+ */
+#define STACK_UNDERHEAD	64
 	
 /*
  * Macros for storing registers into and loading registers from
@@ -286,10 +314,8 @@
 	.long	hdlr;				\
 	.long	int_return
 
-#ifndef CONFIG_PREP
 /* System reset */
 	STD_EXCEPTION(0x100, Reset, UnknownException)
-#endif /* ndef CONFIG_PREP */
 
 /* Machine check */
 	STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
@@ -319,7 +345,7 @@
 
 /* Instruction access exception */
 	. = 0x400
-InstructionAccess:	
+InstructionAccess:
 	EXCEPTION_PROLOG
 	andis.	r0,r23,0x4000		/* no pte found? */
 	beq	1f			/* if so, try to put a PTE */
@@ -338,7 +364,7 @@
 	.long	int_return
 
 /* External interrupt */
-	STD_EXCEPTION(0x500, HardwareInterrupt, handle_IRQ)
+	STD_EXCEPTION(0x500, HardwareInterrupt, do_IRQ)
 
 /* Alignment exception */
 	. = 0x600
@@ -376,21 +402,7 @@
 	.long	KernelFP
 	.long	int_return
 
-/* Decrementer */
-#ifdef CONFIG_PREP
-/* - ignored for now... */
-_ORG(0x0900)
-	mtspr	SPRG0,r1
-	lis	r1,0x7FFF
-	ori	r1,r1,0xFFFF
-	mtspr	DEC,r1
-	mfspr	r1,SPRG0
-	rfi
-#endif /* CONFIG_PREP */
-#ifdef CONFIG_PMAC
 	STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
-#endif /* CONFIG_PMAC */
-
 	STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
 	STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
 
@@ -596,11 +608,6 @@
 	andi.	r23,r23,MSR_PR
 	mfspr	r23,SPRG3		/* if from user, fix up tss */
 	beq	2f
-#ifdef CONFIG_PMAC	
-	lwz	r24,GPR1(r21)
-	stw	r22,LAST_PC(r23)
-	stw	r24,USER_STACK(r23)
-#endif /* CONFIG_PMAC */
 	addi	r24,r1,STACK_FRAME_OVERHEAD
 	stw	r24,PT_REGS(r23)
 2:	addi	r2,r23,-TSS		/* set r2 to current */
@@ -630,7 +637,7 @@
 	REST_32FPRS(0, r5)
 
 /* use last_task_used_math instead of fpu_tss */
-	lis	r3,last_task_used_math@h/*a*/
+	lis	r3,last_task_used_math@ha
 	addis	r3,r3,-KERNELBASE@h
 	subi	r4,r5,TSS
 	addis	r4,r4,KERNELBASE@h
@@ -654,7 +661,7 @@
 	REST_GPR(20, r21)
 	REST_2GPRS(22, r21)
 	lwz	r21,GPR21(r21)
- 	SYNC
+	SYNC
 	rfi
 
 /*
@@ -682,14 +689,15 @@
 	.globl	hash_page
 hash_page:
 	/* Get PTE (linux-style) and check access */
-	lwz	r5,PG_TABLES(r5)	/* task's page tables */
-	lis	r2,-KERNELBASE@h
-	add	r5,r5,r2		/* convert to phys addr */
+	lwz	r5,MM-TSS(r5)		
+	addis	r5,r5,-KERNELBASE@h	/* get physical current->mm */
+	lwz	r5,PGD(r5)		/* get current->mm->pgd */	
+	addis	r5,r5,-KERNELBASE@h	/* convert to phys addr */
 	rlwimi	r5,r3,12,20,29		/* insert top 10 bits of address */
 	lwz	r5,0(r5)		/* get pmd entry */
 	rlwinm.	r5,r5,0,0,19		/* extract address of pte page */
 	beqlr-				/* return if no mapping */
-	add	r2,r5,r2
+	addis	r2,r5,-KERNELBASE@h
 	rlwimi	r2,r3,22,20,29		/* insert next 10 bits of address */
 	lwz	r6,0(r2)		/* get linux-style pte */
 	ori	r4,r4,1			/* set _PAGE_PRESENT bit in access */
@@ -819,58 +827,64 @@
 	rlwinm	r9,r9,16,16,31
 	cmpi	0,r9,1
 	beq	4f			/* not needed for 601 */
-	mfspr	r7,HID0
-	andi.	r0,r7,HID0_DCE
-	ori	r7,r7,HID0_ICE|HID0_DCE
-	ori	r8,r7,HID0_ICFI
+	mfspr	r11,HID0
+	andi.	r0,r11,HID0_DCE
+	ori	r11,r11,HID0_ICE|HID0_DCE
+	ori	r8,r11,HID0_ICFI
 	bne	3f			/* don't invalidate the D-cache */
 	ori	r8,r8,HID0_DCI		/* unless it wasn't enabled */
-3:	sync
+3:
+	/* I haven't tested this yet so it's off now - Cort */
+	/* turn on dpm for 603 */
+	cmpi	0,r9,3
+	bne	10f
+	oris	r11,r11,HID0_DPM@h
+10:	
+	sync
 	mtspr	HID0,r8			/* enable and invalidate caches */
 	sync
-	mtspr	HID0,r7			/* enable caches */
+	mtspr	HID0,r11		/* enable caches */
 	sync
 	isync
 	cmpi	0,r9,4			/* check for 604 */
 	cmpi	1,r9,9			/* or 604e */
 	cror	2,2,6
 	bne	4f
-	ori	r7,r7,HID0_SIED|HID0_BHTE /* for 604[e], enable */
-	mtspr	HID0,r7			/* superscalar exec & br history tbl */
+	ori	r11,r11,HID0_SIED|HID0_BHTE /* for 604[e], enable */
+	mtspr	HID0,r11		/* superscalar exec & br history tbl */
 4:
 	/* ptr to current */
 	lis	r2,init_task_union@h
 	ori	r2,r2,init_task_union@l
 	/* ptr to phys current tss */
-	addis	r3,r2,-KERNELBASE@h
-	addi	r3,r3,TSS	/* init task's TSS */
-	mtspr	SPRG3,r3
+	addis	r11,r2,-KERNELBASE@h
+	addi	r11,r11,TSS	/* init task's TSS */
+	mtspr	SPRG3,r11
 	/* stack */
 	addi	r1,r2,TASK_UNION_SIZE
 	li	r0,0
 	stwu	r0,-STACK_FRAME_OVERHEAD(r1)
 
 	/* Clear out the BSS */
-	lis	r7,_end@ha
-	addi	r7,r7,_end@l
+	lis	r11,_end@ha
+	addi	r11,r11,_end@l
 	lis	r8,__bss_start@ha
 	addi	r8,r8,__bss_start@l
-	subf	r7,r8,r7
-	addi	r7,r7,3
-	rlwinm.	r7,r7,30,2,31
+	subf	r11,r8,r11
+	addi	r11,r11,3
+	rlwinm.	r11,r11,30,2,31
 	beq	2f
 	addi	r8,r8,-4
-	mtctr	r7
+	mtctr	r11
 	li	r0,0
 3:	stwu	r0,4(r8)
 	bdnz	3b
 2:
 /*
- * Initialize the prom stuff (powermacs only) and the MMU.
+ * Initialize the prom stuff and the MMU.
  */
-#ifdef CONFIG_PMAC
+	bl	identify_machine
 	bl	prom_init
-#endif /* CONFIG_PMAC */
 	bl	MMU_init
 
 /*
@@ -889,11 +903,6 @@
 	rfi
 /* Load up the kernel context */
 2:
-#ifdef CONFIG_PREP
-	/* reload the bats now that MMU_init() has setup them up -- Cort */
-	LOAD_BATS(r3,r0)
-#endif
-
 	SYNC			/* Force all PTE updates to finish */
 	tlbia			/* Clear all TLB entries */
 	mtspr	SDR1,r6
@@ -905,8 +914,19 @@
 	addi	r3,r3,1		/* increment VSID */
 	addis	r4,r4,0x1000	/* address of next segment */
 	bdnz	3b
-#ifdef CONFIG_PMAC
-	li	r0,0		/* zot the BATs */
+
+	lis	r3,_machine@ha
+	addis	r3,r3,-KERNELBASE@h
+	lwz	r0,_machine@l(r3)
+	cmpi	0,r0,_MACH_Pmac
+	beq	99f
+	
+/* on prep reload the bats now that MMU_init() has setup them up -- Cort */
+	LOAD_BATS(r3,r14)
+	b	100f
+	
+/* on pmac clear the bats out */	
+99:	li	r0,0		/* zot the BATs */
 #if 1
 	mtspr	IBAT0U,r0
 	mtspr	IBAT0L,r0
@@ -925,7 +945,7 @@
 	mtspr	IBAT3L,r0
 	mtspr	DBAT3U,r0
 	mtspr	DBAT3L,r0
-#endif
+100:	
 /* Now turn on the MMU for real! */
 	li	r4,MSR_KERNEL
 	lis	r3,start_kernel@h
@@ -934,61 +954,6 @@
 	mtspr	SRR1,r4
 	rfi			/* enable MMU and jump to start_kernel */
 
-#ifdef CONFIG_PREP
-/*
- * This is jumped to on prep systems right after the kernel is relocated
- * to its proper place in memory by the boot loader.  The expected layout
- * of the regs is:	
- *   R3: End of image
- *   R4: Start of image - 0x400
- *   R11: Start of command line string
- *   R12: End of command line string
- *
- * This just gets a minimal mmu environment setup so we can call
- * start_here() to do the real work.
- * -- Cort	
- */
-	.globl __start
-__start:	
-	.globl _start
-_start:	
-	lis	r7,0xF000		/* To mask upper 4 bits */
-/* save pointer to residual data */
-	lis	r1,resptr@h
-	ori	r1,r1,resptr@l
-	addis	r1,r1,-KERNELBASE@h
-	stw	r3,0(r1)
-/* save argument string */
-	li	r0,0		/* Null terminate string */
-	stb	r0,0(r12)
-	lis	r1,cmd_line@h
-	ori	r1,r1,cmd_line@l
-	addis	r1,r1,-KERNELBASE@h
-	subi	r1,r1,1
-	subi	r11,r11,1
-00:	lbzu	r0,1(r11)
-	cmpi	0,r0,0
-	stbu	r0,1(r1)
-	bne	00b
-/* setup the msr with sane values */
-	li	r0,MSR_
-	mtmsr	r0
-/* turn on the mmu with bats covering kernel enough to get started */
-	LOAD_BATS(r3,r0)
-	mfmsr	r3
-	ori	r3,r3,MSR_DR|MSR_IR
-	mtspr	SRR1,r3
-	lis	r3,10f@h
-	ori	r3,r3,10f@l
-	mtspr	SRR0,r3
-	SYNC
-	rfi				/* enables MMU */
-10:	lis	r7,start_here@ha	/* jump up to our copy at KERNELBASE */
-	addi	r7,r7,start_here@l
-	mtlr	r7
-	blr
-#endif /* CONFIG_PREP */
-	
 /*
  * FP unavailable trap from kernel - print a message, but let
  * the task use FP in the kernel until it returns to user mode.
@@ -1022,31 +987,23 @@
 giveup_fpu:
 	li	r6,0
 1:
-	addis	r3,r6,last_task_used_math@h/*a*/
+	addis	r3,r6,last_task_used_math@ha
 	lwz	r4,last_task_used_math@l(r3)
-#if 0		
-	addis	r3,r6,fpu_tss@ha
-	lwz	r4,fpu_tss@l(r3)
-#endif	
 	mfmsr	r5
 	ori	r5,r5,MSR_FP
 	SYNC
 	mtmsr	r5			/* enable use of fpu now */
 	SYNC
 	cmpi	0,r4,0
+	beqlr-				/* if no previous owner, done */
 	add	r4,r4,r6
-	beqlr				/* if no previous owner, done */
 	addi	r4,r4,TSS	        /* want TSS of last_task_used_math */
 	li	r5,0
 	stw	r5,last_task_used_math@l(r3)
-#if 0	
-	stw	r5,fpu_tss@l(r3)
-#endif
 	SAVE_32FPRS(0, r4)
 	mffs	fr0
 	stfd	fr0,TSS_FPSCR-4(r4)
 	lwz	r5,PT_REGS(r4)
-	lwz	r5,PT_REGS(r4)
 	add	r5,r5,r6
 	lwz	r3,_MSR-STACK_FRAME_OVERHEAD(r5)
 	li	r4,MSR_FP
@@ -1268,7 +1225,7 @@
 	cmpi	0,r4,0
 	beq+	1f
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	bl	handle_IRQ
+	bl	do_IRQ
 	b	3b
 1:	lis	r4,bh_mask@ha
 	lwz	r4,bh_mask@l(r4)
@@ -1341,7 +1298,7 @@
 	li	r0,0x0fac
 	stw	r0,TRAP(r1)
 	addi	r3,r1,STACK_FRAME_OVERHEAD
-	bl	handle_IRQ
+	bl	do_IRQ
 	addi	r1,r1,INT_FRAME_SIZE+STACK_UNDERHEAD
 	lwz	r0,4(r1)
 	mtlr	r0
@@ -1384,11 +1341,11 @@
  * and invalidate the corresponding instruction cache blocks.
  * This is a no-op on the 601.
  *
- * store_cache_range(unsigned long start, unsigned long stop)
+ * flush_icache_range(unsigned long start, unsigned long stop)
  */
 CACHE_LINE_SIZE = 32
 LG_CACHE_LINE_SIZE = 5
-_GLOBAL(store_cache_range)
+_GLOBAL(flush_icache_range)
 	mfspr	r5,PVR
 	rlwinm	r5,r5,16,16,31
 	cmpi	0,r5,1
@@ -1521,7 +1478,6 @@
 _GLOBAL(__main)
 	blr
 
-#ifdef CONFIG_PMAC
 /*
  * These exception handlers are used when we have called a prom
  * routine after we have taken over the exception vectors and MMU.
@@ -1716,7 +1672,6 @@
 	lwz	r31,28(r1)
 	lwz	r1,0(r1)
 	blr
-#endif
 
 /*
  * We put a few things here that have to be page-aligned.
@@ -1726,7 +1681,6 @@
 	.data
 	.globl	sdata
 sdata:
-	.space	2*4096
 	.globl	empty_zero_page
 empty_zero_page:
 	.space	4096
@@ -1735,7 +1689,6 @@
 swapper_pg_dir:
 	.space	4096	
 
-#ifdef CONFIG_PREP
 /*
  * This space gets a copy of optional info passed to us by the bootstrap
  * Used to pass parameters into the kernel like root=/dev/sda1, etc.
@@ -1743,5 +1696,4 @@
 	.globl	cmd_line
 cmd_line:
 	.space	512
-#endif /* CONFIG_PREP */
 
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c
--- v2.1.50/linux/arch/ppc/kernel/idle.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/idle.c	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,278 @@
+/*
+ * $Id: idle.c,v 1.3 1997/08/10 04:49:08 davem Exp $
+ *
+ * Idle daemon for PowerPC.  Idle daemon will handle any action
+ * that needs to be taken when the system becomes idle.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#define __KERNEL_SYSCALLS__
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/config.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/smp_lock.h>
+#include <asm/processor.h>
+
+int zero_paged(void *unused);
+int power_saved(void *unused);
+
+asmlinkage int sys_idle(void)
+{
+	int ret = -EPERM;
+
+	if (current->pid != 0)
+		goto out;
+
+	/*
+	 * want one per cpu since it would be nice to have all
+	 * processors who aren't doing anything
+	 * zero-ing pages since this daemon is lock-free
+	 * -- Cort
+	 */
+	kernel_thread(zero_paged, NULL, 0);
+	/* no powersaving modes on 601 */
+	/*if(  (_get_PVR()>>16) != 1 )
+		kernel_thread(power_saved, NULL, 0);*/
+
+	/* endless loop with no priority at all */
+	current->priority = -100;
+	current->counter = -100;
+	for (;;)
+	{
+		schedule();
+	}
+	ret = 0;
+out:
+	return ret;
+}
+
+/*
+ * vars for idle task zero'ing out pages
+ */
+unsigned long zero_list = 0;	/* head linked list of pre-zero'd pages */
+unsigned long bytecount = 0;	/* pointer into the currently being zero'd page */
+unsigned long zerocount = 0;	/* # currently pre-zero'd pages */
+unsigned long zerototal = 0;	/* # pages zero'd over time -- for ooh's and ahhh's */
+unsigned long pageptr = 0;	/* current page being zero'd */
+unsigned long zeropage_hits = 0;/* # zero'd pages request that we've done */
+unsigned long zeropage_calls = 0;/* # zero'd pages request that've been made */
+static struct wait_queue * page_zerod_wait = NULL;
+#define PAGE_THRESHOLD 96       /* how many pages to keep pre-zero'd */
+
+/*
+ * Returns a pre-zero'd page from the list otherwise returns
+ * NULL.
+ */
+unsigned long get_prezerod_page(void)
+{
+	unsigned long page;
+
+	atomic_inc((atomic_t *)&zeropage_calls);
+	if ( zero_list )
+	{
+		/* atomically remove this page from the list */
+		asm (	"101:lwarx  %1,0,%2\n"  /* reserve zero_list */
+			"    lwz    %0,0(%1)\n" /* get next -- new zero_list */
+			"    stwcx. %0,0,%2\n"  /* update zero_list */
+			"    bne-   101b\n"     /* if lost reservation try again */
+			: "=&r" (zero_list), "=&r" (page)
+			: "r" (&zero_list)
+			: "cc" );
+		/* we can update zerocount after the fact since it is not
+		 * used for anything but control of a loop which doesn't
+		 * matter since it won't effect anything if it zero's one
+		 * less page -- Cort
+		 */
+		atomic_inc((atomic_t *)&zeropage_hits);
+		atomic_dec((atomic_t *)&zerocount);
+		wake_up(&page_zerod_wait);
+		resched_force();
+		
+		/* zero out the pointer to next in the page */
+		*(unsigned long *)page = 0;
+		return page;
+	}
+	return 0;
+}
+
+/*
+ * Experimental stuff to zero out pages in the idle task
+ * to speed up get_free_pages() -- Cort
+ * Zero's out pages until we need to resched or
+ * we've reached the limit of zero'd pages.
+ */
+
+int zero_paged(void *unused)
+{
+	extern pte_t *get_pte( struct mm_struct *mm, unsigned long address );
+	pgd_t *dir;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	sprintf(current->comm, "zero_paged (idle)");
+	current->blocked = ~0UL;
+	
+	printk("Started zero_paged\n");
+	
+	__sti();
+	while ( 1 )
+	{
+		/* don't want to be pre-empted by swapper or power_saved */
+		current->priority = -98;
+		current->counter = -98;
+		/* we don't want to run until we have something to do */
+		while ( zerocount >= PAGE_THRESHOLD )
+			sleep_on(&page_zerod_wait);
+		/*
+		 * Mark a page as reserved so we can mess with it
+		 * If we're interrupted we keep this page and our place in it
+		 * since we validly hold it and it's reserved for us.
+		 */
+		pageptr = __get_free_pages(GFP_ATOMIC, 0, 0 );
+		if ( !pageptr )
+		{
+			printk("!pageptr in zero_paged\n");
+			goto retry;
+		}
+		
+		if ( resched_needed() )
+			schedule();
+		
+		/*
+		 * Make the page no cache so we don't blow our cache with 0's
+		 */
+		dir = pgd_offset( init_task.mm, pageptr );
+		if (dir)
+		{
+			pmd = pmd_offset(dir, pageptr & PAGE_MASK);
+			if (pmd && pmd_present(*pmd))
+			{
+				pte = pte_offset(pmd, pageptr & PAGE_MASK);
+				if (pte && pte_present(*pte))
+				{			
+					pte_uncache(*pte);
+					flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+				}
+			}
+		}
+	
+		/*
+		 * Important here to not take time away from real processes.
+		 */
+		for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
+		{
+			if ( resched_needed() )
+				schedule();
+			*(unsigned long *)(bytecount + pageptr) = 0;
+		}
+		
+		/*
+		 * If we finished zero-ing out a page add this page to
+		 * the zero_list atomically -- we can't use
+		 * down/up since we can't sleep in idle.
+		 * Disabling interrupts is also a bad idea since we would
+		 * steal time away from real processes.
+		 * We can also have several zero_paged's running
+		 * on different processors so we can't interfere with them.
+		 * So we update the list atomically without locking it.
+		 * -- Cort
+		 */
+		/* turn cache on for this page */
+		pte_cache(*pte);
+		flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
+		
+		/* atomically add this page to the list */
+		asm (	"101:lwarx  %0,0,%1\n"  /* reserve zero_list */
+			"    stw    %0,0(%2)\n" /* update *pageptr */
+#ifdef __SMP__
+			"    sync\n"            /* let store settle */
+#endif			
+			"    mr     %0,%2\n"    /* update zero_list in reg */
+			"    stwcx. %2,0,%1\n"  /* update zero_list in mem */
+			"    bne-   101b\n"     /* if lost reservation try again */
+			: "=&r" (zero_list)
+			: "r" (&zero_list), "r" (pageptr)
+			: "cc" );
+		/*
+		 * This variable is used in the above loop and nowhere
+		 * else so the worst that could happen is we would
+		 * zero out one more or one less page than we want
+		 * per processor on the machine.  This is because
+		 * we could add our page to the list but not have
+		 * zerocount updated yet when another processor
+		 * reads it.  -- Cort
+		 */
+		atomic_inc((atomic_t *)&zerocount);
+		atomic_inc((atomic_t *)&zerototal);
+retry:	
+		schedule();
+	}
+}
+
+int power_saved(void *unused)
+{
+	unsigned long msr, hid0;
+	sprintf(current->comm, "power_saved (idle)");
+	current->blocked = ~0UL;
+	
+	printk("Power saving daemon started\n");
+	
+	__sti();
+	while (1)
+	{
+		/* don't want to be pre-empted by swapper */
+		current->priority = -99;
+		current->counter = -99;
+		/* go ahead and wakeup page_zerod() */
+		wake_up(&page_zerod_wait);
+		schedule();
+		asm volatile(
+			/* clear powersaving modes and set nap mode */
+			"mfspr %3,1008 \n\t"
+			"andc  %3,%3,%4 \n\t"
+			"or    %3,%3,%5 \n\t"
+			"mtspr 1008,%3 \n\t"
+			/* enter the mode */
+			"mfmsr %0 \n\t"
+			"oris  %0,%0,%2 \n\t"
+			"sync \n\t"
+			"mtmsr %0 \n\t"
+			"isync \n\t"
+			: "=&r" (msr)
+			: "0" (msr), "i" (MSR_POW>>16),
+			"r" (hid0),
+			"r" (HID0_DOZE|HID0_NAP|HID0_SLEEP),
+			"r" (HID0_NAP));
+		/*
+		 * The ibm carolina spec says that the eagle memory
+		 * controller will detect the need for a snoop
+		 * and wake up the processor so we don't need to
+		 * check for cache operations that need to be
+		 * snooped.  The ppc book says the run signal
+		 * must be asserted while napping for this though.
+		 *
+		 * Paul, what do you know about the pmac here?
+		 * -- Cort
+		 */
+		schedule();
+	}
+}
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.1.50/linux/arch/ppc/kernel/irq.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/irq.c	Sat Aug 16 09:51:08 1997
@@ -1,13 +1,13 @@
 /*
  *  arch/ppc/kernel/irq.c
  *
- *  Power Macintosh version
- *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
- *
  *  Derived from arch/i386/kernel/irq.c
  *    Copyright (C) 1992 Linus Torvalds
  *  Adapted from arch/i386 by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu) 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *  Updated and modified by Cort Dougan (cort@cs.nmt.edu)
+ *  Adapted for Power Macintosh by Paul Mackerras
+ *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
  *
  * This file contains the code used by various IRQ handling routines:
  * asking for different IRQ's should be done through these routines
@@ -15,11 +15,7 @@
  * shouldn't result in any weird surprises, and installing new handlers
  * should be easier.
  */
-	
-/*
- * IRQ's are in fact implemented a bit like signal handlers for the kernel.
- * Naturally it's not a 1:1 relation, but there are similarities.
- */
+
 
 #include <linux/ptrace.h>
 #include <linux/errno.h>
@@ -30,20 +26,15 @@
 #include <linux/interrupt.h>
 #include <linux/timex.h>
 #include <linux/config.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/bitops.h>
 
-#define IRQ_FLAG	((unsigned *)0xf3000020)
-#define IRQ_ENABLE	((unsigned *)0xf3000024)
-#define IRQ_ACK		((unsigned *)0xf3000028)
-#define IRQ_LEVEL	((unsigned *)0xf300002c)
-
-#define KEYBOARD_IRQ	20	/* irq number for command-power interrupt */
-
-#undef SHOW_IRQ 1
+#undef SHOW_IRQ
 
 unsigned lost_interrupts = 0;
 
@@ -51,100 +42,114 @@
 static struct irqaction irq_action[32];
 
 /*
- * This contains the irq mask for both irq controllers
+ * These are set to the appropriate functions by init_IRQ()
  */
-static unsigned int cached_irq_mask = 0xffff;
-
-#define cached_21	(((char *)(&cached_irq_mask))[0])
-#define cached_A1	(((char *)(&cached_irq_mask))[1])
-
+void (*mask_and_ack_irq)(int irq_nr);
+void (*set_irq_mask)(int irq_nr);
 
+static unsigned int cached_irq_mask = 0xffffffff;
+#define cached_21	(((char *)(&cached_irq_mask))[3])
+#define cached_A1	(((char *)(&cached_irq_mask))[2])
+static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
 int __ppc_bh_counter;
 
-void *null_handler(int,void *,struct pt_regs *);
+/* prep */
+#define PREP_IRQ_MASK	(((unsigned int)cached_A1)<<8) | (unsigned int)cached_21
+extern unsigned long route_pci_interrupts(void);
 
-/*
- * disable and enable intrs in software.  This is used
- * from the non-realtime parts of Linux to disable interrupts.
- * The realtime part disables/enables intrs in the hardware.
- * -- Cort
- */
-unsigned long soft_intr_enable = 1;
-void _soft_cli(void)
-{
-	soft_intr_enable = 0;
-}
+/* pmac */
+#define IRQ_FLAG	((unsigned *)0xf3000020)
+#define IRQ_ENABLE	((unsigned *)0xf3000024)
+#define IRQ_ACK		((unsigned *)0xf3000028)
+#define IRQ_LEVEL	((unsigned *)0xf300002c)
+#define KEYBOARD_IRQ	20	/* irq number for command-power interrupt */
+#define PMAC_IRQ_MASK	(~ld_le32(IRQ_ENABLE))
 
-void _soft_sti(void)
+void prep_mask_and_ack_irq(int irq_nr)
 {
-	soft_intr_enable = 1;
-	if ( lost_interrupts )
-	{
-		printk("lost_interrupts from _soft_sti() %x\n",lost_interrupts);
-		fake_interrupt();
+	spin_lock(&irq_controller_lock);
+	cached_irq_mask |= 1 << irq_nr;
+	if (irq_nr > 7) {
+		inb(0xA1);	/* DUMMY */
+		outb(cached_A1,0xA1);
+		outb(0x62,0x20);	/* Specific EOI to cascade */
+		/*outb(0x20,0xA0);*/
+		outb(0x60|(irq_nr-8), 0xA0); /* specific eoi */
+	} else {
+		inb(0x21);	/* DUMMY */
+		outb(cached_21,0x21);
+		/*outb(0x20,0x20);*/
+		outb(0x60|irq_nr,0x20); /* specific eoi */
+		  
 	}
+	spin_unlock(&irq_controller_lock);
 }
 
-void *
-null_handler(int a, void *b, struct pt_regs *regs)
+void pmac_mask_and_ack_irq(int irq_nr)
 {
-	/*printk("irq.c: null_handler() called.  Should not have happened.\n");*/
+	spin_lock(&irq_controller_lock);
+	cached_irq_mask |= 1 << irq_nr;
+	out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
+	out_le32(IRQ_ACK, 1U << irq_nr);
+	spin_unlock(&irq_controller_lock);
 }
 
-void
-disable_irq(unsigned int irq_nr)
+void prep_set_irq_mask(int irq_nr)
 {
-	int s = _disable_interrupts();
-	unsigned char mask;
-
-#ifdef CONFIG_PMAC
-	out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
-#else /* CONFIG_PMAC */
-	mask = 1 << (irq_nr & 7);
-	if (irq_nr < 8)
-	{
-		cached_21 |= mask;
-		outb(cached_21,0x21);
-	} else
-	{
-		cached_A1 |= mask;
+	if (irq_nr > 7) {
 		outb(cached_A1,0xA1);
-	}	
-#endif	/* CONFIG_PMAC */
-	_enable_interrupts(s);
+	} else {
+		outb(cached_21,0x21);
+	}
 }
 
-void
-enable_irq(unsigned int irq_nr)
+void pmac_set_irq_mask(int irq_nr)
 {
-	int s = _disable_interrupts();
-#ifdef CONFIG_PMAC
-	unsigned bit = 1U << irq_nr;
-	
-	out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) & ~(1 << irq_nr));
-	out_le32(IRQ_ENABLE, ld_le32(IRQ_ENABLE) | bit);
-
+	/* this could be being enabled or disabled - so use cached_irq_mask */
+	out_le32(IRQ_ENABLE, ~cached_irq_mask /* enable all unmasked */ );
 	/*
 	 * Unfortunately, setting the bit in the enable register
 	 * when the device interrupt is already on *doesn't* set
 	 * the bit in the flag register or request another interrupt.
 	 */
-	if ((ld_le32(IRQ_LEVEL) & bit) && !(ld_le32(IRQ_FLAG) & bit))
-		lost_interrupts |= bit;
-#else /* CONFIG_PMAC */
-	if (irq_nr < 8) {
-		cached_21 &= ~(1 << (irq_nr & 7));
-		outb(cached_21,0x21);
-	} else
-	{
-		cached_A1 &= ~(1 << (irq_nr-8 & 7));
-		outb(cached_A1,0xA1);
-	}	
-#endif	/* CONFIG_PMAC */
+	if ((ld_le32(IRQ_LEVEL) & (1UL<<irq_nr)) && !(ld_le32(IRQ_FLAG) & (1UL<<irq_nr)))
+		lost_interrupts |= (1UL<<irq_nr);
+}
 
-	_enable_interrupts(s);
+/*
+ * These have to be protected by the spinlock
+ * before being called.
+ */
+static inline void mask_irq(unsigned int irq_nr)
+{
+	cached_irq_mask |= 1 << irq_nr;
+	set_irq_mask(irq_nr);
 }
 
+static inline void unmask_irq(unsigned int irq_nr)
+{
+	cached_irq_mask &= ~(1 << irq_nr);
+	set_irq_mask(irq_nr);
+}
+
+void disable_irq(unsigned int irq_nr)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&irq_controller_lock, flags);
+	mask_irq(irq_nr);
+	spin_unlock_irqrestore(&irq_controller_lock, flags);
+	synchronize_irq();
+}
+
+void enable_irq(unsigned int irq_nr)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&irq_controller_lock, flags);
+	unmask_irq(irq_nr);
+	spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
 
 int get_irq_list(char *buf)
 {
@@ -153,7 +158,7 @@
 
 	for (i = 0 ; i < NR_IRQS ; i++) {
 		action = irq_action + i;
-		if (!action || !action->handler) 
+		if (!action || !action->handler)
 			continue;
 		len += sprintf(buf+len, "%2d: %10u   %s",
 			i, kstat.interrupts[i], action->name);
@@ -162,152 +167,99 @@
 		}
 		len += sprintf(buf+len, "\n");
 	}
-/*
- *	Linus - should you add NMI counts here ?????
- */
 #ifdef __SMP_PROF__
 	len+=sprintf(buf+len, "IPI: %8lu received\n",
 		ipi_count);
-#endif		
+#endif
 	return len;
 }
 
-asmlinkage void handle_IRQ(struct pt_regs *regs)
+asmlinkage void do_IRQ(struct pt_regs *regs)
 {
 	int irq;
-	unsigned bits;
+	unsigned long bits;
 	struct irqaction *action;
 	int cpu = smp_processor_id();
+	int status;
 
 	hardirq_enter(cpu);
 
-#ifdef CONFIG_PMAC 
-	bits = ld_le32(IRQ_FLAG) | lost_interrupts;
-	lost_interrupts = 0;
-	
-	for (irq = NR_IRQS; irq >= 0; --irq)
-		if (bits & (1U << irq))
-			break;
-#else /* CONFIG_PMAC */
-#if 1
-	if ( lost_interrupts )
+	if ( _machine == _MACH_Pmac )
 	{
-		irq = ffz(~lost_interrupts);
-		lost_interrupts &= ~irq;
-		goto retry;
-	}
-	outb(0x0C, 0x20);
-	irq = inb(0x20) & 7;
-	if (irq == 2)
-	{
-retry_cascade:		
-		outb(0x0C, 0xA0);
-		irq = inb(0xA0);
-		/* if no intr left */
-		if ( !(irq & 128 ) )
-			goto out;
-		irq = (irq&7) + 8;
+		bits = ld_le32(IRQ_FLAG) | lost_interrupts;
+		lost_interrupts = 0;
 	}
-retry:
-#else
-	/* get the irr from the intr controller */
-	outb(0x0A, 0x20);
-	bits = inb(0x20);
-	/* handle cascade */
-	if ( bits  ) 
+	else /* prep */
 	{
-		bits &= 4;
-		outb(0x0A, 0xA0);
-		bits = inb(0xA0)<<8;
-	}
-	/* get lost interrupts */
-	bits |= lost_interrupts;
-	/* save intrs that are masked out */
-	lost_interrupts = bits & cached_irq_mask;
-	/* get rid of intrs being masked */
-	bits &= ~cached_irq_mask;
-        /* non-specifc eoi */
-	outb(0x20,0x20);
-	if ( bits & 0xff00 )
-		outb(0x20,0xA0);
-	
-	printk("bits %04X lost %04X mask %04x\n",
-	       bits, lost_interrupts,cached_irq_mask);
+#if 1
+		outb(0x0C, 0x20);
+		irq = inb(0x20) & 7;
+		if (irq == 2)
+		{
+retry_cascade:
+			outb(0x0C, 0xA0);
+			irq = inb(0xA0);
+			/* if no intr left */
+			if ( !(irq & 128 ) )
+				goto out;
+			irq = (irq&7) + 8;
+		}
+		bits = 1UL << irq;
+#else
+		/*
+		 * get the isr from the intr controller since
+		 * the bit in the irr has been cleared
+		 */
+		outb(0x0a, 0x20);
+		bits = inb(0x20)&0xff;
+		/* handle cascade */
+		if ( bits & 4 )
+		{
+			bits &= ~4UL;
+			outb(0x0a, 0xA0);
+			bits |= inb(0xA0)<<8;
+		}
+		/* ignore masked irqs */
+		bits &= ~cached_irq_mask;
+#endif
+	}
 	
-	for (irq = NR_IRQS; irq >= 0; --irq)
+	for (irq = NR_IRQS - 1; irq >= 0; --irq)
 		if (bits & (1U << irq))
 			break;
-#endif
-#endif	/* CONFIG_PMAC */
-	
+
 	if (irq < 0) {
-		printk("Bogus interrupt from PC = %lx, irq %d\n",regs->nip,irq);
+		printk("Bogus interrupt from PC = %lx\n", regs->nip);
 		goto out;
 	}
 
-#ifdef CONFIG_PMAC 
-	out_le32(IRQ_ACK, 1U << irq);
-#else /* CONFIG_PMAC */
-        /* mask out the irq while handling it */	
-	disable_irq(irq); 
-	/*
-	 * send eoi to interrupt controller right away or lower
-	 * priority intrs would be ignored even if with intrs enabled
-	 */
-	if (irq > 7)
-	{
-		outb(0xE0|(irq-8), 0xA0);
-		outb(0xE2, 0x20);
-	} else
-	{
-		outb(0xE0|irq, 0x20);
-	}
-#endif /* !CONFIG_PMAC */
+	mask_and_ack_irq(irq);
 
-	/*
-	 * now that we've acked the irq, if intrs are disabled in software
-	 * we're in the real-time system and non-rt linux has disabled them
-	 * so we just queue it up and return -- Cort
-	 */
-	if ( ! soft_intr_enable ) 
-	{
-		lost_interrupts |= 1UL << irq;
-		/* can't printk - kernel expects intrs off! */
-		/*printk("irq %d while intrs soft disabled\n", irq);*/
-		goto out;
-	}
-	
-	action = irq + irq_action;
+	status = 0;
+	action = irq_action + irq;
 	kstat.interrupts[irq]++;
-	if (action->handler) {
+	if ( action )
+	{
+		if (!(action->flags & SA_INTERRUPT))
+			__sti();
+		status |= action->flags;
 		action->handler(irq, action->dev_id, regs);
-		_disable_interrupts(); /* in case the handler turned them on */
+		/*if (status & SA_SAMPLE_RANDOM)
+			add_interrupt_randomness(irq);*/
+		__cli(); /* in case the handler turned them on */
+		spin_lock(&irq_controller_lock);
+		unmask_irq(irq);
+		spin_unlock(&irq_controller_lock);
 	} else {
 		disable_irq( irq );
 	}
-#ifdef CONFIG_PREP
-	/* re-enable if the interrupt was good and isn't one-shot */
-	if ( action->handler && !(action->flags & SA_ONESHOT) )
-		enable_irq(irq);
+	
 	/* make sure we don't miss any cascade intrs due to eoi-ing irq 2 */
-	if ( irq > 7 )
+	if ( (_machine != _MACH_Pmac)/*prep*/ && (irq > 7) )
 		goto retry_cascade;
-#endif
-	
-	hardirq_exit(cpu);
-	/*
-	 * This should be conditional: we should really get
-	 * a return code from the irq handler to tell us
-	 * whether the handler wants us to do software bottom
-	 * half handling or not..
-	 */
-	if (1)
-		if (bh_active & bh_mask)
-			do_bottom_half();
-        return;
+	/* do_bottom_half is called if necessary from int_return in head.S */
 out:
 	hardirq_exit(cpu);
-
 }
 
 int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
@@ -315,13 +267,13 @@
 {
 	struct irqaction * action;
 	unsigned long flags;
-	
-#ifdef SHOW_IRQ	
+
+#ifdef SHOW_IRQ
 	printk("request_irq(): irq %d handler %08x name %s dev_id %04x\n",
 	       irq,handler,devname,dev_id);
 #endif /* SHOW_IRQ */
-	
-	if (irq > NR_IRQS)
+
+	if (irq >= NR_IRQS)
 		return -EINVAL;
 	action = irq + irq_action;
 	if (action->handler)
@@ -339,17 +291,16 @@
 	restore_flags(flags);
 	return 0;
 }
-		
 void free_irq(unsigned int irq, void *dev_id)
 {
 	struct irqaction * action = irq + irq_action;
 	unsigned long flags;
 
-#ifdef SHOW_IRQ	
+#ifdef SHOW_IRQ
 	printk("free_irq(): irq %d dev_id %04x\n", irq, dev_id);
 #endif /* SHOW_IRQ */
-	
-	if (irq > NR_IRQS) {
+
+	if (irq >= NR_IRQS) {
 		printk("Trying to free IRQ%d\n",irq);
 		return;
 	}
@@ -370,114 +321,85 @@
 
 unsigned long probe_irq_on (void)
 {
-	unsigned int i, irqs = 0, irqmask;
-	unsigned long delay;
-
-	/* first, snaffle up any unassigned irqs */
-	for (i = 15; i > 0; i--) {
-		if (!request_irq(i, null_handler, SA_ONESHOT, "probe", NULL)) {
-			enable_irq(i);
-			irqs |= (1 << i);
-		}
-	}
-
-	/* wait for spurious interrupts to mask themselves out again */
-	for (delay = jiffies + 2; delay > jiffies; );	/* min 10ms delay */
-
-	/* now filter out any obviously spurious interrupts */
-	irqmask = (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21;
-	for (i = 15; i > 0; i--) {
-		if (irqs & (1 << i) & irqmask) {
-			irqs ^= (1 << i);
-			free_irq(i, NULL);
-		}
-	}
-#ifdef DEBUG
-	printk("probe_irq_on:  irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
-#endif
-	return irqs;
+	return 0;
 }
 
 int probe_irq_off (unsigned long irqs)
 {
-	unsigned int i, irqmask;
-
-	irqmask = (((unsigned int)cached_A1)<<8) | (unsigned int)cached_21;
-	for (i = 15; i > 0; i--) {
-		if (irqs & (1 << i)) {
-			free_irq(i, NULL);
-		}
-	}
-#ifdef SHOW_IRQ
-	printk("probe_irq_off: irqs=0x%04x irqmask=0x%04x\n", irqs, irqmask);
-#endif
-	irqs &= irqmask;
-	if (!irqs)
-		return 0;
-	i = ffz(~irqs);
-	if (irqs != (irqs & (1 << i)))
-		i = -i;
-	return i;
+	return 0;
 }
 
-void init_IRQ(void)
+__initfunc(void init_IRQ(void))
 {
-#ifdef CONFIG_PMAC  
 	extern void xmon_irq(int, void *, struct pt_regs *);
 
-	*IRQ_ENABLE = 0;
-	request_irq(KEYBOARD_IRQ, xmon_irq, 0, "NMI", 0);
-#else /* CONFIG_PMAC */
-	/* Initialize interrupt controllers */
-	outb(0x11, 0x20); /* Start init sequence */
-	outb(0x40, 0x21); /* Vector base */
-#if 1
-	outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
-#else
-	outb(0x0C, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
-#endif	
-	
-	outb(0x01, 0x21); /* Select 8086 mode */
-	outb(0xFF, 0x21); /* Mask all */
-
-	outb(0x11, 0xA0); /* Start init sequence */
-	outb(0x48, 0xA1); /* Vector base */
-#if 1
-	outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
-#else
-	outb(0x0A, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
-#endif
-	outb(0x01, 0xA1); /* Select 8086 mode */
-	outb(0xFF, 0xA1); /* Mask all */
+	if ( _machine == _MACH_Pmac )
+	{
+		mask_and_ack_irq = pmac_mask_and_ack_irq;
+		set_irq_mask = pmac_set_irq_mask;
+		
+		*IRQ_ENABLE = 0;
+#ifdef CONFIG_XMON
+		request_irq(KEYBOARD_IRQ, xmon_irq, 0, "NMI", 0);
+#endif	/* CONFIG_XMON */
+	}
+	else /* prep */
+	{
+		mask_and_ack_irq = prep_mask_and_ack_irq;
+		set_irq_mask = prep_set_irq_mask;
+		
+		/* init master interrupt controller */
+		outb(0x11, 0x20); /* Start init sequence */
+		outb(0x40, 0x21); /* Vector base */
+		/*outb(0x04, 0x21);*/ /* edge tiggered, Cascade (slave) on IRQ2 */
+		outb(0x0C, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
+		outb(0x01, 0x21); /* Select 8086 mode */
+		outb(0xFF, 0x21); /* Mask all */
+
+		/* init slave interrupt controller */
+		outb(0x11, 0xA0); /* Start init sequence */
+		outb(0x48, 0xA1); /* Vector base */
+		/*outb(0x02, 0xA1);*/ /* edge triggered, Cascade (slave) on IRQ2 */
+		outb(0x0A, 0x21); /* level triggered, Cascade (slave) on IRQ2 */
+		outb(0x01, 0xA1); /* Select 8086 mode */
+		outb(0xFF, 0xA1); /* Mask all */
+
+		/*
+		 * According to the Carolina spec from ibm irq's 0,1,2, and 8
+		 * must be edge triggered.  Also, the pci intrs must be level
+		 * triggered and _only_ isa intrs can be level sensitive
+		 * which are 3-7,9-12,14-15. 13 is special - it can be level.
+		 *
+		 * power on default is 0's in both regs - all edge.
+		 *
+		 * These edge/level control regs allow edge/level status
+		 * to be decided on a irq basis instead of on a PIC basis.
+		 * It's still pretty ugly.
+		 * - Cort
+		 */
+		{
+			unsigned char irq_mode1 = 0, irq_mode2 = 0;
+			irq_mode1 = 0; /* to get rid of compiler warnings */
+			/*
+			 * On Carolina, irq 15 and 13 must be level (scsi/ide/net).
+			 */
+			if ( _machine == _MACH_IBM )
+				irq_mode2 |= 0xa0;
+			/*
+			 * Sound on the Powerstack reportedly needs to be edge triggered
+			 */
+			if ( _machine == _MACH_Motorola )
+			{}
 
-	/*
-	 * Program level mode for irq's that 'can' be level triggered.
-	 * This does not effect irq's 0,1,2 and 8 since they must be
-	 * edge triggered. This is not the PIC controller.  The default
-	 * here is for edge trigger mode.  -- Cort
-	 */
-#if 0	
-	outb(0xf8, 0x4d0); /* level triggered */
-	outb(0xff, 0x4d1);
-#endif
-#if 0	
-	outb(0x00, 0x4D0); /* All edge triggered */
-	outb(0xCF, 0x4D1); /* Trigger mode */
-#endif
-	outb(cached_A1, 0xA1);
-	outb(cached_21, 0x21);
-	if (request_irq(2, null_handler, SA_INTERRUPT, "cascade", NULL))
-		printk("Unable to get IRQ2 for cascade\n");
-	enable_irq(2);  /* Enable cascade interrupt */
-	
-#define TIMER0_COUNT 0x40
-#define TIMER_CONTROL 0x43
-	/* set timer to periodic mode */
-	outb_p(0x34,TIMER_CONTROL);		/* binary, mode 2, LSB/MSB, ch 0 */
-	/* set the clock to ~100 Hz */
-	outb_p(LATCH & 0xff , TIMER0_COUNT);	/* LSB */
-	outb(LATCH >> 8 , TIMER0_COUNT);	/* MSB */
+			/*outb( irq_mode1 , 0x4d0 );
+			  outb( irq_mode2 , 0x4d1 );*/
+		}
+		outb(cached_A1, 0xA1);
+		outb(cached_21, 0x21);
+		if (request_irq(2, no_action, SA_INTERRUPT, "cascade", NULL) != 0)
+			panic("Could not allocate cascade IRQ!");
+		enable_irq(2);  /* Enable cascade interrupt */
 
-	route_pci_interrupts();
-#endif	/* CONFIG_PMAC */
+		route_pci_interrupts();
+	}
 }
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/ksyms.c linux/arch/ppc/kernel/ksyms.c
--- v2.1.50/linux/arch/ppc/kernel/ksyms.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/ksyms.c	Wed Dec 31 16:00:00 1969
@@ -1,40 +0,0 @@
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/smp.h>
-#include <linux/elfcore.h>
-#include <linux/sched.h>
-
-#include <asm/semaphore.h>
-#include <asm/processor.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-void transfer_to_handler();
-void int_return();
-void syscall_trace();
-void handle_IRQ();
-void MachineCheckException();
-void AlignmentException();
-void ProgramCheckException();
-void SingleStepException();
-void FloatingPointCheckException();
-void sys_sigreturn();
-unsigned long sys_call_table[];
-
-extern struct task_struct *current_set[1];
-
-/* platform dependent support */
-EXPORT_SYMBOL(current_set);
-EXPORT_SYMBOL(do_signal);
-EXPORT_SYMBOL(syscall_trace);
-EXPORT_SYMBOL(transfer_to_handler);
-EXPORT_SYMBOL(int_return);
-EXPORT_SYMBOL(handle_IRQ);
-EXPORT_SYMBOL(init_task_union);
-EXPORT_SYMBOL(MachineCheckException);
-EXPORT_SYMBOL(AlignmentException);
-EXPORT_SYMBOL(ProgramCheckException);
-EXPORT_SYMBOL(SingleStepException);
-EXPORT_SYMBOL(FloatingPointCheckException);
-EXPORT_SYMBOL(sys_sigreturn);
-EXPORT_SYMBOL(sys_call_table);
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- v2.1.50/linux/arch/ppc/kernel/misc.S	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/misc.S	Sat Aug 16 09:51:08 1997
@@ -64,6 +64,7 @@
 	mtmsr	r3		/* Update machine state */
 	blr
 
+#if 0
 /*
  * Restore 'flags'
  *	__restore_flags(long val)
@@ -79,11 +80,13 @@
 	mtmsr	r3
 	isync
 	blr
-
+#endif
+	
 /*
  * We were about to enable interrupts but we have to simulate
  * some interrupts that were lost by enable_irq first.
  */
+	.globl do_lost_interrupts
 do_lost_interrupts:
 	stwu	r1,-16(r1)
 	mflr	r0
@@ -243,7 +246,6 @@
 	bdnz	00b
 	blr	
 
-#ifdef CONFIG_PMAC
 _GLOBAL(ide_insw)
 	mtctr	r5
 	subi	r4,r4,2
@@ -259,7 +261,6 @@
 	sthx	r5,0,r3	
 	bdnz	00b
 	blr	
-#endif
 
 /*
  * Extended precision shifts
@@ -298,7 +299,7 @@
 _GLOBAL(_get_SP)
 	mr	r3,r1		/* Close enough */
 	blr
-	
+
 _GLOBAL(_get_PVR)
 	mfspr	r3,PVR
 	blr
@@ -308,6 +309,7 @@
 	lfs	0,0(r3)
 	stfd	0,0(r4)
 	blr
+
 /*
  * Fetch the current SR register
  *   get_SR(int index)
@@ -317,7 +319,6 @@
 	mr	r3,r4
 	blr
 
-	
 _GLOBAL(cvt_df)
 cvt_df:
 	lfd	0,0(r3)
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/mk_defs.c linux/arch/ppc/kernel/mk_defs.c
--- v2.1.50/linux/arch/ppc/kernel/mk_defs.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/mk_defs.c	Sat Aug 16 09:51:08 1997
@@ -29,7 +29,6 @@
 void
 main(void)
 {
-	/*DEFINE(KERNELBASE, KERNELBASE);*/
 	DEFINE(STATE, offsetof(struct task_struct, state));
 	DEFINE(NEXT_TASK, offsetof(struct task_struct, next_task));
 	DEFINE(COUNTER, offsetof(struct task_struct, counter));
@@ -37,54 +36,20 @@
 	DEFINE(SIGNAL, offsetof(struct task_struct, signal));
 	DEFINE(TSS, offsetof(struct task_struct, tss));
 	DEFINE(KSP, offsetof(struct thread_struct, ksp));
-	DEFINE(PG_TABLES, offsetof(struct thread_struct, pg_tables));
-#ifdef CONFIG_PMAC	
-	DEFINE(LAST_PC, offsetof(struct thread_struct, last_pc));
-	DEFINE(USER_STACK, offsetof(struct thread_struct, user_stack));
-#endif	
+	/*DEFINE(PG_TABLES, offsetof(struct thread_struct, pg_tables));*/
+	DEFINE(MM, offsetof(struct task_struct, mm));
+	DEFINE(PGD, offsetof(struct mm_struct, pgd));
 	DEFINE(LAST_SYSCALL, offsetof(struct thread_struct, last_syscall));
 	DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
 	DEFINE(PF_TRACESYS, PF_TRACESYS);
 	DEFINE(TASK_FLAGS, offsetof(struct task_struct, flags));
 	DEFINE(TSS_FPR0, offsetof(struct thread_struct, fpr[0]));
-#if 0
-	DEFINE(TSS_FPR1, offsetof(struct thread_struct, fpr[1]));
-	DEFINE(TSS_FPR2, offsetof(struct thread_struct, fpr[2]));
-	DEFINE(TSS_FPR3, offsetof(struct thread_struct, fpr[3]));
-	DEFINE(TSS_FPR4, offsetof(struct thread_struct, fpr[4]));
-	DEFINE(TSS_FPR5, offsetof(struct thread_struct, fpr[5]));
-	DEFINE(TSS_FPR6, offsetof(struct thread_struct, fpr[6]));
-	DEFINE(TSS_FPR7, offsetof(struct thread_struct, fpr[7]));
-	DEFINE(TSS_FPR8, offsetof(struct thread_struct, fpr[8]));
-	DEFINE(TSS_FPR9, offsetof(struct thread_struct, fpr[9]));
-	DEFINE(TSS_FPR10, offsetof(struct thread_struct, fpr[10]));
-	DEFINE(TSS_FPR11, offsetof(struct thread_struct, fpr[11]));
-	DEFINE(TSS_FPR12, offsetof(struct thread_struct, fpr[12]));
-	DEFINE(TSS_FPR13, offsetof(struct thread_struct, fpr[13]));
-	DEFINE(TSS_FPR14, offsetof(struct thread_struct, fpr[14]));
-	DEFINE(TSS_FPR15, offsetof(struct thread_struct, fpr[15]));
-	DEFINE(TSS_FPR16, offsetof(struct thread_struct, fpr[16]));
-	DEFINE(TSS_FPR17, offsetof(struct thread_struct, fpr[17]));
-	DEFINE(TSS_FPR18, offsetof(struct thread_struct, fpr[18]));
-	DEFINE(TSS_FPR19, offsetof(struct thread_struct, fpr[19]));
-	DEFINE(TSS_FPR20, offsetof(struct thread_struct, fpr[20]));
-	DEFINE(TSS_FPR21, offsetof(struct thread_struct, fpr[21]));
-	DEFINE(TSS_FPR22, offsetof(struct thread_struct, fpr[22]));
-	DEFINE(TSS_FPR23, offsetof(struct thread_struct, fpr[23]));
-	DEFINE(TSS_FPR24, offsetof(struct thread_struct, fpr[24]));
-	DEFINE(TSS_FPR25, offsetof(struct thread_struct, fpr[25]));
-	DEFINE(TSS_FPR26, offsetof(struct thread_struct, fpr[26]));
-	DEFINE(TSS_FPR27, offsetof(struct thread_struct, fpr[27]));
-	DEFINE(TSS_FPR28, offsetof(struct thread_struct, fpr[28]));
-	DEFINE(TSS_FPR29, offsetof(struct thread_struct, fpr[29]));
-	DEFINE(TSS_FPR30, offsetof(struct thread_struct, fpr[30]));
-	DEFINE(TSS_FPR31, offsetof(struct thread_struct, fpr[31]));
-#endif
 	DEFINE(TSS_FPSCR, offsetof(struct thread_struct, fpscr));
 	/* Interrupt register frame */
 	DEFINE(TASK_UNION_SIZE, sizeof(union task_union));
 	DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
 	DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
+	/* in fact we only use gpr0 - gpr9 and gpr20 - gpr23 */
 	DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
 	DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
 	DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/pci-bridge.c linux/arch/ppc/kernel/pci-bridge.c
--- v2.1.50/linux/arch/ppc/kernel/pci-bridge.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/pci-bridge.c	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,428 @@
+/*
+ * Support for PCI bridges found on Power Macintoshes.
+ * At present the "bandit" and "chaos" bridges are supported.
+ * Fortunately you access configuration space in the same
+ * way with either bridge.
+ *
+ * Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+
+struct bridge_data {
+	volatile unsigned int *cfg_addr;
+	volatile unsigned char *cfg_data;
+	void *io_base;
+	int bus_number;
+	int max_bus;
+	struct bridge_data *next;
+	struct device_node *node;
+};
+
+static struct bridge_data **bridges, *bridge_list;
+static int max_bus;
+
+static void add_bridges(struct device_node *dev, unsigned long *mem_ptr);
+
+/*
+ * Magic constants for enabling cache coherency in the bandit/PSX bridge.
+ */
+#define APPLE_VENDID	0x106b
+#define BANDIT_DEVID	1
+#define BANDIT_REVID	3
+
+#define BANDIT_DEVNUM	11
+#define BANDIT_MAGIC	0x50
+#define BANDIT_COHERENT	0x40
+
+/*
+ * For a bandit bridge, turn on cache coherency if necessary.
+ * N.B. we can't use pcibios_*_config_* here because bridges[]
+ * is not initialized yet.
+ */
+static void init_bandit(struct bridge_data *bp)
+{
+	unsigned int vendev, magic;
+	int rev;
+
+	/* read the word at offset 0 in config space for device 11 */
+	out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID);
+	udelay(2);
+	vendev = in_le32((volatile unsigned int *)bp->cfg_data);
+	if (vendev != (BANDIT_DEVID << 16) + APPLE_VENDID) {
+		printk(KERN_WARNING "bandit isn't? (%x)\n", vendev);
+		return;
+	}
+
+	/* read the revision id */
+	out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID);
+	udelay(2);
+	rev = in_8(bp->cfg_data);
+	if (rev != BANDIT_REVID)
+		printk(KERN_WARNING "Unknown revision %d for bandit at %p\n",
+		       rev, bp->io_base);
+
+	/* read the word at offset 0x50 */
+	out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC);
+	udelay(2);
+	magic = in_le32((volatile unsigned int *)bp->cfg_data);
+	if ((magic & BANDIT_COHERENT) != 0)
+		return;
+	magic |= BANDIT_COHERENT;
+	udelay(2);
+	out_le32((volatile unsigned int *)bp->cfg_data, magic);
+	printk(KERN_INFO "Cache coherency enabled for bandit/PSX at %p\n",
+	       bp->io_base);
+}
+
+unsigned long pmac_find_bridges(unsigned long mem_start, unsigned long mem_end)
+{
+	int bus;
+	struct bridge_data *bridge;
+
+	bridge_list = 0;
+	max_bus = 0;
+	add_bridges(find_devices("bandit"), &mem_start);
+	add_bridges(find_devices("chaos"), &mem_start);
+	bridges = (struct bridge_data **) mem_start;
+	mem_start += (max_bus + 1) * sizeof(struct bridge_data *);
+	memset(bridges, 0, (max_bus + 1) * sizeof(struct bridge_data *));
+	for (bridge = bridge_list; bridge != NULL; bridge = bridge->next)
+		for (bus = bridge->bus_number; bus <= bridge->max_bus; ++bus)
+			bridges[bus] = bridge;
+
+	return mem_start;
+}
+
+static void add_bridges(struct device_node *dev, unsigned long *mem_ptr)
+{
+	int *bus_range;
+	int len;
+	struct bridge_data *bp;
+
+	for (; dev != NULL; dev = dev->next) {
+		if (dev->n_addrs < 1) {
+			printk(KERN_WARNING "Can't use %s: no address\n",
+			       dev->full_name);
+			continue;
+		}
+		bus_range = (int *) get_property(dev, "bus-range", &len);
+		if (bus_range == NULL || len < 2 * sizeof(int)) {
+			printk(KERN_WARNING "Can't get bus-range for %s\n",
+			       dev->full_name);
+			continue;
+		}
+		if (bus_range[1] == bus_range[0])
+			printk(KERN_INFO "PCI bus %d", bus_range[0]);
+		else
+			printk(KERN_INFO "PCI buses %d..%d", bus_range[0],
+			       bus_range[1]);
+		printk(" controlled by %s at %x\n",
+		       dev->name, dev->addrs[0].address);
+		bp = (struct bridge_data *) *mem_ptr;
+		*mem_ptr += sizeof(struct bridge_data);
+		bp->cfg_addr = (volatile unsigned int *)
+			(dev->addrs[0].address + 0x800000);
+		bp->cfg_data = (volatile unsigned char *)
+			(dev->addrs[0].address + 0xc00000);
+		bp->io_base = (void *) dev->addrs[0].address;
+		ioremap(dev->addrs[0].address, 0x800000);
+		bp->bus_number = bus_range[0];
+		bp->max_bus = bus_range[1];
+		bp->next = bridge_list;
+		bp->node = dev;
+		bridge_list = bp;
+		if (bp->max_bus > max_bus)
+			max_bus = bp->max_bus;
+
+		if (strcmp(dev->name, "bandit") == 0)
+			init_bandit(bp);
+	}
+}
+
+void *pci_io_base(unsigned int bus)
+{
+	struct bridge_data *bp;
+
+	if (bus > max_bus || (bp = bridges[bus]) == 0)
+		return 0;
+	return bp->io_base;
+}
+
+int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
+		   unsigned char *devfn_ptr)
+{
+	unsigned int *reg;
+	int len;
+
+	reg = (unsigned int *) get_property(dev, "reg", &len);
+	if (reg == 0 || len < 5 * sizeof(unsigned int)) {
+		/* doesn't look like a PCI device */
+		*bus_ptr = 0xff;
+		*devfn_ptr = 0xff;
+		return -1;
+	}
+	*bus_ptr = reg[0] >> 16;
+	*devfn_ptr = reg[0] >> 8;
+	return 0;
+}
+
+int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+				  unsigned char offset, unsigned char *val)
+{
+	struct bridge_data *bp;
+
+	*val = 0xff;
+	if (bus > max_bus || (bp = bridges[bus]) == 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	if (bus == bp->bus_number) {
+		if (dev_fn < (11 << 3))
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		out_le32(bp->cfg_addr,
+			 (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+			 + (offset & ~3));
+	} else {
+		out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+	}
+	udelay(2);
+	*val = in_8(bp->cfg_data + (offset & 3));
+
+	if (offset == PCI_INTERRUPT_LINE) {
+		/*
+		 * Open Firmware often doesn't initialize this
+		 * register properly, so we find the node and see
+		 * if it has an AAPL,interrupts property.
+		 */
+		struct device_node *node;
+		unsigned int *reg;
+
+		for (node = bp->node->child; node != 0; node = node->sibling) {
+			reg = (unsigned int *) get_property(node, "reg", 0);
+			if (reg == 0 || ((reg[0] >> 8) & 0xff) != dev_fn)
+				continue;
+			/* this is the node, see if it has interrupts */
+			if (node->n_intrs > 0)
+				*val = node->intrs[0];
+			break;
+		}
+	}
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+				  unsigned char offset, unsigned short *val)
+{
+	struct bridge_data *bp;
+
+	*val = 0xffff;
+	if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 1) != 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	if (bus == bp->bus_number) {
+		if (dev_fn < (11 << 3))
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		out_le32(bp->cfg_addr,
+			 (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+			 + (offset & ~3));
+	} else {
+		out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+	}
+	udelay(2);
+	*val = in_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+				   unsigned char offset, unsigned int *val)
+{
+	struct bridge_data *bp;
+
+	*val = 0xffffffff;
+	if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 3) != 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	if (bus == bp->bus_number) {
+		if (dev_fn < (11 << 3))
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		out_le32(bp->cfg_addr,
+			 (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+			 + offset);
+	} else {
+		out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+	}
+	udelay(2);
+	*val = in_le32((volatile unsigned int *)bp->cfg_data);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+				   unsigned char offset, unsigned char val)
+{
+	struct bridge_data *bp;
+
+	if (bus > max_bus || (bp = bridges[bus]) == 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	if (bus == bp->bus_number) {
+		if (dev_fn < (11 << 3))
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		out_le32(bp->cfg_addr,
+			 (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+			 + (offset & ~3));
+	} else {
+		out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+	}
+	udelay(2);
+	out_8(bp->cfg_data + (offset & 3), val);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+				   unsigned char offset, unsigned short val)
+{
+	struct bridge_data *bp;
+
+	if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 1) != 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	if (bus == bp->bus_number) {
+		if (dev_fn < (11 << 3))
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		out_le32(bp->cfg_addr,
+			 (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+			 + (offset & ~3));
+	} else {
+		out_le32(bp->cfg_addr, (dev_fn << 8) + (offset & ~3) + 1);
+	}
+	udelay(2);
+	out_le16((volatile unsigned short *)(bp->cfg_data + (offset & 3)), val);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+				    unsigned char offset, unsigned int val)
+{
+	struct bridge_data *bp;
+
+	if (bus > max_bus || (bp = bridges[bus]) == 0 || (offset & 3) != 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	if (bus == bp->bus_number) {
+		if (dev_fn < (11 << 3))
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		out_le32(bp->cfg_addr,
+			 (1UL << (dev_fn >> 3)) + ((dev_fn & 7) << 8)
+			 + offset);
+	} else {
+		out_le32(bp->cfg_addr, (dev_fn << 8) + offset + 1);
+	}
+	udelay(2);
+	out_le32((volatile unsigned int *)bp->cfg_data, val);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pmac_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+			     unsigned short index, unsigned char *bus_ptr,
+			     unsigned char *dev_fn_ptr)
+{
+	int bus, unit, fn, num, devfn;
+	unsigned int x, vendev;
+	unsigned char h;
+
+	if (vendor == 0xffff)
+		return PCIBIOS_BAD_VENDOR_ID;
+	vendev = (dev_id << 16) + vendor;
+	num = 0;
+	for (bus = 0; bus <= max_bus; ++bus) {
+		if (bridges[bus] == 0)
+			continue;
+		unit = fn = 0;
+		if (bus == bridges[bus]->bus_number)
+			unit = 11;
+		while (unit < 32) {
+			devfn = PCI_DEVFN(unit, fn);
+			if (pcibios_read_config_dword(bus, devfn,
+						      PCI_VENDOR_ID, &x)
+			    == PCIBIOS_SUCCESSFUL && x == vendev) {
+				if (index == num) {
+					*bus_ptr = bus;
+					*dev_fn_ptr = devfn;
+					return PCIBIOS_SUCCESSFUL;
+				}
+				++num;
+			}
+			if (fn != 0) {
+				if (++fn >= 8) {
+					++unit;
+					fn = 0;
+				}
+				continue;
+			}
+			if (pcibios_read_config_byte(bus, devfn,
+						     PCI_HEADER_TYPE, &h)
+			    == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0)
+				++fn;
+			else
+				++unit;
+		}
+	}
+	return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int pmac_pcibios_find_class(unsigned int class_code, unsigned short index,
+			    unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
+{
+	int bus, unit, fn, num, devfn;
+	unsigned int x;
+	unsigned char h;
+
+	num = 0;
+	for (bus = 0; bus <= max_bus; ++bus) {
+		if (bridges[bus] == 0)
+			continue;
+		unit = fn = 0;
+		if (bus == bridges[bus]->bus_number)
+			unit = 11;
+		while (unit < 32) {
+			devfn = PCI_DEVFN(unit, fn);
+			if (pcibios_read_config_dword(bus, devfn,
+						      PCI_CLASS_REVISION, &x)
+			    == PCIBIOS_SUCCESSFUL && (x >> 8) == class_code) {
+				if (index == num) {
+					*bus_ptr = bus;
+					*dev_fn_ptr = devfn;
+					return PCIBIOS_SUCCESSFUL;
+				}
+				++num;
+			}
+			if (fn != 0) {
+				if (++fn >= 8) {
+					++unit;
+					fn = 0;
+				}
+				continue;
+			}
+			if (pcibios_read_config_byte(bus, devfn,
+						     PCI_HEADER_TYPE, &h)
+			    == PCIBIOS_SUCCESSFUL && (h & 0x80) != 0)
+				++fn;
+			else
+				++unit;
+		}
+	}
+	return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+__initfunc(unsigned long route_pci_interrupts(void))
+{
+	return 0;
+}
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- v2.1.50/linux/arch/ppc/kernel/pci.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/pci.c	Sat Aug 16 09:51:08 1997
@@ -1,630 +1,164 @@
 /*
- * PCI support
- * -- rough emulation of "PCI BIOS" functions
- *
- * Note: these are very motherboard specific!  Some way needs to
- * be worked out to handle the differences.
+ * $Id: pci.c,v 1.11 1997/08/13 03:06:14 cort Exp $
+ * Common pmac/prep pci routines. -- Cort
  */
 
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/bios32.h>
+#include <linux/kernel.h>
 #include <linux/pci.h>
+/*#include <linux/bios32.h>*/
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
 
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/ptrace.h>
 #include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
 
-/*
- * PCI interrupt configuration.  This is motherboard specific.
- */
-/* Which PCI interrupt line does a given device [slot] use? */
-/* Note: This really should be two dimensional based in slot/pin used */
-unsigned char *Motherboard_map;
-unsigned char *Motherboard_map_name;
-
-/* How is the 82378 PIRQ mapping setup? */
-unsigned char *Motherboard_routes;
-
-/* Tables for known hardware */   
-
-/* Motorola PowerStack */
-static char Blackhawk_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 */
-  	1,	/* Slot 14 - Ethernet */
-  	0,	/* Slot 15 - unused */
-};
-
-static char Blackhawk_pci_IRQ_routes[] =
-{
-   	0,	/* Line 0 - Unused */
-   	9,	/* Line 1 */
-   	11,	/* Line 2 */
-   	14,	/* Line 3 */
-   	15	/* Line 4 */
-};
-   
-/* Motorola MVME16xx */
-static char Genesis_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 */
-  	1,	/* Slot 14 - Ethernet */
-  	0,	/* Slot 15 - unused */
-};
-
-static char Genesis_pci_IRQ_routes[] =
-{
-   	0,	/* Line 0 - Unused */
-   	10,	/* Line 1 */
-   	11,	/* Line 2 */
-   	14,	/* Line 3 */
-   	15	/* Line 4 */
-};
-   
-/* Motorola Series-E */
-static char Comet_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 */
-  	1,	/* Slot 14 - Ethernet */
-  	0,	/* Slot 15 - unused */
-};
-
-static char Comet_pci_IRQ_routes[] =
-{
-   	0,	/* Line 0 - Unused */
-   	10,	/* Line 1 */
-   	11,	/* Line 2 */
-   	14,	/* Line 3 */
-   	15	/* Line 4 */
-};
-
-/* BeBox */
-static char BeBox_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 */
-  	16,	/* Slot 12 - SCSI */
-  	0,	/* Slot 13 - unused */
-  	0,	/* Slot 14 - unused */
-  	0,	/* Slot 15 - unused */
-};
-
-static char BeBox_pci_IRQ_routes[] =
-{
-   	0,	/* Line 0 - Unused */
-   	9,	/* Line 1 */
-   	11,	/* Line 2 */
-   	14,	/* Line 3 */
-   	15	/* Line 4 */
-};
-
-/* 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 */
-};
-
+unsigned long io_base;
 
 /*
- * ibm 830 (and 850?).
- * This is actually based on the Carolina motherboard
- * -- Cort
- */
-static char ibm8xx_pci_IRQ_map[23] = {
-        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 - FireCoral */
-        4, /* Slot 12 - Ethernet  PCIINTD# */
-        2, /* Slot 13 - PCI Slot #2 */
-        2, /* Slot 14 - S3 Video PCIINTD# */
-        0, /* Slot 15 - onboard SCSI (INDI) [1] */
-        3, /* Slot 16 - NCR58C810 RS6000 Only PCIINTC# */
-        0, /* Slot 17 - unused */
-        2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
-        0, /* Slot 19 - unused */
-        0, /* Slot 20 - unused */
-        0, /* Slot 21 - unused */
-        2, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
-};
-static char ibm8xx_pci_IRQ_routes[] = {
-        0,      /* Line 0 - unused */
-        13,     /* Line 1 */
-        10,     /* Line 2 */
-        15,     /* Line 3 */
-        15,     /* Line 4 */
-};
-/* This just changes the PCI slots & onboard SCSI + S3 to IRQ10, but
- * it really needs some logic to set them to unique IRQ's, or even
- * add some logic to the drivers to ask an irq.c routine to re-map
- * the IRQ if it needs one to itself...
- */
-static char Carolina_PIRQ_routes[] = {
-   0xad,	/* INTB# = 10, INTA# = 13 */
-   0xff		/* INTD# = 15, INTC# = 15 */
-};
-/* We have to turn on LEVEL mode for changed IRQ's */
-/* All PCI IRQ's need to be level mode, so this should be something
- * other than hard-coded as well... IRQ's are individually mappable
- * to either edge or level.
- */
-#define CAROLINA_IRQ_EDGE_MASK_LO   0x00  /* IRQ's 0-7  */
-#define CAROLINA_IRQ_EDGE_MASK_HI   0xA4  /* IRQ's 8-15 [10,13,15] */
-#define PCI_DEVICE_ID_IBM_CORAL		0x000a
-
-#undef  PCI_DEBUG
-
-#ifdef PCI_STATS
-int PCI_conversions[2];
-#endif
-
-
-unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end)
-{
-	return mem_start;
-}
-
-int
-pcibios_present (void)
-{
-#ifdef PCI_DEBUG	
-	printk("PCI [BIOS] present?\n");
-#endif	
-	return (1);
-}
-
-int
-pcibios_read_config_dword (unsigned char bus,
-			   unsigned char dev, unsigned char offset, unsigned int *val)
-{
-	unsigned long _val;
-	unsigned long *ptr;
-	dev >>= 3;
-#ifdef PCI_DEBUG	
-	printk("PCI Read config dword[%d.%d.%x] = ", bus, dev, offset);
-#endif	
-	if ((bus != 0) || (dev < 11) || (dev > 16))
-	{
-		*val = 0xFFFFFFFF;
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	} else
-	{
-		ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
-#ifdef PCI_DEBUG	
-		printk("[%x] ", ptr);
-#endif		
-		_val = le32_to_cpu(*ptr);
-	}
-#ifdef PCI_DEBUG	
-	printk("%x\n", _val);
-#endif	
-	*val = _val;
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int
-pcibios_read_config_word (unsigned char bus,
-			  unsigned char dev, unsigned char offset, unsigned short *val)
-{
-	unsigned short _val;
-	unsigned short *ptr;
-	dev >>= 3;
-#ifdef PCI_DEBUG
-	printk("PCI Read config word[%d.%d.%x] = ", bus, dev, offset);
-#endif	
-	if ((bus != 0) || (dev < 11) || (dev > 16))
-	{
-		*val = (unsigned short)0xFFFFFFFF;
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	} else
-	{
-		ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
-#ifdef PCI_DEBUG
-		printk("[%x] ", ptr);
-#endif		
-		_val = le16_to_cpu(*ptr);
-	}
-#ifdef PCI_DEBUG
-	printk("%x\n", _val);
-#endif		
-	*val = _val;
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int
-pcibios_read_config_byte (unsigned char bus,
-			  unsigned char dev, unsigned char offset, unsigned char *val)
-{
-	unsigned char _val;
-	volatile unsigned char *ptr;
-	dev >>= 3;
-	/* Note: the configuration registers don't always have this right! */
-	if (offset == PCI_INTERRUPT_LINE)
-	{
-		if (Motherboard_map[dev] <= 4)
-		{
-			*val = Motherboard_routes[Motherboard_map[dev]];
-			/*printk("dev %d map %d route %d\n",
-			  dev,Motherboard_map[dev],
-			  Motherboard_routes[Motherboard_map[dev]]);*/
-		} else
-		{ /* Pseudo interrupts [for BeBox] */
-			*val = Motherboard_map[dev];
-		}
-#ifdef PCI_DEBUG	
-		printk("PCI Read Interrupt Line[%d.%d] = %d\n", bus, dev, *val);
-#endif		
-		return PCIBIOS_SUCCESSFUL;
+ * It would be nice if we could create a include/asm/pci.h and have just
+ * function ptrs for all these in there, but that isn't the case.
+ * We have a function, pcibios_*() which calls the function ptr ptr_pcibios_*()
+ * which has been setup by pcibios_init().  This is all to avoid a check
+ * for pmac/prep every time we call one of these.  It should also make the move
+ * to a include/asm/pcibios.h easier, we can drop the ptr_ on these functions
+ * and create pci.h
+ *   -- Cort
+ */
+int (*ptr_pcibios_read_config_byte)(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned char *val);
+int (*ptr_pcibios_read_config_word)(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned short *val);
+int (*ptr_pcibios_read_config_dword)(unsigned char bus, unsigned char dev_fn,
+			      unsigned char offset, unsigned int *val);
+int (*ptr_pcibios_write_config_byte)(unsigned char bus, unsigned char dev_fn,
+			      unsigned char offset, unsigned char val);
+int (*ptr_pcibios_write_config_word)(unsigned char bus, unsigned char dev_fn,
+			      unsigned char offset, unsigned short val);
+int (*ptr_pcibios_write_config_dword)(unsigned char bus, unsigned char dev_fn,
+			       unsigned char offset, unsigned int val);
+int (*ptr_pcibios_find_device)(unsigned short vendor, unsigned short dev_id,
+			unsigned short index, unsigned char *bus_ptr,
+			unsigned char *dev_fn_ptr);
+int (*ptr_pcibios_find_class)(unsigned int class_code, unsigned short index,
+		       unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+
+extern int pmac_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned char *val);
+extern int pmac_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned short *val);
+extern int pmac_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+			      unsigned char offset, unsigned int *val);
+extern int pmac_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+			      unsigned char offset, unsigned char val);
+extern int pmac_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+			      unsigned char offset, unsigned short val);
+extern int pmac_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+			       unsigned char offset, unsigned int val);
+extern int pmac_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+			unsigned short index, unsigned char *bus_ptr,
+			unsigned char *dev_fn_ptr);
+extern int pmac_pcibios_find_class(unsigned int class_code, unsigned short index,
+		       unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+
+extern int prep_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned char *val);
+extern int prep_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned short *val);
+extern int prep_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+			      unsigned char offset, unsigned int *val);
+extern int prep_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+			      unsigned char offset, unsigned char val);
+extern int prep_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+			      unsigned char offset, unsigned short val);
+extern int prep_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+			       unsigned char offset, unsigned int val);
+extern int prep_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+			unsigned short index, unsigned char *bus_ptr,
+			unsigned char *dev_fn_ptr);
+extern int prep_pcibios_find_class(unsigned int class_code, unsigned short index,
+		       unsigned char *bus_ptr, unsigned char *dev_fn_ptr);
+
+
+int pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned char *val)
+{
+	return ptr_pcibios_read_config_byte(bus,dev_fn,offset,val);
+}
+int pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned short *val)
+{
+	return ptr_pcibios_read_config_word(bus,dev_fn,offset,val);
+}
+int pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+			      unsigned char offset, unsigned int *val)
+{
+	return ptr_pcibios_read_config_dword(bus,dev_fn,offset,val);
+}
+int pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+			      unsigned char offset, unsigned char val)
+{
+	return ptr_pcibios_write_config_byte(bus,dev_fn,offset,val);
+}
+int pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+			      unsigned char offset, unsigned short val)
+{
+	return ptr_pcibios_write_config_word(bus,dev_fn,offset,val);
+}
+int pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+			       unsigned char offset, unsigned int val)
+{
+	return ptr_pcibios_write_config_dword(bus,dev_fn,offset,val);
+}
+int pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+			unsigned short index, unsigned char *bus_ptr,
+			unsigned char *dev_fn_ptr)
+{
+	return ptr_pcibios_find_device(vendor,dev_id,index,bus_ptr,dev_fn_ptr);
+}
+int pcibios_find_class(unsigned int class_code, unsigned short index,
+		       unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
+{
+	return ptr_pcibios_find_class(class_code,index,bus_ptr,dev_fn_ptr);
+}
+
+int pcibios_present(void)
+{
+	return 1;
+}
+
+__initfunc(unsigned long
+pcibios_init(unsigned long mem_start,unsigned long mem_end))
+{
+	if ( _machine == _MACH_Pmac )
+	{
+		ptr_pcibios_read_config_byte = pmac_pcibios_read_config_byte;
+		ptr_pcibios_read_config_word = pmac_pcibios_read_config_word;
+		ptr_pcibios_read_config_dword = pmac_pcibios_read_config_dword;
+		ptr_pcibios_write_config_byte = pmac_pcibios_write_config_byte;
+		ptr_pcibios_write_config_word = pmac_pcibios_write_config_word;
+		ptr_pcibios_write_config_dword = pmac_pcibios_write_config_dword;
+		ptr_pcibios_find_device = pmac_pcibios_find_device;
+		ptr_pcibios_find_class = pmac_pcibios_find_class;
+	}
+	else /* prep */
+	{
+		ptr_pcibios_read_config_byte = prep_pcibios_read_config_byte;
+		ptr_pcibios_read_config_word = prep_pcibios_read_config_word;
+		ptr_pcibios_read_config_dword = prep_pcibios_read_config_dword;
+		ptr_pcibios_write_config_byte = prep_pcibios_write_config_byte;
+		ptr_pcibios_write_config_word = prep_pcibios_write_config_word;
+		ptr_pcibios_write_config_dword = prep_pcibios_write_config_dword;
+		ptr_pcibios_find_device = prep_pcibios_find_device;
+		ptr_pcibios_find_class = prep_pcibios_find_class;
 	}
-#ifdef PCI_DEBUG	
-	printk("PCI Read config byte[%d.%d.%x] = ", bus, dev, offset);
-#endif		
-	if ((bus != 0) || (dev < 11) || (dev > 16))
-	{
-		*val = 0xFFFFFFFF;
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	} else
-	{
-		ptr = (unsigned char *)(0x80800000 | (1<<dev) | offset ^ 1);
-#ifdef PCI_DEBUG	
-		printk("[%x] ", ptr);
-#endif		
-		_val = *ptr;
-	}
-#ifdef PCI_DEBUG	
-	printk("%x\n", _val);
-#endif
-	*val = _val;
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int
-pcibios_write_config_dword (unsigned char bus,
-			    unsigned char dev, unsigned char offset, unsigned int val)
-{
-	unsigned long _val;
-	unsigned long *ptr;
-	dev >>= 3;
-	_val = le32_to_cpu(val);
-#ifdef PCI_DEBUG	
-	printk("PCI Write config dword[%d.%d.%x] = %x\n", bus, dev, offset, _val);
-#endif		
-	if ((bus != 0) || (dev < 11) || (dev > 16))
-	{
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	} else
-	{
-		ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
-		*ptr = _val;
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int
-pcibios_write_config_word (unsigned char bus,
-			   unsigned char dev, unsigned char offset, unsigned short val)
-{
-	unsigned short _val;
-	unsigned short *ptr;
-	dev >>= 3;
-	_val = le16_to_cpu(val);
-#ifdef PCI_DEBUG	
-	printk("PCI Write config word[%d.%d.%x] = %x\n", bus, dev, offset, _val);
-#endif		
-	if ((bus != 0) || (dev < 11) || (dev > 16))
-	{
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	} else
-	{
-		ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
-		*ptr = _val;
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int
-pcibios_write_config_byte (unsigned char bus,
-			   unsigned char dev, unsigned char offset, unsigned char val)
-{
-	unsigned char _val;
-	unsigned char *ptr;
-	dev >>= 3;
-	_val = val;
-#ifdef PCI_DEBUG	
-	printk("PCI Write config byte[%d.%d.%x] = %x\n", bus, dev, offset, _val);
-#endif		
-	if ((bus != 0) || (dev < 11) || (dev > 16))
-	{
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	} else
-	{
-		ptr = (unsigned char *)(0x80800000 | (1<<dev) | offset ^ 1);
-		*ptr = _val;
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int
-pcibios_find_device (unsigned short vendor, unsigned short device_id,
-		     unsigned short index, unsigned char *bus,
-		     unsigned char *dev)
-{
-	unsigned long w, desired = (device_id << 16) | vendor;
-	int devnr;
-
-	if (vendor == 0xffff) {
-		return PCIBIOS_BAD_VENDOR_ID;
-	}
-
-	for (devnr = 11;  devnr < 16;  devnr++)
-	{
-		pcibios_read_config_dword(0, devnr<<3, PCI_VENDOR_ID, &w);
-		if (w == desired) {
-			if (index == 0) {
-				*bus = 0;
-				*dev = devnr<<3;
-				return PCIBIOS_SUCCESSFUL;
-			}
-			--index;
-		}
-	}
-	return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-int
-pcibios_find_class (unsigned int class_code, unsigned short index, 
-		    unsigned char *bus, unsigned char *dev)
-{
-	int dev_nr, class, indx;
-	indx = 0;
-#ifdef PCI_DEBUG	
-	printk("pcibios_find_class - class: %x, index: %x", class_code, index);
-#endif	
-	for (dev_nr = 11;  dev_nr < 16;  dev_nr++)
-	{
-		pcibios_read_config_dword(0, dev_nr<<3, PCI_CLASS_REVISION, &class);
-		if ((class>>8) == class_code)
-		{
-			if (index == indx)
-			{
-				*bus = 0;
-				*dev = dev_nr<<3;
-#ifdef PCI_DEBUG
-				printk(" - device: %x\n", dev_nr);
-#endif	
-				return (0);
-			}
-			indx++;
-		}
-	}
-#ifdef PCI_DEBUG
-	printk(" - not found\n");
-#endif	
-	return PCIBIOS_DEVICE_NOT_FOUND;
-}    
-
-const char *pcibios_strerror(int error)
-{
-	static char buf[32];
-	switch (error)
-	{	case PCIBIOS_SUCCESSFUL:
-		return ("PCI BIOS: no error");
-	case PCIBIOS_FUNC_NOT_SUPPORTED:
-		return ("PCI BIOS: function not supported");
-	case PCIBIOS_BAD_VENDOR_ID:
-		return ("PCI BIOS: bad vendor ID");
-	case PCIBIOS_DEVICE_NOT_FOUND:
-		return ("PCI BIOS: device not found");
-	case PCIBIOS_BAD_REGISTER_NUMBER:
-		return ("PCI BIOS: bad register number");
-	case PCIBIOS_SET_FAILED:
-		return ("PCI BIOS: set failed");
-	case PCIBIOS_BUFFER_TOO_SMALL:
-		return ("PCI BIOS: buffer too small");
-	default:
-		sprintf(buf, "PCI BIOS: invalid error #%d", error);
-		return(buf);
-	}
-}
-
-/*
- * Note: This routine has to access the PCI configuration space
- * for the PCI bridge chip (Intel 82378).
- */
-unsigned long pcibios_init(unsigned long mem_start,unsigned long mem_end)
-{
 	return mem_start;
 }
 
-unsigned long route_pci_interrupts(void)
+__initfunc(unsigned long
+pcibios_fixup(unsigned long mem_start, unsigned long mem_end))
 {
-	unsigned char *ibc_pirq = (unsigned char *)0x80800860;
-	unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
-	extern unsigned long isBeBox[];
-	int i;
-	
-	if ( _machine == _MACH_Motorola)
-	{ 
-		switch (inb(0x800) & 0xF0)
-		{
-		case 0x10: /* MVME16xx */
-			Motherboard_map_name = "Genesis";
-			Motherboard_map = Genesis_pci_IRQ_map;
-			Motherboard_routes = Genesis_pci_IRQ_routes;
-			break;
-		case 0x20: /* Series E */
-			Motherboard_map_name = "Series E";
-			Motherboard_map = Comet_pci_IRQ_map;
-			Motherboard_routes = Comet_pci_IRQ_routes;
-			break;
-		case 0x40: /* PowerStack */
-		default: /* Can't hurt, can it? */
-			Motherboard_map_name = "Blackhawk (Powerstack)";
-			Motherboard_map = Blackhawk_pci_IRQ_map;
-			Motherboard_routes = Blackhawk_pci_IRQ_routes;
-			break;
-		}
-	} else
-	{
-		if ( _machine == _MACH_IBM )
-		{
-			unsigned char pl_id;
-			unsigned long flags;
-			unsigned index;
-			unsigned char fn, bus;
-			unsigned int addr;
-			unsigned char dma_mode, ide_mode;
-			int i;
-			
-			Motherboard_map_name = "IBM 8xx (Carolina)";
-			Motherboard_map = ibm8xx_pci_IRQ_map;
-			Motherboard_routes = ibm8xx_pci_IRQ_routes;
-ll_printk("before loop\n");			
-			
-			for (index = 0;
-			     !pcibios_find_device (PCI_VENDOR_ID_IBM, 
-						   PCI_DEVICE_ID_IBM_CORAL, 
-						   index, &bus, &fn); ++index)
-			{
-				pcibios_read_config_dword(bus, fn, 0x10, &addr);
-				addr &= ~0x3;
-				outb(0x26, addr);
-				dma_mode = inb(addr+4);
-				outb(0x25, addr);
-				ide_mode = inb(addr+4);
-				/*printk("CORAL I/O at 0x%x, DMA mode: %x, IDE mode: %x", 
-				       addr, dma_mode, ide_mode);*/
-				/* Make CDROM non-DMA */
-				ide_mode = (ide_mode & 0x0F) | 0x20;
-				outb(0x25, addr);
-				outb(ide_mode, addr+4);
-				dma_mode = dma_mode & ~0x80;
-				outb(0x26, addr);
-				outb(dma_mode, addr+4);
-				outb(0x26, addr);
-				dma_mode = inb(addr+4);
-				outb(0x25, addr);
-				ide_mode = inb(addr+4);
-				/*printk("=> DMA mode: %x, IDE mode: %x\n", 
-				       dma_mode, ide_mode);*/
-			}
-			
-			/* Setup the PCI INT mappings for the Carolina */
-			/* These are PCI Interrupt Route Control [1|2] Register */
-			outb(Carolina_PIRQ_routes[0], 0x0890);
-			outb(Carolina_PIRQ_routes[1], 0x0891);
-			
-			pl_id=inb(0x0852);
-			/*printk("CPU Planar ID is %#0x\n", pl_id);*/
-			
-			if (pl_id == 0x0C) {
-				/* INDI */
-				Motherboard_map[12] = 1;
-			}
-ll_printk("before edge/level\n");			
-#if 0			
-			/*printk("Changing IRQ mode\n");*/
-			pl_id=inb(0x04d0);
-			/*printk("Low mask is %#0x\n", pl_id);*/
-			outb(pl_id|CAROLINA_IRQ_EDGE_MASK_LO, 0x04d0);
-			
-			pl_id=inb(0x04d1);
-			/*printk("Hi mask is  %#0x\n", pl_id);*/
-			outb(pl_id|CAROLINA_IRQ_EDGE_MASK_HI, 0x04d1);
-			pl_id=inb(0x04d1);
-			/*printk("Hi mask now %#0x\n", pl_id);*/
-#endif			
-		}
-	}
-	
-	/* Set up mapping from slots */
-	for (i = 1;  i <= 4;  i++)
-	{
-		ibc_pirq[i-1] = Motherboard_routes[i];
-	}
-	/* Enable PCI interrupts */
-	*ibc_pcicon |= 0x20;
+	return mem_start;
 }
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c
--- v2.1.50/linux/arch/ppc/kernel/pmac_setup.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/pmac_setup.c	Sat Aug 16 09:51:08 1997
@@ -21,6 +21,7 @@
  * bootup setup stuff..
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -35,31 +36,35 @@
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
+#include <linux/major.h>
 #include <asm/prom.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
 #include <asm/ide.h>
+#include <asm/pci-bridge.h>
+#include "time.h"
+
+/*
+ * A magic address and value to put into it on machines with the
+ * "ohare" I/O controller.  This makes the IDE CD work on Starmaxes.
+ * Contributed by Harry Eaton.
+ */
+#define OMAGICPLACE	((volatile unsigned *) 0xf3000038)
+#define OMAGICCONT	0xbeff7a
 
 extern int root_mountflags;
 
 extern char command_line[];
-char saved_command_line[256];
+extern char saved_command_line[256];
 
-unsigned char aux_device_present;	/* XXX */
-unsigned char kbd_read_mask;
 unsigned char drive_info;
 
 #define DEFAULT_ROOT_DEVICE 0x0801	/* sda1 - slightly silly choice */
 
 extern unsigned long find_available_memory(void);
 
-unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end)
-{
-	return memory_start;
-}
-
-void setup_arch(char **cmdline_p,
+void pmac_setup_arch(char **cmdline_p,
 	unsigned long * memory_start_p, unsigned long * memory_end_p)
 {
 	extern unsigned long *end_of_DRAM;
@@ -84,6 +89,8 @@
 		if (fp != 0) {
 			switch (_get_PVR() >> 16) {
 			case 4:		/* 604 */
+			case 9:		/* 604e */
+			case 20:	/* 620 */
 				loops_per_sec = *fp;
 				break;
 			default:	/* 601, 603, etc. */
@@ -102,13 +109,19 @@
 kdev_t boot_dev;
 
 unsigned long
-pmac_find_devices(unsigned long mem_start, unsigned long mem_end)
+powermac_init(unsigned long mem_start, unsigned long mem_end)
 {
-	struct device_node *chosen_np;
+	struct device_node *chosen_np, *ohare_np;
 
-	nvram_init();
+	mem_start = pmac_find_bridges(mem_start, mem_end);
+	ohare_np = find_devices("ohare");
+	if (ohare_np != NULL) {
+		printk(KERN_INFO "Twiddling the magic ohare bits\n");
+		out_le32(OMAGICPLACE, OMAGICCONT);
+	}
+	pmac_nvram_init();
 	via_cuda_init();
-	read_rtc_time();
+	pmac_read_rtc_time();
 	pmac_find_display();
 	bootpath = NULL;
 	chosen_np = find_devices("chosen");
@@ -147,7 +160,7 @@
 	}
 }
 
-void find_scsi_boot()
+void find_boot_device(void)
 {
 	int dev;
 
@@ -156,10 +169,28 @@
 	ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE);
 	if (boot_host == NULL)
 		return;
+#ifdef CONFIG_SCSI
 	dev = sd_find_target(boot_host, boot_target);
 	if (dev == 0)
 		return;
 	boot_dev = to_kdev_t(dev + boot_part);
+#endif
+	/* XXX should cope with booting from IDE also */
+}
+
+void note_bootable_part(kdev_t dev, int part)
+{
+	static int found_boot = 0;
+
+	if (!found_boot) {
+		find_boot_device();
+		found_boot = 1;
+	}
+	if (dev == boot_dev) {
+		ROOT_DEV = MKDEV(MAJOR(dev), MINOR(dev) + part);
+		boot_dev = NODEV;
+		printk(" (root)");
+	}
 }
 
 void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
@@ -186,41 +217,18 @@
 	if (np->n_intrs == 0) {
 		printk("ide: no intrs for device %s, using 13\n",
 		       np->full_name);
-		np->intrs[0] = 13;
+		*irq = 13;
+	} else {
+		*irq = np->intrs[0];
 	}
 	base = (unsigned long) ioremap(np->addrs[0].address, 0x200);
 	for (i = 0; i < 8; ++i)
 		*p++ = base + i * 0x10;
 	*p = base + 0x160;
-	*irq = np->intrs[0];
-}
-
-int sys_ioperm(unsigned long from, unsigned long num, int on)
-{
-	return -EIO;
-}
-
-#if 0
-extern char builtin_ramdisk_image;
-extern long builtin_ramdisk_size;
-#endif
-
-void
-builtin_ramdisk_init(void)
-{
-#if 0
-	if ((ROOT_DEV == to_kdev_t(DEFAULT_ROOT_DEVICE)) && (builtin_ramdisk_size != 0))
-	{
-		rd_preloaded_init(&builtin_ramdisk_image, builtin_ramdisk_size);
-	} else
-#endif
-	{  /* Not ramdisk - assume root needs to be mounted read only */
-		root_mountflags |= MS_RDONLY;
-	}
 }
 
 int
-get_cpuinfo(char *buffer)
+pmac_get_cpuinfo(char *buffer)
 {
 	int pvr = _get_PVR();
 	char *model;
@@ -251,10 +259,13 @@
 	case 7:
 		model = "603ev";
 		break;
+	case 9:
+		model = "604e";
+		break;
 	default:
 		model = "unknown";
 		break;
 	}
 	return l + sprintf(buffer+l, "PowerPC %s rev %d.%d\n", model,
-			   (pvr & 0xff) >> 8, pvr & 0xff);
+			   (pvr & 0xff00) >> 8, pvr & 0xff);
 }
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/pmac_support.c linux/arch/ppc/kernel/pmac_support.c
--- v2.1.50/linux/arch/ppc/kernel/pmac_support.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/pmac_support.c	Sat Aug 16 09:51:08 1997
@@ -3,30 +3,14 @@
  */
 #include <linux/kernel.h>
 #include <linux/stddef.h>
+#include <linux/reboot.h>
+#include <linux/nvram.h>
 #include <asm/ptrace.h>
 #include <asm/io.h>
 #include <asm/cuda.h>
 #include <asm/system.h>
 #include <asm/prom.h>
 
-void hard_reset_now(void)
-{
-	struct cuda_request req;
-
-	cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM);
-	for (;;)
-		cuda_poll();
-}
-
-void poweroff_now(void)
-{
-	struct cuda_request req;
-
-	cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN);
-	for (;;)
-		cuda_poll();
-}
-
 /*
  * Read and write the non-volatile RAM on PowerMacs.
  */
@@ -34,26 +18,29 @@
 static volatile unsigned char *nvram_addr;
 static volatile unsigned char *nvram_data;
 
-void nvram_init(void)
+void pmac_nvram_init(void)
 {
 	struct device_node *dp;
 
 	dp = find_devices("nvram");
-	if (dp == NULL)
-		panic("Can't find NVRAM device");
+	if (dp == NULL) {
+		printk(KERN_ERR "Can't find NVRAM device\n");
+		nvram_naddrs = 0;
+		return;
+	}
 	nvram_naddrs = dp->n_addrs;
-	if (nvram_naddrs == 1)
+	if (nvram_naddrs == 1) {
 		nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
-	else if (nvram_naddrs == 2) {
+	} else if (nvram_naddrs == 2) {
 		nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
 		nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
 	} else {
-		printk("Found %d addresses for NVRAM\n", nvram_naddrs);
-		panic("don't understand NVRAM");
+		printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
+		       nvram_naddrs);
 	}
 }
 
-int nvram_readb(int addr)
+unsigned char nvram_read_byte(int addr)
 {
 	switch (nvram_naddrs) {
 	case 1:
@@ -63,10 +50,10 @@
 		eieio();
 		return nvram_data[(addr & 0x1f) << 4];
 	}
-	return -1;
+	return 0;
 }
 
-void nvram_writeb(int addr, int val)
+void nvram_write_byte(unsigned char val, int addr)
 {
 	switch (nvram_naddrs) {
 	case 1:
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/pmac_time.c linux/arch/ppc/kernel/pmac_time.c
--- v2.1.50/linux/arch/ppc/kernel/pmac_time.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/pmac_time.c	Sat Aug 16 09:51:08 1997
@@ -19,125 +19,60 @@
 #include <asm/prom.h>
 #include <asm/system.h>
 
-static int get_dec(void);
-static void set_dec(int);
-static unsigned long get_rtc_time(void);
+#include "time.h"
+
 
 /* Apparently the RTC stores seconds since 1 Jan 1904 */
 #define RTC_OFFSET	2082844800
 
-/* Accessor functions for the decrementer register. */
-static inline int
-get_dec()
-{
-    int ret;
-
-    asm volatile("mfspr %0,22" : "=r" (ret) :);
-    return ret;
-}
-
-static inline void
-set_dec(int val)
-{
-    asm volatile("mtspr 22,%0" : : "r" (val));
-}
-
-/* The decrementer counts down by 128 every 128ns on a 601. */
-#define DECREMENTER_COUNT_601	(1000000000 / HZ)
-#define COUNT_PERIOD_NUM_601	1
-#define COUNT_PERIOD_DEN_601	1000
-
-unsigned decrementer_count;	/* count value for 1e6/HZ microseconds */
-unsigned count_period_num;	/* 1 decrementer count equals */
-unsigned count_period_den;	/* count_period_num / count_period_den us */
-
 /*
- * This version of gettimeofday has microsecond resolution.
+ * Query the OF and get the decr frequency.
+ * This was taken from the pmac time_init() when merging the prep/pmac
+ * time functions.
  */
-void do_gettimeofday(struct timeval *tv)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	*tv = xtime;
-	tv->tv_usec += (decrementer_count - get_dec())
-	    * count_period_num / count_period_den;
-	if (tv->tv_usec >= 1000000) {
-		tv->tv_usec -= 1000000;
-		tv->tv_sec++;
-	}
-	restore_flags(flags);
-}
-
-void do_settimeofday(struct timeval *tv)
+void pmac_calibrate_decr(void)
 {
-	unsigned long flags;
-	int frac_tick;
+	struct device_node *cpu;
+	int freq, *fp, divisor;
 
-	frac_tick = tv->tv_usec % (1000000 / HZ);
-	save_flags(flags);
-	cli();
-	xtime.tv_sec = tv->tv_sec;
-	xtime.tv_usec = tv->tv_usec - frac_tick;
-	set_dec(frac_tick * count_period_den / count_period_num);
-	restore_flags(flags);
+	/*
+	 * The cpu node should have a timebase-frequency property
+	 * to tell us the rate at which the decrementer counts.
+	 */
+	cpu = find_type_devices("cpu");
+	if (cpu == 0)
+		panic("can't find cpu node in time_init");
+	fp = (int *) get_property(cpu, "timebase-frequency", NULL);
+	if (fp == 0)
+		panic("can't get cpu timebase frequency");
+	freq = *fp * 60;	/* try to make freq/1e6 an integer */
+	divisor = 60;
+	printk("time_init: decrementer frequency = %d/%d\n",
+	       freq, divisor);
+	decrementer_count = freq / HZ / divisor;
+	count_period_num = divisor;
+	count_period_den = freq / 1000000;
 }
 
-/*
- * timer_interrupt - gets called when the decrementer overflows,
- * with interrupts disabled.
- * We set it up to overflow again in 1/HZ seconds.
- */
-void timer_interrupt(struct pt_regs * regs)
+unsigned long
+pmac_get_rtc_time(void)
 {
-	int dval, d;
-
-	while ((dval = get_dec()) < 0) {
-		/*
-		 * Wait for the decrementer to change, then jump
-		 * in and add decrementer_count to its value
-		 * (quickly, before it changes again!)
-		 */
-		while ((d = get_dec()) == dval)
-			;
-		set_dec(d + decrementer_count);
-		do_timer(regs);
-	}
+	struct cuda_request req;
 
+	/* Get the time from the RTC */
+	cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME);
+	while (!req.got_reply)
+		cuda_poll();
+	if (req.reply_len != 7)
+		printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
+		      req.reply_len);
+	return (req.reply[3] << 24) + (req.reply[4] << 16)
+		+ (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
 }
 
-void
-time_init(void)
+int pmac_set_rtc_time(unsigned long nowtime)
 {
-	struct device_node *cpu;
-	int freq, *fp, divisor;
-
-	if ((_get_PVR() >> 16) == 1) {
-		/* 601 processor: dec counts down by 128 every 128ns */
-		decrementer_count = DECREMENTER_COUNT_601;
-		count_period_num = COUNT_PERIOD_NUM_601;
-		count_period_den = COUNT_PERIOD_DEN_601;
-	} else {
-		/*
-		 * The cpu node should have a timebase-frequency property
-		 * to tell us the rate at which the decrementer counts.
-		 */
-		cpu = find_type_devices("cpu");
-		if (cpu == 0)
-			panic("can't find cpu node in time_init");
-		fp = (int *) get_property(cpu, "timebase-frequency", NULL);
-		if (fp == 0)
-			panic("can't get cpu timebase frequency");
-		freq = *fp * 60;	/* try to make freq/1e6 an integer */
-		divisor = 60;
-		printk("time_init: decrementer frequency = %d/%d\n",
-		       freq, divisor);
-		decrementer_count = freq / HZ / divisor;
-		count_period_num = divisor;
-		count_period_den = freq / 1000000;
-	}
-	set_dec(decrementer_count);
+	return 0;
 }
 
 /*
@@ -145,24 +80,8 @@
  * been called at that stage.
  */
 void
-read_rtc_time(void)
+pmac_read_rtc_time(void)
 {
-	xtime.tv_sec = get_rtc_time();
+	xtime.tv_sec = pmac_get_rtc_time();
 	xtime.tv_usec = 0;
-}
-
-static unsigned long
-get_rtc_time()
-{
-	struct cuda_request req;
-
-	/* Get the time from the RTC */
-	cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME);
-	while (!req.got_reply)
-		cuda_poll();
-	if (req.reply_len != 7)
-		panic("get_rtc_time: didn't expect %d byte reply",
-		      req.reply_len);
-	return (req.reply[3] << 24) + (req.reply[4] << 16)
-		+ (req.reply[5] << 8) + req.reply[6] - RTC_OFFSET;
 }
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/port_io.c linux/arch/ppc/kernel/port_io.c
--- v2.1.50/linux/arch/ppc/kernel/port_io.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/port_io.c	Wed Dec 31 16:00:00 1969
@@ -1,146 +0,0 @@
-/*
- * I/O 'port' access routines
- */
-#include <asm/byteorder.h>
-#include <asm/io.h>
-
-#define inb_asm(port) {( \
-  unsigned char ret; \
-  asm ( "lbz %0,0(%1)\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n" : "=r" (ret) : "r" (port+_IO_BASE)); \
-  return ret; \
-})
-
-inline unsigned char
-inb(int port)
-{
-  unsigned char ret;
-  asm("/*inb*/\n");
-  asm ( "lbz %0,0(%1)" : "=r" (ret) : "r" (port+_IO_BASE));
-  return ret;
-}
-
-inline unsigned short
-inw(int port)
-{
-  unsigned short ret;
-  asm("/*inw*/\n");
-  asm ( "lhbrx %0,%1,%2" : "=r" (ret) : "r" (port+_IO_BASE), "r" (0));
-  return ret;
-}
-
-inline unsigned long
-inl(int port)
-{
-  unsigned long ret;
-  asm("/*inl*/\n");
-  asm ( "lwbrx %0,%1,%2" : "=r" (ret) : "r" (port+_IO_BASE), "r" (0));
-  return ret;
-}
-
-inline unsigned char
-outb(unsigned char val,int port)
-{
-  asm("/*outb*/\n");
-  asm ( "stb %0,0(%1)" :: "r" (val), "r" (port+_IO_BASE));
-  return (val);
-}
-
-inline unsigned short
-outw(unsigned short val,int port)
-{
-  asm("/*outw*/\n");
-  asm ( "sthbrx %0,%1,%2" :: "r" (val), "r" (port+_IO_BASE), "r" (0));
-  return (val);
-}
-
-inline unsigned long
-outl(unsigned long val,int port)
-{
-  asm("/*outl*/\n");
-  asm ( "stwbrx %0,%1,%2" :: "r" (val), "r" (port+_IO_BASE), "r" (0));
-  return (val);
-}
-
-void insb(int port, char *ptr, int len)
-{
-  memcpy( (void *)ptr, (void *)(port+_IO_BASE), len);
-}
-
-void insw(int port, short *ptr, int len)
-{
-  asm ("mtctr	%2 \n\t"
-       "subi	%1,%1,2 \n\t"
-       "00:\n\t"
-       "lhbrx	%2,0,%0 \n\t"
-       "sthu	%2,2(%1) \n\t"
-       "bdnz 00b \n\t"
-       :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
-}
-
-void insw_unswapped(int port, short *ptr, int len)
-{
-  memcpy( (void *)ptr, (void *)(port+_IO_BASE), (len*sizeof(short)) );
-}
-
-void insl(int port, long *ptr, int len)
-{
-  asm ("mtctr	%2 \n\t"
-       "subi	%1,%1,4 \n\t"
-       "00:\n\t"
-       "lhbrx	%2,0,%0 \n\t"
-       "sthu	%2,4(%1) \n\t"
-       "bdnz 00b \n\t"
-       :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
-}
-
-void outsb(int port, char *ptr, int len)
-{
-  memcpy( (void *)ptr, (void *)(port+_IO_BASE), len );
-}
-
-void outsw(int port, short *ptr, int len)
-{
-  asm ("mtctr	%2\n\t"
-       "subi	%1,%1,2\n\t"
-       "00:lhzu	%2,2(%1)\n\t"
-       "sthbrx	%2,0,%0\n\t"
-       "bdnz	00b\n\t"
-       :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
-}
-
-void outsw_unswapped(int port, short *ptr, int len)
-{
-  memcpy( (void *)ptr, (void *)(port+_IO_BASE), len*sizeof(short) );  
-}
-
-void outsl(int port, long *ptr, int len)
-{
-  asm ("mtctr	%2\n\t"
-       "subi	%1,%1,4\n\t"
-       "00:lwzu	%2,4(%1)\n\t"
-       "sthbrx	%2,0,%0\n\t"
-       "bdnz	00b\n\t"
-       :: "r" (port+_IO_BASE), "r" (ptr), "r" (len));
-}
-
-void insl_unswapped(int port, long *ptr, int len)
-{
-        unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
-        /* Ensure I/O operations complete */
-        __asm__ volatile("eieio");
-        while (len-- > 0)
-        {
-                *ptr++ = (*io_ptr);
-        }
-}
-
-void outsl_unswapped(int port, long *ptr, int len)
-{
-        unsigned long *io_ptr = (unsigned long *)(_IO_BASE+port);
-        /* Ensure I/O operations complete */
-        __asm__ volatile("eieio");
-        while (len-- > 0)
-        {
-                *io_ptr = (*ptr++);
-        }
-}
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/ppc_asm.tmpl linux/arch/ppc/kernel/ppc_asm.tmpl
--- v2.1.50/linux/arch/ppc/kernel/ppc_asm.tmpl	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/ppc_asm.tmpl	Sat Aug 16 09:51:08 1997
@@ -187,7 +187,3 @@
 #define REST_8FPRS(n, base)	REST_4FPRS(n, base); REST_4FPRS(n+4, base)
 #define REST_16FPRS(n, base)	REST_8FPRS(n, base); REST_8FPRS(n+8, base)
 #define REST_32FPRS(n, base)	REST_16FPRS(n, base); REST_16FPRS(n+16, base)
-
-/* Missing instructions */
-#define bdne	bc 0,2,
-
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/ppc_defs.h linux/arch/ppc/kernel/ppc_defs.h
--- v2.1.50/linux/arch/ppc/kernel/ppc_defs.h	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/ppc_defs.h	Wed Dec 31 16:00:00 1969
@@ -1,63 +0,0 @@
-/*
- * WARNING! This file is automatically generated - DO NOT EDIT!
- */
-#define	STATE	0
-#define	NEXT_TASK	68
-#define	COUNTER	4
-#define	BLOCKED	16
-#define	SIGNAL	12
-#define	TSS	544
-#define	KSP	0
-#define	PG_TABLES	4
-#define	LAST_SYSCALL	288
-#define	PT_REGS	280
-#define	PF_TRACESYS	32
-#define	TASK_FLAGS	20
-#define	TSS_FPR0	16
-#define	TSS_FPSCR	12
-#define	TASK_UNION_SIZE	8192
-#define	STACK_FRAME_OVERHEAD	16
-#define	INT_FRAME_SIZE	192
-#define	GPR0	16
-#define	GPR1	20
-#define	GPR2	24
-#define	GPR3	28
-#define	GPR4	32
-#define	GPR5	36
-#define	GPR6	40
-#define	GPR7	44
-#define	GPR8	48
-#define	GPR9	52
-#define	GPR10	56
-#define	GPR11	60
-#define	GPR12	64
-#define	GPR13	68
-#define	GPR14	72
-#define	GPR15	76
-#define	GPR16	80
-#define	GPR17	84
-#define	GPR18	88
-#define	GPR19	92
-#define	GPR20	96
-#define	GPR21	100
-#define	GPR22	104
-#define	GPR23	108
-#define	GPR24	112
-#define	GPR25	116
-#define	GPR26	120
-#define	GPR27	124
-#define	GPR28	128
-#define	GPR29	132
-#define	GPR30	136
-#define	GPR31	140
-#define	_NIP	144
-#define	_MSR	148
-#define	_CTR	152
-#define	_LINK	156
-#define	_CCR	160
-#define	_XER	164
-#define	_DAR	168
-#define	_DSISR	172
-#define	ORIG_GPR3	176
-#define	RESULT	180
-#define	TRAP	184
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/ppc_htab.c linux/arch/ppc/kernel/ppc_htab.c
--- v2.1.50/linux/arch/ppc/kernel/ppc_htab.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/ppc_htab.c	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,196 @@
+/*
+ * $Id: ppc_htab.c,v 1.4 1997/08/12 04:24:54 cort Exp $
+ * PowerPC hash table management proc entry.  Will show information
+ * about the current hash table and will allow changes to it.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * 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.
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+static long ppc_htab_read(struct inode * inode, struct file * file,
+			   char * buf, unsigned long nbytes);
+static long ppc_htab_write(struct inode * inode, struct file * file,
+			    const char * buffer, unsigned long count);
+static long long ppc_htab_lseek(struct inode * inode, struct file * file, 
+				 long long offset, int orig);
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+
+static struct file_operations ppc_htab_operations = {
+    ppc_htab_lseek,	/* lseek   */
+    ppc_htab_read,	/* read	   */
+    ppc_htab_write,	/* write   */
+    NULL,		/* readdir */
+    NULL,		/* poll    */
+    NULL,		/* ioctl   */
+    NULL,		/* mmap	   */
+    NULL,		/* no special open code	   */
+    NULL,		/* no special release code */
+    NULL		/* can't fsync */
+};
+
+/*
+ * proc files can do almost nothing..
+ */
+struct inode_operations proc_ppc_htab_inode_operations = {
+    &ppc_htab_operations,  /* default proc 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  */
+};
+
+
+/*
+ * print some useful info about the hash table.  This function
+ * is _REALLY_ slow (see the nested for loops below) but nothing
+ * in here should be really timing critical. -- Cort
+ */
+static long ppc_htab_read(struct inode * inode, struct file * file,
+			   char * buf, unsigned long nbytes)
+{
+	int n = 0, valid;
+	unsigned int kptes = 0, overflow = 0, uptes = 0;
+	PTE *ptr;
+	struct task_struct *p;
+	
+	if (nbytes < 0)
+		return -EINVAL;
+
+	/*
+	 * compute user/kernel pte's table this info can be
+	 * misleading since there can be valid (v bit set) entries
+	 * in the table but their vsid is used by no process (mm->context)
+	 * due to the way tlb invalidation is handled on the ppc
+	 * -- Cort
+	 */
+	for ( ptr = Hash ; ptr < (PTE *)(Hash+Hash_size) ; ptr+=sizeof(PTE))
+	{
+		if (ptr->v)
+		{
+			/* make sure someone is using this context/vsid */
+			for_each_task(p)
+			{
+				if ( (ptr->vsid >> 4) == p->mm->context )
+				{
+					valid = 1;
+					break;
+				}
+			}
+			if ( !valid )
+				continue;
+			/* user not allowed read or write */
+			if (ptr->pp == PP_RWXX)
+				kptes++;
+			else
+				uptes++;
+			if (ptr->h == 1)
+				overflow++;
+		}
+	}
+	n += sprintf( buf,
+		      "Size\t\t: %luKb\n"
+		      "Buckets\t\t: %lu\n"
+ 		      "Address\t\t: %08lx\n"
+		      "Entries\t\t: %lu\n"
+		      "User ptes\t: %u\n"
+		      "Kernel ptes\t: %u\n"
+		      "Overflows\t: %u\n"
+		      "Percent full\t: %%%lu\n",
+                      (unsigned long)(Hash_size>>10),
+		      (Hash_size/(sizeof(PTE)*8)),
+		      (unsigned long)Hash,
+		      Hash_size/sizeof(PTE),
+                      uptes,
+		      kptes,
+		      overflow,
+		      ((kptes+uptes)*100) / (Hash_size/sizeof(PTE))
+		);
+	/* if we're trying to read part of the file that isn't there */
+	if ( file->f_pos > n )
+		return -ENOMEM;
+	file->f_pos += n;
+	return n;
+}
+
+/*
+ * Can't _yet_ adjust the hash table size while running. -- Cort
+ */
+static long
+ppc_htab_write(struct inode * inode, struct file * file,
+		const char * buffer, unsigned long count)
+{
+	if ( current->uid != 0 )
+		return -EACCES;
+	else
+		return -ENOSYS;
+	return 0;
+}
+
+
+static long long
+ppc_htab_lseek(struct inode * inode, struct file * file, 
+				 long long offset, int orig)
+{
+    switch (orig) {
+    case 0:
+	file->f_pos = offset;
+	return(file->f_pos);
+    case 1:
+	file->f_pos += offset;
+	return(file->f_pos);
+    case 2:
+	return(-EINVAL);
+    default:
+	return(-EINVAL);
+    }
+}
+
+
+#if 0
+/*
+  for root.c
+  */
+static struct proc_dir_entry proc_root_ppc_htab = {
+	PROC_PPC_HTAB, 8, "ppc_htab",
+	S_IFREG | S_IRUGO, 1, 0, 0,
+	0, &proc_ppc_htab_inode_operations
+};
+#ifdef __powerpc__
+	proc_register(&proc_root, &proc_root_ppc_htab);
+#endif
+
+
+/* add to proc_fs.h
+   	PROC_PPC_HTAB,*/
+#endif
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c
--- v2.1.50/linux/arch/ppc/kernel/ppc_ksyms.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/ppc_ksyms.c	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,140 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/elfcore.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/bios32.h>
+
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+#include <asm/checksum.h>
+#include <asm/pgtable.h>
+#include <asm/cuda.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/pci-bridge.h>
+
+void transfer_to_handler();
+void int_return();
+void syscall_trace();
+void do_IRQ();
+void MachineCheckException();
+void AlignmentException();
+void ProgramCheckException();
+void SingleStepException();
+void FloatingPointCheckException();
+void sys_sigreturn();
+extern unsigned lost_interrupts;
+extern void do_lost_interrupts(unsigned long);
+
+EXPORT_SYMBOL(do_signal);
+EXPORT_SYMBOL(syscall_trace);
+EXPORT_SYMBOL(transfer_to_handler);
+EXPORT_SYMBOL(int_return);
+EXPORT_SYMBOL(do_IRQ);
+EXPORT_SYMBOL(init_task_union);
+EXPORT_SYMBOL(MachineCheckException);
+EXPORT_SYMBOL(AlignmentException);
+EXPORT_SYMBOL(ProgramCheckException);
+EXPORT_SYMBOL(SingleStepException);
+EXPORT_SYMBOL(sys_sigreturn);
+EXPORT_SYMBOL(lost_interrupts);
+EXPORT_SYMBOL(do_lost_interrupts);
+
+EXPORT_SYMBOL(atomic_add);
+EXPORT_SYMBOL(atomic_sub);
+EXPORT_SYMBOL(atomic_inc);
+EXPORT_SYMBOL(atomic_inc_return);
+EXPORT_SYMBOL(atomic_dec);
+EXPORT_SYMBOL(atomic_dec_return);
+EXPORT_SYMBOL(atomic_dec_and_test);
+
+EXPORT_SYMBOL(set_bit);
+EXPORT_SYMBOL(clear_bit);
+EXPORT_SYMBOL(change_bit);
+EXPORT_SYMBOL(test_and_set_bit);
+EXPORT_SYMBOL(test_and_clear_bit);
+EXPORT_SYMBOL(test_and_change_bit);
+#if 0
+EXPORT_SYMBOL(ffz);
+EXPORT_SYMBOL(find_first_zero_bit);
+EXPORT_SYMBOL(find_next_zero_bit);
+#endif
+
+EXPORT_SYMBOL(strcpy);
+EXPORT_SYMBOL(strncpy);
+EXPORT_SYMBOL(strcat);
+EXPORT_SYMBOL(strncat);
+EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strrchr);
+EXPORT_SYMBOL(strpbrk);
+EXPORT_SYMBOL(strtok);
+EXPORT_SYMBOL(strstr);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strspn);
+EXPORT_SYMBOL(strcmp);
+EXPORT_SYMBOL(strncmp);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(memscan);
+EXPORT_SYMBOL(memcmp);
+
+/* EXPORT_SYMBOL(csum_partial); already in net/netsyms.c */
+EXPORT_SYMBOL(csum_partial_copy_generic);
+EXPORT_SYMBOL(ip_fast_csum);
+EXPORT_SYMBOL(csum_tcpudp_magic);
+
+EXPORT_SYMBOL(__copy_tofrom_user);
+EXPORT_SYMBOL(__clear_user);
+EXPORT_SYMBOL(__strncpy_from_user);
+EXPORT_SYMBOL(strlen_user);
+
+/*
+EXPORT_SYMBOL(inb);
+EXPORT_SYMBOL(inw);
+EXPORT_SYMBOL(inl);
+EXPORT_SYMBOL(outb);
+EXPORT_SYMBOL(outw);
+EXPORT_SYMBOL(outl);
+EXPORT_SYMBOL(outsl);*/
+
+EXPORT_SYMBOL(_insw);
+EXPORT_SYMBOL(_outsw);
+EXPORT_SYMBOL(_insl);
+EXPORT_SYMBOL(_outsl);
+EXPORT_SYMBOL(ioremap);
+
+EXPORT_SYMBOL(start_thread);
+
+EXPORT_SYMBOL(__down_interruptible);
+
+EXPORT_SYMBOL(__cli);
+EXPORT_SYMBOL(__sti);
+/*EXPORT_SYMBOL(__restore_flags);*/
+EXPORT_SYMBOL(_disable_interrupts);
+EXPORT_SYMBOL(_enable_interrupts);
+EXPORT_SYMBOL(flush_instruction_cache);
+EXPORT_SYMBOL(_get_PVR);
+EXPORT_SYMBOL(giveup_fpu);
+EXPORT_SYMBOL(flush_icache_range);
+EXPORT_SYMBOL(xchg_u32);
+
+EXPORT_SYMBOL(cuda_request);
+EXPORT_SYMBOL(cuda_send_request);
+EXPORT_SYMBOL(adb_register);
+EXPORT_SYMBOL(abort);
+EXPORT_SYMBOL(call_prom);
+EXPORT_SYMBOL(find_devices);
+EXPORT_SYMBOL(find_type_devices);
+EXPORT_SYMBOL(find_path_device);
+EXPORT_SYMBOL(get_property);
+EXPORT_SYMBOL(pci_io_base);
+EXPORT_SYMBOL(pci_device_loc);
+EXPORT_SYMBOL(note_scsi_host);
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
--- v2.1.50/linux/arch/ppc/kernel/prep_setup.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/prep_setup.c	Sat Aug 16 09:51:08 1997
@@ -26,6 +26,8 @@
 #include <linux/interrupt.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
+#include <linux/blk.h>
+#include <linux/ioport.h>
 
 #include <asm/mmu.h>
 #include <asm/processor.h>
@@ -42,7 +44,7 @@
 extern unsigned long loops_per_sec;
 
 unsigned long empty_zero_page[1024];
-unsigned char aux_device_present;
+extern unsigned char aux_device_present;
 
 #ifdef CONFIG_BLK_DEV_RAM
 extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
@@ -50,19 +52,8 @@
 extern int rd_image_start;	/* starting block # of image */
 #endif
 
-/* copy of the residual data */
-RESIDUAL res;
-/* ptr to residual data from hw, must be initialized so not in bss (gets cleared )*/
-unsigned long resptr = 0;
-int _machine;
-extern unsigned long _TotalMemory;
-
-#define COMMAND_LINE_SIZE 256
-static char command_line[COMMAND_LINE_SIZE] = { 0, };
-char saved_command_line[COMMAND_LINE_SIZE];
-#ifdef HASHSTATS
-unsigned long evicts;
-#endif
+
+extern char saved_command_line[256];
 
 struct screen_info screen_info = {
 	0, 25,			/* orig-x, orig-y */
@@ -76,49 +67,31 @@
 	16			/* orig-video-points */
 };
 
-void machine_halt(void)
+
+/*
+ * these are here to get by until the pmac/prep merge is done
+ */
+int pmac_display_supported(char *name)
 {
-	machine_restart(NULL);
+	return 0;
 }
-
-void machine_power_off(void)
+int sd_find_target(void *a, int b)
 {
-	machine_restart(NULL);
+	return 0;
 }
-
-void machine_restart(char *cmd)
+void pmac_find_display(void)
 {
-	unsigned char ctl;
-	unsigned long flags;
-	unsigned long i = 10000;
-	
-	_disable_interrupts();
-
-	/* set exception prefix high - to the prom */
-	save_flags( flags );
-	restore_flags( flags|MSR_IP );
-
-	/* make sure bit 0 (reset) is a 0 */
-	outb( inb(0x92) & ~1L , 0x92 );
-	/* signal a reset to system control port A - soft reset */
-	outb( inb(0x92) | 1 , 0x92 );
-
-	while ( i != 0 ) i++;
-	panic("restart failed\n");
 }
 
 int
-get_cpuinfo(char *buffer)
+prep_get_cpuinfo(char *buffer)
 {
 	extern char *Motherboard_map_name;
+	extern RESIDUAL res;
 	int i;
 	int pvr = _get_PVR();
 	int len;
 	char *model;
-	PTE *ptr;
-	unsigned long kptes = 0, uptes = 0, overflow = 0;
-	unsigned int ti;
-  
   
 	switch (pvr>>16)
 	{
@@ -226,8 +199,6 @@
 	/* L2 */
 	if ( (inb(IBM_EQUIP_PRESENT) & 1) == 0) /* l2 present */
 	{
-		int size;
-    
 		len += sprintf(buffer+len,"l2\t\t: %dkB %s\n",
 			       ((inb(IBM_L2_STATUS) >> 5) & 1) ? 512 : 256,
 			       (inb(IBM_SYS_CTL) & 64) ? "enabled" : "disabled");
@@ -246,61 +217,25 @@
 	 * Ooh's and aah's info about zero'd pages in idle task
 	 */ 
 	{
-		extern unsigned int zerocount, zerototal, zeropage_hits;
+		extern unsigned int zerocount, zerototal, zeropage_hits,zeropage_calls;
 		len += sprintf(buffer+len,"zero pages\t: total %u (%uKb) "
-			       "current: %u (%uKb) hits: %u\n",
+			       "current: %u (%uKb) hits: %u/%u (%lu%%)\n",
 			       zerototal, (zerototal*PAGE_SIZE)>>10,
 			       zerocount, (zerocount*PAGE_SIZE)>>10,
-			       zeropage_hits);
-	}
-
-
-	/* ram/hash table info */
-	len += sprintf(buffer+len,"hash table\t: %dkB (%dk buckets)\n",
-		       Hash_size>>10,(Hash_size/(sizeof(PTE)*8)) >> 10);
-
-	/* if booted print info about hash table use (overflows, etc) */
-#ifdef HASHSTATS
-	for ( ptr = Hash ; ptr < (PTE *)(Hash+Hash_size) ; ptr++)
-	{
-		if (ptr->v)
-		{
-			/* user not allowed read or write */
-			if (ptr->pp == PP_RWXX)
-				kptes++;
-			else
-				uptes++;
-			if (ptr->h == 1)
-				overflow++;
-		}
+			       zeropage_hits,zeropage_calls,
+			       /* : 1 below is so we don't div by zero */
+			       (zeropage_hits*100) /
+			            ((zeropage_calls)?zeropage_calls:1));
 	}
-	/*len+=sprintf(buffer+len,"Hash %x Hash+Hash_size %x MemEnd %x\n",
-	  Hash,Hash+Hash_size,KERNELBASE+_TotalMemory);*/
-	/*len += sprintf(buffer+len,"PTEs: (user/kernel/max) %d (%d%%)/%d "
-	  "(%d%%)/%d (%d%% full)\n",
-	  uptes,(uptes*100)/(Hash_size/sizeof(PTE)),
-	  kptes,(kptes*100)/(Hash_size/sizeof(PTE)),
-	  Hash_size/sizeof(PTE),
-	  ((uptes+kptes)*100)/(Hash_size/sizeof(PTE)));
-	  len += sprintf(buffer+len,"Current Ovflw PTE's: %d Total Evicts: %u\n",
-	  overflow,evicts);*/
-#endif /* HASHSTATS */
 	return len;
 }
 
-__initfunc(unsigned long
-bios32_init(unsigned long memory_start, unsigned long memory_end))
-{
-	return memory_start;
-}
-
 __initfunc(void
-setup_arch(char **cmdline_p, unsigned long * memory_start_p,
+prep_setup_arch(char **cmdline_p, unsigned long * memory_start_p,
 	   unsigned long * memory_end_p))
 {
 	extern char cmd_line[];
 	extern char _etext[], _edata[], _end[];
-	unsigned char reg;
 	extern int panic_timeout;
 
 	/* Save unparsed command line copy for /proc/cmdline */
@@ -308,13 +243,13 @@
 	*cmdline_p = cmd_line;
   
 	*memory_start_p = (unsigned long) Hash+Hash_size;
-	(unsigned long *)*memory_end_p = (unsigned long *)(_TotalMemory+KERNELBASE);
+	(unsigned long *)*memory_end_p = (unsigned long *)(res.TotalMemory+KERNELBASE);
 
 	/* init to some ~sane value until calibrate_delay() runs */
 	loops_per_sec = 50000000;
 	
 	/* reboot on panic */	
-	/*panic_timeout = 180;*/
+	panic_timeout = 180;
 	
 	init_task.mm->start_code = PAGE_OFFSET;
 	init_task.mm->end_code = (unsigned long) _etext;
@@ -332,23 +267,7 @@
 		ROOT_DEV = to_kdev_t(0x0801); /* sda1 */
 		break;
 	}
-	/*ROOT_DEV = to_kdev_t(0x0811);*/ /* sdb1 */
-#if 0
-	strcpy(cmd_line+strlen(cmd_line),"console=1,9600,n8");
-#endif
 	
-#if 0  
-	if ( _machine == _MACH_Motorola )
-	{
-		/* get root via nfs from gordito -- only used for testing */
-		ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255);	/* nfs */
-		/*nfsaddrs=myip:serverip:gateip:netmaskip:clientname*/
-		strcpy(cmd_line+strlen(cmd_line),
-		       "nfsaddrs=129.138.6.13:129.138.6.101:129.138.6.1:255.255.255.0:"
-		       "pandora nfsroot=/usr/src/root/");
-	}
-#endif
-  
 #ifdef CONFIG_BLK_DEV_RAM
 #if 0
 	ROOT_DEV = to_kdev_t(0x0200); /* floppy */  
@@ -356,7 +275,20 @@
 	rd_doload = 1;
 	rd_image_start = 0;
 #endif
+	/* initrd_start and size are setup by boot/head.S and kernel/head.S */
+	if ( initrd_start )
+	{
+		if (initrd_end > *memory_end_p)
+		{
+			printk("initrd extends beyond end of memory "
+			       "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+			       initrd_end,*memory_end_p);
+			initrd_start = 0;
+		}
+	}
 #endif
+
+	printk("Boot arguments: %s\n", cmd_line);
 	
 	request_region(0x20,0x20,"pic1");
 	request_region(0xa0,0x20,"pic2");
@@ -365,4 +297,3 @@
 	request_region(0x80,0x10,"dma page reg");
 	request_region(0xc0,0x20,"dma2");
 }
-
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/prep_time.c linux/arch/ppc/kernel/prep_time.c
--- v2.1.50/linux/arch/ppc/kernel/prep_time.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/prep_time.c	Sat Aug 16 09:51:08 1997
@@ -23,18 +23,72 @@
 #include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/processor.h>
+#include <asm/nvram.h>
 
-/* last time the cmos clock got updated */
-static long last_rtc_update = 0;
-static int set_rtc_mmss(unsigned long nowtime);
-unsigned long get_cmos_time(void);
-static inline unsigned long mktime(unsigned int, unsigned int,unsigned int,
+#include "time.h"
+
+inline unsigned long mktime(unsigned int, unsigned int,unsigned int,
 				   unsigned int, unsigned int, unsigned int);
-#define TIMER_IRQ 0
 
-/* Cycle counter value at the previous timer interrupt.. */
-static unsigned long long last_timer_cc = 0;
-static unsigned long long init_timer_cc = 0;
+/*
+ * The motorola uses the m48t18 rtc (includes DS1643) whose registers
+ * are at a higher end of nvram (1ff8-1fff) than the ibm mc146818
+ * rtc (ds1386) which has regs at addr 0-d).  The intel gets
+ * past this because the bios emulates the mc146818.
+ *
+ * Why in the world did they have to use different clocks?
+ *
+ * Right now things are hacked to check which machine we're on then
+ * use the appropriate macro.  This is very very ugly and I should
+ * probably have a function that checks which machine we're on then
+ * does things correctly transparently or a function pointer which
+ * is setup at boot time to use the correct addresses.
+ * -- Cort
+ */
+/*
+ * translate from mc146818 to m48t18  addresses
+ */
+unsigned int clock_transl[] = { MOTO_RTC_SECONDS,0 /* alarm */,
+		       MOTO_RTC_MINUTES,0 /* alarm */,
+		       MOTO_RTC_HOURS,0 /* alarm */,                 /*  4,5 */
+		       MOTO_RTC_DAY_OF_WEEK,
+		       MOTO_RTC_DAY_OF_MONTH,
+		       MOTO_RTC_MONTH,
+		       MOTO_RTC_YEAR,                    /* 9 */
+		       MOTO_RTC_CONTROLA, MOTO_RTC_CONTROLB /* 10,11 */
+};
+
+int prep_cmos_clock_read(int addr)
+{
+	if ( _machine == _MACH_IBM )
+		return CMOS_READ(addr);
+	else if ( _machine == _MACH_Motorola )
+	{
+		outb(clock_transl[addr]>>8, NVRAM_AS1);
+		outb(clock_transl[addr], NVRAM_AS0);
+		return (inb(NVRAM_DATA));
+	}
+
+	printk("Unknown machine in prep_cmos_clock_read()!\n");
+	return -1;
+}
+
+void prep_cmos_clock_write(unsigned long val, int addr)
+{
+	if ( _machine == _MACH_IBM )
+	{
+		CMOS_WRITE(val,addr);
+		return;
+	}
+	else if ( _machine == _MACH_Motorola )
+	{
+		outb(clock_transl[addr]>>8, NVRAM_AS1);
+		outb(clock_transl[addr], NVRAM_AS0);
+		outb(val,NVRAM_DATA);
+		return;
+	}
+	printk("Unknown machine in prep_cmos_clock_write()!\n");
+}
 
 #define TICK_SIZE tick
 #define FEBRUARY	2
@@ -49,6 +103,7 @@
 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
 };
 
+#if 0
 static unsigned long do_slow_gettimeoffset(void)
 {
 	int count;
@@ -69,7 +124,6 @@
 	count = (count + LATCH/2) / LATCH;
 	return offset + count;
 }
-
 static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
 
 /*
@@ -106,6 +160,8 @@
 	sti();
 }
 
+#endif
+
 void to_tm(int tim, struct rtc_time * tm)
 {
 	register int    i;
@@ -139,20 +195,20 @@
 /*
  * Set the hardware clock. -- Cort
  */
-static int set_rtc_mmss(unsigned long nowtime)
+int prep_set_rtc_time(unsigned long nowtime)
 {
-	int retval = 0;
-	int real_seconds, real_minutes, cmos_minutes;
 	unsigned char save_control, save_freq_select;
 	struct rtc_time tm;
 
 	to_tm(nowtime, &tm);
 
-	save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
-	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+	save_control = prep_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
 
-	save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
-	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+	prep_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
+
+	save_freq_select = prep_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
+	
+	prep_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
 
         tm.tm_year -= 1900;
 	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
@@ -163,12 +219,12 @@
 		BIN_TO_BCD(tm.tm_mday);
 		BIN_TO_BCD(tm.tm_year);
 	}
-	CMOS_WRITE(tm.tm_sec,RTC_SECONDS);
-	CMOS_WRITE(tm.tm_min,RTC_MINUTES);
-	CMOS_WRITE(tm.tm_hour,RTC_HOURS);
-	CMOS_WRITE(tm.tm_mon,RTC_MONTH);
-	CMOS_WRITE(tm.tm_mday,RTC_DAY_OF_MONTH);
-	CMOS_WRITE(tm.tm_year,RTC_YEAR);
+	prep_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
+	prep_cmos_clock_write(tm.tm_min,RTC_MINUTES);
+	prep_cmos_clock_write(tm.tm_hour,RTC_HOURS);
+	prep_cmos_clock_write(tm.tm_mon,RTC_MONTH);
+	prep_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
+	prep_cmos_clock_write(tm.tm_year,RTC_YEAR);
 	
 	/* The following flags have to be released exactly in this order,
 	 * otherwise the DS12887 (popular MC146818A clone with integrated
@@ -177,15 +233,15 @@
 	 * 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);
+	prep_cmos_clock_write(save_control, RTC_CONTROL);
+	prep_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
 
 	if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
 		time_state = TIME_OK;
 	return 0;
 }
 
-unsigned long get_cmos_time(void)
+unsigned long prep_get_rtc_time(void)
 {
 	unsigned int year, mon, day, hour, min, sec;
 	int i;
@@ -197,20 +253,20 @@
 	 */
 	/* 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)
+		if (prep_cmos_clock_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))
+		if (!(prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP))
 			break;
 	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));
-	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+		sec = prep_cmos_clock_read(RTC_SECONDS);
+		min = prep_cmos_clock_read(RTC_MINUTES);
+		hour = prep_cmos_clock_read(RTC_HOURS);
+		day = prep_cmos_clock_read(RTC_DAY_OF_MONTH);
+		mon = prep_cmos_clock_read(RTC_MONTH);
+		year = prep_cmos_clock_read(RTC_YEAR);
+	} while (sec != prep_cmos_clock_read(RTC_SECONDS));
+	if (!(prep_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
 	  {
 	    BCD_TO_BIN(sec);
 	    BCD_TO_BIN(min);
@@ -224,19 +280,68 @@
 	return mktime(year, mon, day, hour, min, sec);
 }
 
+/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+ * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
+ * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
+ *
+ * [For the Julian calendar (which was used in Russia before 1917,
+ * Britain & colonies before 1752, anywhere else before 1582,
+ * and is still in use by some communities) leave out the
+ * -year/100+year/400 terms, and add 10.]
+ *
+ * This algorithm was first published by Gauss (I think).
+ *
+ * WARNING: this function will overflow on 2106-02-07 06:28:16 on
+ * machines were long is 32-bit! (However, as time_t is signed, we
+ * will already get problems at other places on 2038-01-19 03:14:08)
+ */
+inline unsigned long mktime(unsigned int year, unsigned int mon,
+				   unsigned int day, unsigned int hour,
+				   unsigned int min, unsigned int sec)
+{
+	
+	if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
+		mon += 12;	/* Puts Feb last since it has leap day */
+		year -= 1;
+	}
+	return (((
+		(unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
+		year*365 - 719499
+		)*24 + hour /* now have hours */
+		)*60 + min /* now have minutes */
+		)*60 + sec; /* finally seconds */
+}
+
+#if 0
+void time_init(void)
+{
+	void (*irq_handler)(int, void *,struct pt_regs *);
+	
+	xtime.tv_sec = prep_get_rtc_time();
+	xtime.tv_usec = 0;
+	
+	prep_calibrate_decr();
+	
+	/* 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!");
+}
+
 /*
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
 static inline void timer_interrupt(int irq, void *dev, struct pt_regs * regs)
 {
+	prep_calibrate_decr_handler(irq,dev,regs);
 	do_timer(regs);
 
 	/* update the hw clock if:
 	 * the time is marked out of sync (TIME_ERROR)
 	 * or ~11 minutes have expired since the last update -- Cort
 	 * If we have an externally synchronized Linux clock, then update
-	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+	 * CMOS clock accordingly every ~11 minutes. prep_set_rtc_mmss() has to be
 	 * called as close as possible to 500 ms before the new second starts.
 	 */
 	if ( time_state == TIME_BAD ||
@@ -244,7 +349,7 @@
 	/*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)
+		if (prep_set_rtc_time(xtime.tv_sec) == 0)
 			last_rtc_update = xtime.tv_sec;
 		else
 			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
@@ -269,47 +374,4 @@
 	}
 #endif
 }
-
-
-/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
- * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
- * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
- *
- * [For the Julian calendar (which was used in Russia before 1917,
- * Britain & colonies before 1752, anywhere else before 1582,
- * and is still in use by some communities) leave out the
- * -year/100+year/400 terms, and add 10.]
- *
- * This algorithm was first published by Gauss (I think).
- *
- * WARNING: this function will overflow on 2106-02-07 06:28:16 on
- * machines were long is 32-bit! (However, as time_t is signed, we
- * will already get problems at other places on 2038-01-19 03:14:08)
- */
-static inline unsigned long mktime(unsigned int year, unsigned int mon,
-				   unsigned int day, unsigned int hour,
-				   unsigned int min, unsigned int sec)
-{
-	if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
-		mon += 12;	/* Puts Feb last since it has leap day */
-		year -= 1;
-	}
-	return (((
-		(unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
-		year*365 - 719499
-		)*24 + hour /* now have hours */
-		)*60 + min /* now have minutes */
-		)*60 + sec; /* finally seconds */
-}
-
-void time_init(void)
-{
-	void (*irq_handler)(int, void *,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!");
-}
+#endif
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- v2.1.50/linux/arch/ppc/kernel/process.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/process.c	Sat Aug 16 09:51:08 1997
@@ -7,7 +7,7 @@
  *  Derived from "arch/i386/kernel/process.c"
  *    Copyright (C) 1995  Linus Torvalds
  *
- *  Modified by Cort Dougan (cort@cs.nmt.edu) and
+ *  Updated and modified by Cort Dougan (cort@cs.nmt.edu) and
  *  Paul Mackerras (paulus@cs.anu.edu.au)
  *
  *  This program is free software; you can redistribute it and/or
@@ -28,22 +28,22 @@
 #include <linux/ptrace.h>
 #include <linux/malloc.h>
 #include <linux/user.h>
-#include <linux/a.out.h>
+#include <linux/elf.h>
 #include <linux/config.h>
+#include <linux/elf.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/smp_lock.h>
+#include <asm/processor.h>
 
-int dump_fpu(void);
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs);
 void switch_to(struct task_struct *, struct task_struct *);
-void print_backtrace(unsigned long *);
-void show_regs(struct pt_regs * regs);
-void inline zero_paged(void);
 extern unsigned long _get_SP(void);
 
+
 #undef SHOW_TASK_SWITCHES 1
 #undef CHECK_STACK 1
 #undef IDLE_ZERO 1
@@ -59,7 +59,7 @@
 {
 	return ((unsigned long)tsk) + sizeof(struct task_struct);
 }
-	
+
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
@@ -69,9 +69,12 @@
 union task_union init_task_union = { INIT_TASK };
 
 int
-dump_fpu(void)
+dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
 {
-	return (1);
+	if (last_task_used_math == current)
+		giveup_fpu();
+	memcpy(fpregs, &current->tss.fpr[0], sizeof(*fpregs));
+	return 1;
 }
 
 /* check to make sure the kernel stack is healthy */
@@ -80,7 +83,6 @@
 	unsigned long stack_top = kernel_stack_top(tsk);
 	unsigned long tsk_top = task_top(tsk);
 	int ret = 0;
-	unsigned long *i;
 
 #if 0	
 	/* check tss magic */
@@ -98,7 +100,7 @@
 	if ( (tsk->tss.ksp > stack_top) || (tsk->tss.ksp < tsk_top) )
 	{
 		printk("stack out of bounds: %s/%d\n"
-		       " tsk_top %08x ksp %08x stack_top %08x\n",
+		       " tsk_top %08lx ksp %08lx stack_top %08lx\n",
 		       tsk->comm,tsk->pid,
 		       tsk_top, tsk->tss.ksp, stack_top);
 		ret |= 2;
@@ -108,7 +110,7 @@
 	if ( (tsk == current) && ((_get_SP() > stack_top ) || (_get_SP() < tsk_top)) )
 	{
 		printk("current stack ptr out of bounds: %s/%d\n"
-		       " tsk_top %08x sp %08x stack_top %08x\n",
+		       " tsk_top %08lx sp %08lx stack_top %08lx\n",
 		       current->comm,current->pid,
 		       tsk_top, _get_SP(), stack_top);
 		ret |= 4;
@@ -143,15 +145,12 @@
 {
 	struct thread_struct *new_tss, *old_tss;
 	int s = _disable_interrupts();
-	struct pt_regs *regs = (struct pt_regs *)(new->tss.ksp+STACK_FRAME_OVERHEAD);
 
 #if CHECK_STACK
 	check_stack(prev);
 	check_stack(new);
 #endif
-        /* turn off fpu for task last to run */
-	/*prev->tss.regs->msr &= ~MSR_FP;*/
-	
+
 #ifdef SHOW_TASK_SWITCHES
 	printk("%s/%d (%x) -> %s/%d (%x) ctx %x\n",
 	       prev->comm,prev->pid,prev->tss.regs->nip,
@@ -160,289 +159,29 @@
 	new_tss = &new->tss;
 	old_tss = &current->tss;
 	_switch(old_tss, new_tss, new->mm->context);
-        /* turn off fpu for task last to run */	
 	_enable_interrupts(s);
 }
-	
-#include <linux/mc146818rtc.h>
-asmlinkage int sys_debug(long a, long b, long c, long d, long e, long f,struct pt_regs *regs)
-{
-#if 1
-	struct task_struct *p;
-	printk("sys_debug(): r3 %x r4 %x r5 %x r6 %x\n", a,b,c,d);
-	printk("last %x\n", last_task_used_math);
-	printk("cur %x regs %x/%x tss %x/%x\n",
-	       current, current->tss.regs,regs,&current->tss,current->tss);
-	for_each_task(p)
-	{
-		if ((long)p < KERNELBASE)
-		{
-			printk("nip %x lr %x r3 %x\n", regs->nip,regs->link,a);
-			print_mm_info();
-			__cli();
-			while(1);
-		}
-	}
-	return regs->gpr[3];
-#endif
-#if 0
-	/* set the time in the cmos clock */
-	unsigned long hwtime, nowtime;
-	struct rtc_time tm;
-	
-	hwtime = get_cmos_time();
-	to_tm(hwtime, &tm);
-	printk("hw: H:M:S M/D/Y %02d:%02d:%02d %d/%d/%d\n", 
-	       tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_mon,
-	       tm.tm_mday, tm.tm_year);
-	return;
-#endif
-}
 
-/*
- * vars for idle task zero'ing out pages
- */
-unsigned long zero_list = 0;	/* head linked list of pre-zero'd pages */
-unsigned long bytecount = 0;	/* pointer into the currently being zero'd page */
-unsigned long zerocount = 0;	/* # currently pre-zero'd pages */
-unsigned long zerototal = 0;	/* # pages zero'd over time -- for ooh's and ahhh's */
-unsigned long pageptr = 0;	/* current page being zero'd */
-unsigned long zeropage_hits = 0;/* # zero'd pages request that we've done */
-
-/*
- * Returns a pre-zero'd page from the list otherwise returns
- * NULL.
- */
-unsigned long get_prezerod_page(void)
+asmlinkage int sys_debug(long a, long b, long c, long d, long e, long f,struct pt_regs *regs)
 {
-	unsigned long page;
-	unsigned long s;
-
-	if ( zero_list )
-	{
-		/* atomically remove this page from the list */
-		asm (	"101:lwarx  %1,0,%2\n"  /* reserve zero_list */
-			"    lwz    %0,0(%1)\n" /* get next -- new zero_list */
-			"    stwcx. %0,0,%2\n"  /* update zero_list */
-			"    bne-   101b\n"     /* if lost reservation try again */
-			: "=&r" (zero_list), "=&r" (page)
-			: "r" (&zero_list)
-			: "cc" );
-		/* we can update zerocount after the fact since it is not
-		 * used for anything but control of a loop which doesn't
-		 * matter since it won't effect anything if it zero's one
-		 * less page -- Cort
-		 */
-		atomic_inc((atomic_t *)&zeropage_hits);
-		atomic_dec((atomic_t *)&zerocount);
-		/* zero out the pointer to next in the page */
-		*(unsigned long *)page = 0;
-		return page;
-	}
 	return 0;
 }
 
-/*
- * Experimental stuff to zero out pages in the idle task
- * to speed up get_free_pages() -- Cort
- * Zero's out pages until we need to resched or
- * we've reached the limit of zero'd pages.
- */
-void inline zero_paged(void)
-{
-	extern pte_t *get_pte( struct mm_struct *mm, unsigned long address );
-	unsigned long tmp;
-	pte_t ptep;
-	pgd_t *dir;
-	pmd_t *pmd;
-	pte_t *pte;
-
-	sprintf(current->comm, "zero_paged");
-	printk("Started zero_paged\n");
-	/* want priority over idle task and powerd */
-	current->priority = -98;
-	current->counter = -98;
-	__sti();
-	
-	while ( zerocount < 128 )
-	{
-		/*
-		 * Mark a page as reserved so we can mess with it
-		 * If we're interrupted we keep this page and our place in it
-		 * since we validly hold it and it's reserved for us.
-		 */
-		pageptr = __get_free_pages(GFP_ATOMIC, 0, 0 );
-		if ( !pageptr )
-		{
-			printk("!pageptr in zero_paged\n");
-			goto retry;
-		}
-		
-		if ( need_resched )
-			schedule();
-		
-		/*
-		 * Make the page no cache so we don't blow our cache with 0's
-		 */
-		dir = pgd_offset( init_task.mm, pageptr );
-		if (dir)
-		{
-			pmd = pmd_offset(dir, pageptr & PAGE_MASK);
-			if (pmd && pmd_present(*pmd))
-			{
-				pte = pte_offset(pmd, pageptr & PAGE_MASK);
-				if (pte && pte_present(*pte))
-				{			
-					pte_uncache(*pte);
-					flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
-				}
-			}
-		}
-	
-		/*
-		 * Important here to not take time away from real processes.
-		 */
-		for ( bytecount = 0; bytecount < PAGE_SIZE ; bytecount += 4 )
-		{
-			if ( need_resched )
-				schedule();
-			*(unsigned long *)(bytecount + pageptr) = 0;
-		}
-		
-		/*
-		 * If we finished zero-ing out a page add this page to
-		 * the zero_list atomically -- we can't use
-		 * down/up since we can't sleep in idle.
-		 * Disabling interrupts is also a bad idea since we would
-		 * steal time away from real processes.
-		 * We can also have several zero_paged's running
-		 * on different processors so we can't interfere with them.
-		 * So we update the list atomically without locking it.
-		 * -- Cort
-		 */
-		/* turn cache on for this page */
-		pte_cache(*pte);
-		flush_tlb_page(find_vma(init_task.mm,pageptr),pageptr);
-		
-		/* atomically add this page to the list */
-		asm (	"101:lwarx  %0,0,%1\n"  /* reserve zero_list */
-			"    stw    %0,0(%2)\n" /* update *pageptr */
-#ifdef __SMP__
-			"    sync\n"            /* let store settle */
-#endif			
-			"    mr     %0,%2\n"    /* update zero_list in reg */
-			"    stwcx. %2,0,%1\n"  /* update zero_list in mem */
-			"    bne-   101b\n"     /* if lost reservation try again */
-			: "=&r" (zero_list)
-			: "r" (&zero_list), "r" (pageptr)
-			: "cc" );
-		/*
-		 * This variable is used in the above loop and nowhere
-		 * else so the worst that could happen is we would
-		 * zero out one more or one less page than we want
-		 * per processor on the machine.  This is because
-		 * we could add our page to the list but not have
-		 * zerocount updated yet when another processor
-		 * reads it.  -- Cort
-		 */
-		atomic_inc((atomic_t *)&zerocount);
-		atomic_inc((atomic_t *)&zerototal);
-retry:	
-		schedule();
-	}
-}
-
-void powerd(void)
-{
-	unsigned long msr, hid0;
-
-	sprintf(current->comm, "powerd");
-	__sti();
-	while (1)
-	{
-		/* want priority over idle task 'swapper' -- Cort */
-		current->priority = -99;
-		current->counter = -99;
-		asm volatile(
-			/* clear powersaving modes and set nap mode */
-			"mfspr %3,1008 \n\t"
-			"andc  %3,%3,%4 \n\t"
-			"or    %3,%3,%5 \n\t"
-			"mtspr 1008,%3 \n\t"
-			/* enter the mode */
-			"mfmsr %0 \n\t"
-			"oris  %0,%0,%2 \n\t"
-			"sync \n\t"
-			"mtmsr %0 \n\t"
-			"isync \n\t"
-			: "=&r" (msr)
-			: "0" (msr), "i" (MSR_POW>>16),
-			"r" (hid0),
-			"r" (HID0_DOZE|HID0_NAP|HID0_SLEEP),
-			"r" (HID0_NAP));
-		if ( need_resched )
-			schedule();
-		/*
-		 * The ibm carolina spec says that the eagle memory
-		 * controller will detect the need for a snoop
-		 * and wake up the processor so we don't need to
-		 * check for cache operations that need to be
-		 * snooped.  The ppc book says the run signal
-		 * must be asserted while napping for this though.
-		 * -- Cort
-		 */
-	}
-}
-	
-asmlinkage int sys_idle(void)
-{
-	int ret = -EPERM;
-	if (current->pid != 0)
-		goto out;
-
-#ifdef IDLE_ZERO
-	/*
-	 * want one per cpu since it would be nice to have all
-	 * processors who aren't doing anything
-	 * zero-ing pages since this daemon is lock-free
-	 * -- Cort
-	 */
-	kernel_thread(zero_paged, NULL, 0);
-#endif /* IDLE_ZERO */
-
-#ifdef CONFIG_POWERSAVING
-	/* no powersaving modes on 601 - one per processor */
-	if(  (_get_PVR()>>16) != 1 )
-		kernel_thread(powerd, NULL, 0);
-#endif /* CONFIG_POWERSAVING */
-	
-	/* endless loop with no priority at all */
-	current->priority = -100;
-	current->counter = -100;
-	for (;;) 
-	{
-		schedule();
-	}
-	ret = 0;
-out:
-	return ret;
-}
-
 void show_regs(struct pt_regs * regs)
 {
 	int i;
 
-	printk("NIP: %08X XER: %08X LR: %08X REGS: %08X TRAP: %04x\n",
+	printk("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx\n",
 	       regs->nip, regs->xer, regs->link, regs,regs->trap);
-	printk("MSR: %08x EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
+	printk("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n",
 	       regs->msr, regs->msr&MSR_EE ? 1 : 0, regs->msr&MSR_PR ? 1 : 0,
 	       regs->msr & MSR_FP ? 1 : 0,regs->msr&MSR_ME ? 1 : 0,
 	       regs->msr&MSR_IR ? 1 : 0,
 	       regs->msr&MSR_DR ? 1 : 0);
-	printk("TASK = %x[%d] '%s' mm->pgd %08X ",
+	printk("TASK = %p[%d] '%s' mm->pgd %p ",
 	       current, current->pid, current->comm, current->mm->pgd);
-	printk("Last syscall: %d ", current->tss.last_syscall);
-	printk("\nlast math %08X\n", last_task_used_math);
+	printk("Last syscall: %ld ", current->tss.last_syscall);
+	printk("\nlast math %p\n", last_task_used_math);
 	for (i = 0;  i < 32;  i++)
 	{
 		long r;
@@ -451,9 +190,9 @@
 			printk("GPR%02d: ", i);
 		}
 
-		if ( get_user(r, &(regs->gpr[i])) )
+		if ( __get_user(r, &(regs->gpr[i])) )
 		    goto out;
-		printk("%08X ", r);
+		printk("%08lX ", r);
 		if ((i % 8) == 7)
 		{
 			printk("\n");
@@ -480,14 +219,14 @@
 }
 
 /*
-  * Copy a thread..
-  */
+ * Copy a thread..
+ */
 int
 copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
 	    struct task_struct * p, struct pt_regs * regs)
 {
-	int i;
 	struct pt_regs * childregs;
+
 	/* Copy registers */
 	childregs = ((struct pt_regs *)
 		     ((unsigned long)p + sizeof(union task_union)
@@ -497,13 +236,13 @@
 	if ((childregs->msr & MSR_PR) == 0)
 		childregs->gpr[2] = (unsigned long) p;	/* `current' in new task */
 	childregs->gpr[3] = 0;  /* Result from fork() */
-	p->tss.ksp = (unsigned long)(childregs) - STACK_FRAME_OVERHEAD;
-	p->tss.regs = (struct pt_regs *)(childregs);
-	if (usp >= (unsigned long)regs)
-	{ /* Stack is in kernel space - must adjust */
-		childregs->gpr[1] = (long)(childregs+1);
-	} else
-	{ /* Provided stack is in user space */
+	p->tss.ksp = (unsigned long) childregs - STACK_FRAME_OVERHEAD;
+	p->tss.regs = childregs;
+	if (usp >= (unsigned long) regs) {
+		/* Stack is in kernel space - must adjust */
+		childregs->gpr[1] = (unsigned long)(childregs + 1);
+	} else {
+		/* Provided stack is in user space */
 		childregs->gpr[1] = usp;
 	}
 
@@ -511,24 +250,75 @@
 
 	/*
 	 * copy fpu info - assume lazy fpu switch now always
-	 * this should really be conditional on whether or
-	 * not the process has used the fpu
 	 *  -- Cort
 	 */
 	if ( last_task_used_math == current )
 		giveup_fpu();
-	
+
 	memcpy(&p->tss.fpr, &current->tss.fpr, sizeof(p->tss.fpr));
 	p->tss.fpscr = current->tss.fpscr;
 	childregs->msr &= ~MSR_FP;
-	
+
 	return 0;
 }
 
+/*
+ * XXX ld.so expects the auxiliary table to start on
+ * a 16-byte boundary, so we have to find it and
+ * move it up. :-(
+ */
+static inline void shove_aux_table(unsigned long sp)
+{
+	int argc;
+	char *p;
+	unsigned long e;
+	unsigned long aux_start, offset;
+
+	if (__get_user(argc, (int *)sp))
+		return;
+	sp += sizeof(int) + (argc + 1) * sizeof(char *);
+	/* skip over the environment pointers */
+	do {
+		if (__get_user(p, (char **)sp))
+			return;
+		sp += sizeof(char *);
+	} while (p != NULL);
+	aux_start = sp;
+	/* skip to the end of the auxiliary table */
+	do {
+		if (__get_user(e, (unsigned long *)sp))
+			return;
+		sp += 2 * sizeof(unsigned long);
+	} while (e != AT_NULL);
+	offset = ((aux_start + 15) & ~15) - aux_start;
+	if (offset != 0) {
+		do {
+			sp -= sizeof(unsigned long);
+			if (__get_user(e, (unsigned long *)sp)
+			    || __put_user(e, (unsigned long *)(sp + offset)))
+				return;
+		} while (sp > aux_start);
+	}
+}
+
+/*
+ * Set up a thread for executing a new program
+ */
+void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp)
+{
+	set_fs(USER_DS);
+	regs->nip = nip;
+	regs->gpr[1] = sp;
+	regs->msr = MSR_USER;
+	shove_aux_table(sp);
+}
+
+
 asmlinkage int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
 			struct pt_regs *regs)
 {
 	int ret;
+
 	lock_kernel();
 	ret = do_fork(SIGCHLD, regs->gpr[1], regs);
 	unlock_kernel();
@@ -541,26 +331,26 @@
 {
 	int error;
 	char * filename;
-	filename = (int) getname((char *) a0);
+	
+	filename = getname((char *) a0);
 	error = PTR_ERR(filename);
-	if(IS_ERR(filename))
+	if (IS_ERR(filename))
 		goto out;
 	if ( last_task_used_math == current )
 		last_task_used_math = NULL;
 	error = do_execve(filename, (char **) a1, (char **) a2, regs);
-
 	putname(filename);
-
 out:
 	unlock_kernel();
 	return error;
 }
 
-asmlinkage int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6, struct pt_regs *regs)
+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;
 	int res;
-	
+
 	lock_kernel();
 	res = do_fork(clone_flags, regs->gpr[1], regs);
 	unlock_kernel();
@@ -571,34 +361,23 @@
 print_backtrace(unsigned long *sp)
 {
 	int cnt = 0;
-	int i;
+	unsigned long i;
+
 	printk("Call backtrace: ");
-	while ( !get_user(i, sp) && i)
-	{
-		if ( get_user( i, &sp[1] ) )
-			return;
-		printk("%08X ", i);
-		if ( get_user( (ulong)sp, sp) )
-		    return;
-		if (cnt == 6 ) cnt = 7; /* wraparound early -- Cort */
-		if (++cnt == 8)
-		{
+	while (sp) {
+		if (__get_user( i, &sp[1] ))
+			break;
+		if (cnt++ % 7 == 0)
 			printk("\n");
-		}
+		printk("%08lX ", i);
 		if (cnt > 32) break;
+		if (__get_user(sp, (unsigned long **)sp))
+			break;
 	}
 	printk("\n");
 }
 
-inline void start_thread(struct pt_regs * regs,
-                         unsigned long eip, unsigned long esp)
-{
-	set_fs(USER_DS);
-	regs->nip = eip;
-	regs->gpr[1] = esp;
-	regs->msr = MSR_USER;
-}
-
+#if 0
 /*
  * Low level print for debugging - Cort
  */
@@ -651,3 +430,4 @@
 	orig_x = x;
 	orig_y = y;
 }
+#endif /* CONFIG_PREP */
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- v2.1.50/linux/arch/ppc/kernel/prom.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/prom.c	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,523 @@
+/*
+ * Procedures for interfacing to the Open Firmware PROM on
+ * Power Macintosh computers.
+ *
+ * In particular, we are interested in the device tree
+ * and in using some of its services (exit, write to stdout).
+ *
+ * Paul Mackerras	August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#include <stdarg.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <asm/prom.h>
+#include <asm/page.h>
+
+#define getpromprop(node, name, buf, len)	\
+	((int)call_prom("getprop", 4, 1, (node), (name), (buf), (len)))
+
+ihandle prom_stdout;
+ihandle prom_chosen;
+
+char command_line[256];
+int screen_initialized = 0;
+
+char prom_display_path[128];
+
+struct prom_args {
+	const char *service;
+	int nargs;
+	int nret;
+	void *args[10];
+} prom_args;
+
+struct pci_address {
+	unsigned a_hi;
+	unsigned a_mid;
+	unsigned a_lo;
+};
+
+struct pci_reg_property {
+	struct pci_address addr;
+	unsigned size_hi;
+	unsigned size_lo;
+};
+
+struct pci_range {
+	struct pci_address addr;
+	unsigned phys;
+	unsigned size_hi;
+	unsigned size_lo;
+};
+
+void (*prom_entry)(void *);
+extern int prom_trashed;
+
+static int prom_callback(struct prom_args *);
+static unsigned long inspect_node(phandle, struct device_node *, unsigned long,
+				  unsigned long, unsigned long);
+static void check_display(void);
+static int prom_next_node(phandle *);
+
+extern int pmac_display_supported(const char *);
+extern void enter_prom(void *);
+
+void
+prom_exit()
+{
+	struct prom_args args;
+
+	args.service = "exit";
+	args.nargs = 0;
+	args.nret = 0;
+	enter_prom(&args);
+	for (;;)			/* should never get here */
+		;
+}
+
+void *
+call_prom(const char *service, int nargs, int nret, ...)
+{
+	va_list list;
+	int i;
+
+	if (prom_trashed)
+		panic("prom called after its memory was reclaimed");
+	prom_args.service = service;
+	prom_args.nargs = nargs;
+	prom_args.nret = nret;
+	va_start(list, nret);
+	for (i = 0; i < nargs; ++i)
+		prom_args.args[i] = va_arg(list, void *);
+	va_end(list);
+	for (i = 0; i < nret; ++i)
+		prom_args.args[i + nargs] = 0;
+	enter_prom(&prom_args);
+	return prom_args.args[nargs];
+}
+
+void
+prom_print(const char *msg)
+{
+	const char *p, *q;
+	const char *crlf = "\r\n";
+
+	if (screen_initialized)
+		return;
+	for (p = msg; *p != 0; p = q) {
+		for (q = p; *q != 0 && *q != '\n'; ++q)
+			;
+		if (q > p)
+			call_prom("write", 3, 1, prom_stdout, p, q - p);
+		if (*q != 0) {
+			++q;
+			call_prom("write", 3, 1, prom_stdout, crlf, 2);
+		}
+	}
+}
+
+/*
+ * We enter here early on, when the Open Firmware prom is still
+ * handling exceptions and the MMU hash table for us.
+ */
+void
+prom_init(char *params, int unused, void (*pp)(void *))
+{
+	/* First get a handle for the stdout device */
+	if ( _machine != _MACH_Pmac ) /* prep */
+		return;
+	prom_entry = pp;
+	prom_chosen = call_prom("finddevice", 1, 1, "/chosen");
+	if (prom_chosen == (void *)-1)
+		prom_exit();
+	call_prom("getprop", 4, 1, prom_chosen, "stdout", &prom_stdout,
+		  (void *) sizeof(prom_stdout));
+
+	/*
+	 * If we were booted via quik, params points to the physical address
+	 * of the command-line parameters.
+	 * If we were booted from an xcoff image (i.e. netbooted or
+	 * booted from floppy), we get the command line from the bootargs
+	 * property of the /chosen node.  If an initial ramdisk is present,
+	 * params and unused are used for initrd_start and initrd_size,
+	 * otherwise they contain 0xdeadbeef.  
+	 */
+	command_line[0] = 0;
+	if ((unsigned long) params >= 0x4000
+	    && (unsigned long) params < 0x800000
+	    && unused == 0) {
+		strncpy(command_line, params+KERNELBASE, sizeof(command_line));
+	} else {
+#ifdef CONFIG_BLK_DEV_INITRD
+		if ((unsigned long) params - KERNELBASE < 0x800000
+		    && unused != 0 && unused != 0xdeadbeef) {
+			initrd_start = (unsigned long) params;
+			initrd_end = initrd_start + unused;
+			ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+		}
+#endif
+		call_prom("getprop", 4, 1, prom_chosen, "bootargs",
+			  command_line, sizeof(command_line));
+	}
+	command_line[sizeof(command_line) - 1] = 0;
+
+	check_display();
+}
+
+/*
+ * If we have a display that we don't know how to drive,
+ * we will want to try to execute OF's open method for it
+ * later.  However, OF may fall over if we do that after
+ * we've taken over the MMU and done set_prom_callback.
+ * So we check whether we will need to open the display,
+ * and if so, open it now.
+ */
+static void
+check_display()
+{
+	phandle node;
+	ihandle ih;
+	char type[16], name[64], path[128];
+
+	for (node = 0; prom_next_node(&node); ) {
+		type[0] = 0;
+		getpromprop(node, "device_type", type, sizeof(type));
+		if (strcmp(type, "display") != 0)
+			continue;
+		name[0] = 0;
+		getpromprop(node, "name", name, sizeof(name));
+		if (pmac_display_supported(name))
+			/* we have a supported display */
+			return;
+	}
+	printk(KERN_INFO "No supported display found\n");
+	for (node = 0; prom_next_node(&node); ) {
+		type[0] = 0;
+		getpromprop(node, "device_type", type, sizeof(type));
+		if (strcmp(type, "display") != 0)
+			continue;
+		/* It seems OF doesn't null-terminate the path :-( */
+		memset(path, 0, sizeof(path));
+		if ((int) call_prom("package-to-path", 3, 1,
+				    node, path, sizeof(path) - 1) < 0) {
+			printk(KERN_WARNING "can't get path for display %p\n",
+			       node);
+			continue;
+		}
+		ih = call_prom("open", 1, 1, path);
+		if (ih == 0 || ih == (ihandle) -1) {
+			printk(KERN_WARNING "couldn't open display %s\n",
+			       path);
+			continue;
+		}
+		printk(KERN_INFO "Opened display device %s using "
+		       "Open Firmware\n", path);
+		strcpy(prom_display_path, path);
+		break;
+	}
+}
+
+static int
+prom_next_node(phandle *nodep)
+{
+	phandle node;
+
+	if ((node = *nodep) != 0
+	    && (*nodep = call_prom("child", 1, 1, node)) != 0)
+		return 1;
+	if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+		return 1;
+	for (;;) {
+		if ((node = call_prom("parent", 1, 1, node)) == 0)
+			return 0;
+		if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+			return 1;
+	}
+}
+
+/*
+ * Callback routine for the PROM to call us.
+ * No services are implemented yet :-)
+ */
+static int
+prom_callback(struct prom_args *argv)
+{
+	printk("uh oh, prom callback '%s' (%d/%d)\n", argv->service,
+	       argv->nargs, argv->nret);
+	return -1;
+}
+
+/*
+ * Register a callback with the Open Firmware PROM so it can ask
+ * us to map/unmap memory, etc.
+ */
+void
+set_prom_callback()
+{
+	call_prom("set-callback", 1, 1, prom_callback);
+}
+
+void
+abort()
+{
+#ifdef CONFIG_XMON
+	xmon(0);
+#endif
+	prom_exit();
+}
+
+/*
+ * Make a copy of the device tree from the PROM.
+ */
+
+static struct device_node *allnodes;
+static struct device_node **allnextp;
+
+#define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
+
+unsigned long
+copy_device_tree(unsigned long mem_start, unsigned long mem_end)
+{
+	phandle root;
+
+	root = call_prom("peer", 1, 1, (phandle)0);
+	if (root == (phandle)0)
+		panic("couldn't get device tree root\n");
+	allnextp = &allnodes;
+	mem_start = inspect_node(root, 0, 0, mem_start, mem_end);
+	*allnextp = 0;
+	return mem_start;
+}
+
+static unsigned long
+inspect_node(phandle node, struct device_node *dad, unsigned long base_address,
+	     unsigned long mem_start, unsigned long mem_end)
+{
+	struct reg_property *reg, *rp;
+	struct pci_reg_property *pci_addrs;
+	int l, i;
+	phandle child;
+	struct device_node *np;
+	struct property *pp, **prev_propp;
+	char *prev_name;
+
+	np = (struct device_node *) mem_start;
+	mem_start += sizeof(struct device_node);
+	memset(np, 0, sizeof(*np));
+	np->node = node;
+	*allnextp = np;
+	allnextp = &np->allnext;
+	np->parent = dad;
+	if (dad != 0) {
+		/* we temporarily use the `next' field as `last_child'. */
+		if (dad->next == 0)
+			dad->child = np;
+		else
+			dad->next->sibling = np;
+		dad->next = np;
+	}
+
+	/* get and store all properties */
+	prev_propp = &np->properties;
+	prev_name = 0;
+	for (;;) {
+		pp = (struct property *) mem_start;
+		pp->name = (char *) (pp + 1);
+		if ((int) call_prom("nextprop", 3, 1, node, prev_name,
+				    pp->name) <= 0)
+			break;
+		mem_start = ALIGN((unsigned long)pp->name
+				  + strlen(pp->name) + 1);
+		pp->value = (unsigned char *) mem_start;
+		pp->length = (int)
+			call_prom("getprop", 4, 1, node, pp->name, pp->value,
+				  mem_end - mem_start);
+		if (pp->length < 0)
+			panic("hey, where did property %s go?", pp->name);
+		mem_start = ALIGN(mem_start + pp->length);
+		prev_name = pp->name;
+		*prev_propp = pp;
+		prev_propp = &pp->next;
+	}
+	*prev_propp = 0;
+
+	np->name = get_property(np, "name", 0);
+	np->type = get_property(np, "device_type", 0);
+
+	/* get all the device addresses and interrupts */
+	reg = (struct reg_property *) mem_start;
+	pci_addrs = (struct pci_reg_property *)
+		get_property(np, "assigned-addresses", &l);
+	i = 0;
+	if (pci_addrs != 0) {
+		while ((l -= sizeof(struct pci_reg_property)) >= 0) {
+			/* XXX assumes PCI addresses mapped 1-1 to physical */
+			reg[i].address = pci_addrs[i].addr.a_lo;
+			reg[i].size = pci_addrs[i].size_lo;
+			++i;
+		}
+	} else {
+		rp = (struct reg_property *) get_property(np, "reg", &l);
+		if (rp != 0) {
+			while ((l -= sizeof(struct reg_property)) >= 0) {
+				reg[i].address = rp[i].address + base_address;
+				reg[i].size = rp[i].size;
+				++i;
+			}
+		}
+	}
+	if (i > 0) {
+		np->addrs = reg;
+		np->n_addrs = i;
+		mem_start += i * sizeof(struct reg_property);
+	}
+
+	np->intrs = (int *) get_property(np, "AAPL,interrupts", &l);
+	if (np->intrs != 0)
+		np->n_intrs = l / sizeof(int);
+
+	/* get the node's full name */
+	l = (int) call_prom("package-to-path", 3, 1, node,
+			    (char *) mem_start, mem_end - mem_start);
+	if (l >= 0) {
+		np->full_name = (char *) mem_start;
+		np->full_name[l] = 0;
+		mem_start = ALIGN(mem_start + l + 1);
+	}
+
+	if (np->type != 0 && strcmp(np->type, "dbdma") == 0 && np->n_addrs > 0)
+		base_address = np->addrs[0].address;
+
+	child = call_prom("child", 1, 1, node);
+	while (child != (void *)0) {
+		mem_start = inspect_node(child, np, base_address,
+					 mem_start, mem_end);
+		child = call_prom("peer", 1, 1, child);
+	}
+
+	return mem_start;
+}
+
+/*
+ * Construct a return a list of the device_nodes with a given name.
+ */
+struct device_node *
+find_devices(const char *name)
+{
+	struct device_node *head, **prevp, *np;
+
+	prevp = &head;
+	for (np = allnodes; np != 0; np = np->allnext) {
+		if (np->name != 0 && strcasecmp(np->name, name) == 0) {
+			*prevp = np;
+			prevp = &np->next;
+		}
+	}
+	*prevp = 0;
+	return head;
+}
+
+/*
+ * Construct a return a list of the device_nodes with a given type.
+ */
+struct device_node *
+find_type_devices(const char *type)
+{
+	struct device_node *head, **prevp, *np;
+
+	prevp = &head;
+	for (np = allnodes; np != 0; np = np->allnext) {
+		if (np->type != 0 && strcasecmp(np->type, type) == 0) {
+			*prevp = np;
+			prevp = &np->next;
+		}
+	}
+	*prevp = 0;
+	return head;
+}
+
+/*
+ * Find the device_node with a given full_name.
+ */
+struct device_node *
+find_path_device(const char *path)
+{
+	struct device_node *np;
+
+	for (np = allnodes; np != 0; np = np->allnext)
+		if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)
+			return np;
+	return NULL;
+}
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+unsigned char *
+get_property(struct device_node *np, const char *name, int *lenp)
+{
+	struct property *pp;
+
+	for (pp = np->properties; pp != 0; pp = pp->next)
+		if (strcmp(pp->name, name) == 0) {
+			if (lenp != 0)
+				*lenp = pp->length;
+			return pp->value;
+		}
+	return 0;
+}
+
+void
+print_properties(struct device_node *np)
+{
+	struct property *pp;
+	char *cp;
+	int i, n;
+
+	for (pp = np->properties; pp != 0; pp = pp->next) {
+		printk(KERN_INFO "%s", pp->name);
+		for (i = strlen(pp->name); i < 16; ++i)
+			printk(" ");
+		cp = (char *) pp->value;
+		for (i = pp->length; i > 0; --i, ++cp)
+			if ((i > 1 && (*cp < 0x20 || *cp > 0x7e))
+			    || (i == 1 && *cp != 0))
+				break;
+		if (i == 0 && pp->length > 1) {
+			/* looks like a string */
+			printk(" %s\n", (char *) pp->value);
+		} else {
+			/* dump it in hex */
+			n = pp->length;
+			if (n > 64)
+				n = 64;
+			if (pp->length % 4 == 0) {
+				unsigned int *p = (unsigned int *) pp->value;
+
+				n /= 4;
+				for (i = 0; i < n; ++i) {
+					if (i != 0 && (i % 4) == 0)
+						printk("\n                ");
+					printk(" %08x", *p++);
+				}
+			} else {
+				unsigned char *bp = pp->value;
+
+				for (i = 0; i < n; ++i) {
+					if (i != 0 && (i % 16) == 0)
+						printk("\n                ");
+					printk(" %02x", *bp++);
+				}
+			}
+			printk("\n");
+			if (pp->length > 64)
+				printk("                 ... (length = %d)\n",
+				       pp->length);
+		}
+	}
+}
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c
--- v2.1.50/linux/arch/ppc/kernel/ptrace.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/ptrace.c	Sat Aug 16 09:51:08 1997
@@ -171,8 +171,11 @@
 		goto repeat;
 	}
 /* this is a hack for non-kernel-mapped video buffers and similar */
-	if (MAP_NR(page) < max_mapnr)
-		*(unsigned long *) (page + (addr & ~PAGE_MASK)) = data;
+	if (MAP_NR(page) < max_mapnr) {
+		unsigned long phys_addr = page + (addr & ~PAGE_MASK);
+		*(unsigned long *) phys_addr = data;
+		flush_icache_range(phys_addr, phys_addr+4);
+	}
 /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
 /* this should also re-instate whatever read-only mode there was before */
 	set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
@@ -364,7 +367,7 @@
 		case PTRACE_PEEKUSR: {
 			unsigned long tmp;
 			
-			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) {
+			if ((addr & 3) || addr < 0 || addr > (PT_FPSCR << 2)) {
 				ret = -EIO;
 				goto out;
 			}
@@ -378,13 +381,11 @@
 			if (addr < PT_FPR0) {
 				tmp = get_reg(child, addr);
 			}
-#if 1
-			else if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
+			else if (addr >= PT_FPR0 && addr <= PT_FPSCR) {
 				if (last_task_used_math == child)
 					giveup_fpu();
 				tmp = ((long *)child->tss.fpr)[addr - PT_FPR0];
 			}
-#endif
 			else
 				ret = -EIO;
 			if (!ret)
@@ -400,7 +401,7 @@
 
 		case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
 			ret = -EIO;
-			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
+			if ((addr & 3) || addr < 0 || addr >= ((PT_FPR0 + 64) << 2))
 				goto out;
 
 			addr = addr >> 2; /* temporary hack. */
@@ -508,7 +509,7 @@
 		goto out;
 	current->exit_code = SIGTRAP;
 	current->state = TASK_STOPPED;
-	notify_parent(current);
+	notify_parent(current, SIGCHLD);
 	schedule();
 	/*
 	 * this isn't the same as continuing with a signal, but it will do
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.1.50/linux/arch/ppc/kernel/setup.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/setup.c	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,173 @@
+/*
+ * $Id: setup.c,v 1.12 1997/08/13 03:06:17 cort Exp $
+ * Common prep/pmac boot and setup code.
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+
+#include <asm/cuda.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+
+char saved_command_line[256];
+unsigned char aux_device_present;
+
+/* copy of the residual data */
+RESIDUAL res;
+int _machine;
+
+/*
+ * Find out what kind of machine we're on and save any data we need
+ * from the early boot process (devtree is copied on pmac by prom_init() )
+ */
+unsigned long identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
+			       unsigned long r6, unsigned long r7)
+{
+	extern unsigned long initrd_start, initrd_end;
+	extern char cmd_line[256];
+#ifdef CONFIG_PMAC /* cheat for now - perhaps a check for OF could tell us */
+	_machine = _MACH_Pmac;
+#endif /* CONFIG_PMAC */
+#ifdef CONFIG_PREP
+	if (!strncmp(res.VitalProductData.PrintableModel,"IBM",3))
+		_machine = _MACH_IBM;
+	else
+		_machine = _MACH_Motorola;
+#endif /* CONFIG_PREP */
+	
+	if ( _machine == _MACH_Pmac )
+	{
+		io_base = 0;
+	}
+	else if ( is_prep ) /* prep */
+	{
+		io_base = 0x80000000;
+		/* make a copy of residual data */
+		if ( r3 )
+			memcpy( (void *)&res,(void *)(r3+KERNELBASE), sizeof(RESIDUAL) );
+		/* take care of initrd if we have one */
+		if ( r4 )
+		{
+			initrd_start = r4 + KERNELBASE;
+			initrd_end = r5 + KERNELBASE;
+		}
+		/* take care of cmd line */
+		if ( r6 )
+		{
+			
+			*(char *)(r7+KERNELBASE) = 0;
+			strcpy(cmd_line, (char *)(r6+KERNELBASE));
+		}
+	}
+	else
+	{
+		printk("Unknown machine type in identify_machine!\n");
+	}
+	return 0;
+}
+
+/* cmd is ignored for now... */
+void machine_restart(char *cmd)
+{
+	struct cuda_request req;
+	unsigned long flags;
+	unsigned long i = 10000;
+
+	if ( _machine == _MACH_Pmac )
+	{
+		cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM);
+		for (;;)
+			cuda_poll();
+	}
+	else /* prep */
+	{
+		_disable_interrupts();
+		
+		/* set exception prefix high - to the prom */
+		save_flags( flags );
+		restore_flags( flags|MSR_IP );
+		
+		/* make sure bit 0 (reset) is a 0 */
+		outb( inb(0x92) & ~1L , 0x92 );
+		/* signal a reset to system control port A - soft reset */
+		outb( inb(0x92) | 1 , 0x92 );
+		
+		while ( i != 0 ) i++;
+		panic("restart failed\n");
+	}
+
+}
+
+void machine_power_off(void)
+{
+	struct cuda_request req;
+
+	if ( _machine == _MACH_Pmac )
+	{
+		cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN);
+		for (;;)
+			cuda_poll();
+	}
+	else /* prep */
+	{
+		machine_restart(NULL);
+	}
+}
+
+void machine_halt(void)
+{
+	if ( _machine == _MACH_Pmac )
+	{
+#if 0
+		prom_exit();		/* doesn't work because prom is trashed */
+#else
+		machine_power_off();	/* for now */
+#endif
+	}
+	else /* prep */
+		machine_restart(NULL);
+
+}
+
+
+__initfunc(unsigned long
+bios32_init(unsigned long memory_start, unsigned long memory_end))
+{
+	return memory_start;
+}
+
+/*
+ * Will merge more into here later  -- Cort
+ */
+int get_cpuinfo(char *buffer)
+{
+	extern int pmac_get_cpuinfo(char *);	
+	extern int prep_get_cpuinfo(char *);
+	
+	if ( _machine == _MACH_Pmac )
+		return pmac_get_cpuinfo(buffer);
+#ifdef CONFIG_PREP
+	else /* prep */
+		return prep_get_cpuinfo(buffer);
+#endif /* CONFIG_PREP */
+}
+
+__initfunc(void setup_arch(char **cmdline_p,
+	unsigned long * memory_start_p, unsigned long * memory_end_p))
+{
+	extern void pmac_setup_arch(char **, unsigned long *, unsigned long *);
+	extern void prep_setup_arch(char **, unsigned long *, unsigned long *);
+	
+	if ( _machine == _MACH_Pmac )
+		pmac_setup_arch(cmdline_p,memory_start_p,memory_end_p);
+#ifdef CONFIG_PREP
+	else /* prep */
+		prep_setup_arch(cmdline_p,memory_start_p,memory_end_p);
+#endif /* CONFIG_PREP */
+}
+
+
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c
--- v2.1.50/linux/arch/ppc/kernel/signal.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/signal.c	Sat Aug 16 09:51:08 1997
@@ -24,6 +24,7 @@
 #include <linux/wait.h>
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
+#include <linux/elf.h>
 #include <asm/uaccess.h>
 
 #define _S(nr) (1<<((nr)-1))
@@ -36,6 +37,10 @@
 #define PAUSE_AFTER_SIGNAL
 #undef  PAUSE_AFTER_SIGNAL
 
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
 asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
 
 /*
@@ -71,32 +76,52 @@
 	}
 }
 
+/* 
+ * These are the flags in the MSR that the user is allowed to change
+ * by modifying the saved value of the MSR on the stack.  SE and BE
+ * should not be in this list since gdb may want to change these.  I.e,
+ * you should be able to step out of a signal handler to see what
+ * instruction executes next after the signal handler completes.
+ * Alternately, if you stepped into a signal handler, you should be
+ * able to continue 'til the next breakpoint from within the signal
+ * handler, even if the handler returns.
+ */
+#define MSR_USERCHANGE	(MSR_FE0 | MSR_FE1)
+
 /*
  * 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, ret;
+	struct sigcontext_struct *sc, sigctx;
+	int ret;
+	elf_gregset_t saved_regs;  /* an array of ELF_NGREG unsigned longs */
 
-#if 1 	
-	if (verify_area(VERIFY_READ, (void *) regs->gpr[1], sizeof(sc))
-	    || (regs->gpr[1] >= KERNELBASE))
+	sc = (struct sigcontext_struct *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
+	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
 		goto badframe;
-#endif	
-	sc = (struct sigcontext_struct *)(regs->gpr[1]+STACK_FRAME_OVERHEAD);
-	get_user(current->blocked, &sc->oldmask);
-	current->blocked &= _BLOCKABLE;
-	get_user(int_regs, &sc->regs);
-	get_user(signo, &sc->signal);
+	current->blocked = sigctx.oldmask & _BLOCKABLE;
 	sc++;			/* Pop signal 'context' */
 #ifdef DEBUG_SIGNALS
-printk("Sig return - Regs: %x, sc: %x, sig: %d\n", int_regs, sc, signo);
+	printk("Sig return - Regs: %p, sc: %p, sig: %d\n", sigctx.regs, sc,
+	       sigctx.signal);
 #endif
-	if (sc == (struct sigcontext_struct *)(int_regs)) {
-		/* Last stacked signal */
-		memcpy(regs, int_regs, sizeof(*regs));
+	if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
+		/* Last stacked signal - restore registers */
+		if (last_task_used_math == current)
+			giveup_fpu();
+		if (copy_from_user(saved_regs, sigctx.regs, sizeof(saved_regs)))
+			goto badframe;
+		saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
+			| (saved_regs[PT_MSR] & MSR_USERCHANGE);
+		memcpy(regs, saved_regs, 
+		       MIN(sizeof(elf_gregset_t),sizeof(struct pt_regs)));
+
+		if (copy_from_user(current->tss.fpr,
+				   (unsigned long *)sigctx.regs + ELF_NGREG,
+				   ELF_NFPREG * sizeof(double)))
+			goto badframe;
+
 		if (regs->trap == 0x0C00 /* System Call! */ &&
 		    ((int)regs->result == -ERESTARTNOHAND ||
 		     (int)regs->result == -ERESTARTSYS ||
@@ -106,15 +131,17 @@
 			regs->result = 0;
 		}
 		ret = regs->result;
+
 	} else {
 		/* More signals to go */
-		regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
-		get_user(regs->gpr[3], &sc->signal);
-		get_user(int_regs, (struct pt_regs **) &sc->regs);
-		regs->gpr[4] = (unsigned long) int_regs;
-		regs->link = (unsigned long) (int_regs+1);
-		get_user(regs->nip, &sc->handler);
-		ret = regs->gpr[3];
+		regs->gpr[1] = (unsigned long)sc - __SIGNAL_FRAMESIZE;
+		if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
+			goto badframe;
+		regs->gpr[3] = ret = sigctx.signal;
+		regs->gpr[4] = (unsigned long) sigctx.regs;
+		regs->link = regs->gpr[4] + ELF_NGREG * sizeof(unsigned long)
+			+ ELF_NFPREG * sizeof(double);
+		regs->nip = sigctx.handler;
 	}
 	return ret;
 
@@ -142,6 +169,7 @@
 	unsigned long *frame = NULL;
 	unsigned long *trampoline;
 	unsigned long *regs_ptr;
+	double *fpregs_ptr;
 	unsigned long nip = 0;
 	unsigned long signr;
 	struct sigcontext_struct *sc;
@@ -164,7 +192,7 @@
 		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
 			current->exit_code = signr;
 			current->state = TASK_STOPPED;
-			notify_parent(current);
+			notify_parent(current, SIGCHLD);
 			schedule();
 			if (!(signr = current->exit_code))
 				continue;
@@ -204,7 +232,7 @@
 				current->exit_code = signr;
 				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
 						SA_NOCLDSTOP))
-					notify_parent(current);
+					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
 
@@ -257,18 +285,33 @@
 	nip = regs->nip;
 	frame = (unsigned long *) regs->gpr[1];
 
-	/* Build trampoline code on stack */
-	frame -= 2;
+	/*
+	 * Build trampoline code on stack, and save gp and fp regs.
+	 * The 56 word hole is because programs using the rs6000/xcoff
+	 * style calling sequence can save up to 19 gp regs and 18 fp regs
+	 * on the stack before decrementing sp.
+	 */
+	frame -= 2 + 56;
 	trampoline = frame;
-	/* verify stack is valid for writing regs struct */
-	if (verify_area(VERIFY_WRITE,(void *)frame, sizeof(long)*2+sizeof(*regs))
-	    || ((unsigned long) frame >= KERNELBASE ))
-		goto badframe;
-	put_user(0x38007777UL, trampoline);      /* li r0,0x7777 */
-	put_user(0x44000002UL, trampoline+1);    /* sc           */
-	frame -= sizeof(*regs) / sizeof(long);
+	frame -= ELF_NFPREG * sizeof(double) / sizeof(unsigned long);
+	fpregs_ptr = (double *) frame;
+	frame -= ELF_NGREG;
 	regs_ptr = frame;
-	copy_to_user(regs_ptr, regs, sizeof(*regs));
+	/* verify stack is valid for writing to */
+	if (verify_area(VERIFY_WRITE, frame,
+			(ELF_NGREG + 2) * sizeof(long)
+			+ ELF_NFPREG * sizeof(double)))
+		goto badframe;
+	if (last_task_used_math == current)
+		giveup_fpu();
+	if (__copy_to_user(regs_ptr, regs, 
+	                   MIN(sizeof(elf_gregset_t),sizeof(struct pt_regs)))
+	    || __copy_to_user(fpregs_ptr, current->tss.fpr,
+			      ELF_NFPREG * sizeof(double))
+	    || __put_user(0x38007777UL, trampoline)	/* li r0,0x7777 */
+	    || __put_user(0x44000002UL, trampoline+1))	/* sc           */
+		goto badframe;
+
 	signr = 1;
 	sa = current->sig->action;
 
@@ -279,24 +322,29 @@
 			continue;
 
 		frame -= sizeof(struct sigcontext_struct) / sizeof(long);
-		if (verify_area(VERIFY_WRITE,(void *)frame,
-				sizeof(struct sigcontext_struct)/sizeof(long)))
+		if (verify_area(VERIFY_WRITE, frame,
+				sizeof(struct sigcontext_struct)))
 			goto badframe;
 		sc = (struct sigcontext_struct *)frame;
 		nip = (unsigned long) sa->sa_handler;
 		if (sa->sa_flags & SA_ONESHOT)
 			sa->sa_handler = NULL;
-		put_user(nip, &sc->handler);
-		put_user(oldmask, &sc->oldmask); /* was current->blocked */
-		put_user(regs_ptr, &sc->regs);
-		put_user(signr, &sc->signal);
+		if (__put_user(nip, &sc->handler)
+		    || __put_user(oldmask, &sc->oldmask)
+		    || __put_user(regs_ptr, &sc->regs)
+		    || __put_user(signr, &sc->signal))
+			goto badframe;
 		current->blocked |= sa->sa_mask;
 		regs->gpr[3] = signr;
-		regs->gpr[4] = (unsigned long)regs_ptr;
+		regs->gpr[4] = (unsigned long) regs_ptr;
 	}
+
+	frame -= __SIGNAL_FRAMESIZE / sizeof(unsigned long);
+	if (put_user(regs->gpr[1], frame))
+		goto badframe;
 	regs->link = (unsigned long)trampoline;
 	regs->nip = nip;
-	regs->gpr[1] = (unsigned long)sc - STACK_FRAME_OVERHEAD;
+	regs->gpr[1] = (unsigned long) frame;
 
 	/* The DATA cache must be flushed here to insure coherency */
 	/* between the DATA & INSTRUCTION caches.  Since we just */
@@ -305,8 +353,8 @@
 	/* 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 */
-	store_cache_range((unsigned long) trampoline,
-			  (unsigned long) (trampoline + 2));
+	flush_icache_range((unsigned long) trampoline,
+			   (unsigned long) (trampoline + 2));
 	return 1;
 
 badframe:
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/strcase.c linux/arch/ppc/kernel/strcase.c
--- v2.1.50/linux/arch/ppc/kernel/strcase.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/strcase.c	Wed Dec 31 16:00:00 1969
@@ -1,12 +0,0 @@
-#include <linux/ctype.h>
-
-int strcasecmp(const char *s1, const char *s2)
-{
-	int c1, c2;
-
-	do {
-		c1 = tolower(*s1++);
-		c2 = tolower(*s2++);
-	} while (c1 == c2 && c1 != 0);
-	return c1 - c2;
-}
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c
--- v2.1.50/linux/arch/ppc/kernel/syscalls.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/syscalls.c	Sat Aug 16 09:51:08 1997
@@ -1,15 +1,25 @@
 /*
  * linux/arch/ppc/kernel/sys_ppc.c
  *
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Derived from "arch/i386/kernel/sys_i386.c"
  * Adapted from the i386 version by Gary Thomas
  * Modified by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras (paulus@cs.anu.edu.au).
  *
  * This file contains various random system calls that
  * have a non-standard calling sequence on the Linux/PPC
  * platform.
+ *
+ *  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.
+ *
  */
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -20,11 +30,11 @@
 #include <linux/shm.h>
 #include <linux/stat.h>
 #include <linux/mman.h>
+#include <linux/sys.h>
 #include <linux/ipc.h>
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
 
-
 void
 check_bugs(void)
 {
@@ -32,32 +42,32 @@
 
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
 {
-	printk("sys_ioperm()\n");
+	printk(KERN_ERR "sys_ioperm()\n");
 	return -EIO;
 }
 
 int sys_iopl(int a1, int a2, int a3, int a4)
 {
 	lock_kernel();
-	printk( "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
+	printk(KERN_ERR "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
 	unlock_kernel();
-	return (ENOSYS);
+	return (-ENOSYS);
 }
 
 int sys_vm86(int a1, int a2, int a3, int a4)
 {
 	lock_kernel();
-	printk( "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
+	printk(KERN_ERR "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
 	unlock_kernel();
-	return (ENOSYS);
+	return (-ENOSYS);
 }
 
 int sys_modify_ldt(int a1, int a2, int a3, int a4)
 {
 	lock_kernel();
-	printk( "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
+	printk(KERN_ERR "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4);
 	unlock_kernel();
-	return (ENOSYS);
+	return (-ENOSYS);
 }
 
 /*
@@ -65,7 +75,8 @@
  *
  * This is really horribly ugly.
  */
-asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
+asmlinkage int 
+sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth)
 {
 	int version, ret;
 
@@ -73,138 +84,113 @@
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
 
-	if (call <= SEMCTL)
-		switch (call) {
-		case SEMOP:
-			ret = sys_semop (first, (struct sembuf *)ptr, second);
-			goto out;
-		case SEMGET:
-			ret = sys_semget (first, second, third);
-			goto out;
-		case SEMCTL: {
-			union semun fourth;
-			ret = -EINVAL;
-			if (!ptr)
-				goto out;
-			ret = -EFAULT;
-			if (get_user(fourth.__pad, (void **) ptr))
-				goto out;	
-			ret = sys_semctl (first, second, third, fourth);
-			goto out;
-		}
-		default:
-			ret = -EINVAL;
-			goto out;
+	ret = -EINVAL;
+	switch (call) {
+	case SEMOP:
+		ret = sys_semop (first, (struct sembuf *)ptr, second);
+		break;
+	case SEMGET:
+		ret = sys_semget (first, second, third);
+		break;
+	case SEMCTL: {
+		union semun fourth;
+
+		if (!ptr)
+			break;
+		if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long)))
+		    || (ret = get_user(fourth.__pad, (void **)ptr)))
+			break;
+		ret = sys_semctl (first, second, third, fourth);
+		break;
 		}
-	if (call <= MSGCTL) 
-		switch (call) {
-		case MSGSND:
-			ret = sys_msgsnd (first, (struct msgbuf *) ptr, 
-					  second, third);
-			goto out;
-		case MSGRCV:
-			switch (version) {
-			case 0: {
-				struct ipc_kludge tmp;
-				ret = -EINVAL;
-				if (!ptr)
-					goto out;
-				ret = -EFAULT;
-				if (copy_from_user(&tmp,(struct ipc_kludge *) ptr, 
-						   sizeof (tmp)))
-					goto out; 	
-				ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third);
-				goto out;
-			}
-			case 1: default:
-				ret = sys_msgrcv (first, (struct msgbuf *) ptr, second, fifth, third);
-				goto out;
+	case MSGSND:
+		ret = sys_msgsnd (first, (struct msgbuf *) ptr, second, third);
+		break;
+	case MSGRCV:
+		switch (version) {
+		case 0: {
+			struct ipc_kludge tmp;
+
+			if (!ptr)
+				break;
+			if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp)))
+			    || (ret = copy_from_user(&tmp,
+						(struct ipc_kludge *) ptr,
+						sizeof (tmp))))
+				break;
+			ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp,
+					  third);
+			break;
 			}
-		case MSGGET:
-			ret = sys_msgget ((key_t) first, second);
-			goto out;
-		case MSGCTL:
-			ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
-			goto out;
 		default:
-			ret = -EINVAL;
-			goto out;
+			ret = sys_msgrcv (first, (struct msgbuf *) ptr,
+					  second, fifth, third);
+			break;
 		}
-	if (call <= SHMCTL) 
-		switch (call) {
-		case SHMAT:
-			switch (version) {
-			case 0: default: {
-				ulong raddr;
-				ret = sys_shmat (first, (char *) ptr, second, &raddr);
-				if (ret)
-					goto out;
-				ret = put_user (raddr, (ulong *) third);
-				goto out;
+		break;
+	case MSGGET:
+		ret = sys_msgget ((key_t) first, second);
+		break;
+	case MSGCTL:
+		ret = sys_msgctl (first, second, (struct msqid_ds *) ptr);
+		break;
+	case SHMAT:
+		switch (version) {
+		default: {
+			ulong raddr;
+
+			if ((ret = verify_area(VERIFY_WRITE, (ulong*) third,
+					       sizeof(ulong))))
+				break;
+			ret = sys_shmat (first, (char *) ptr, second, &raddr);
+			if (ret)
+				break;
+			ret = put_user (raddr, (ulong *) third);
+			break;
 			}
-			case 1:	/* iBCS2 emulator entry point */
-				ret = -EINVAL;
-				if (get_fs() != get_ds())
-					goto out;
-				ret = sys_shmat (first, (char *) ptr, second, (ulong *) third);
-				goto out;
-			}
-		case SHMDT: 
-			ret = sys_shmdt ((char *)ptr);
-			goto out;
-		case SHMGET:
-			ret = sys_shmget (first, second, third);
-			goto out;
-		case SHMCTL:
-			ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
-			goto out;
-		default:
-			ret = -EINVAL;
-			goto out;
+		case 1:	/* iBCS2 emulator entry point */
+			if (get_fs() != get_ds())
+				break;
+			ret = sys_shmat (first, (char *) ptr, second,
+					 (ulong *) third);
+			break;
 		}
-	else
-		ret = -EINVAL;
-out:
-	unlock_kernel();
-	return ret;
-}
-
+		break;
+	case SHMDT: 
+		ret = sys_shmdt ((char *)ptr);
+		break;
+	case SHMGET:
+		ret = sys_shmget (first, second, third);
+		break;
+	case SHMCTL:
+		ret = sys_shmctl (first, second, (struct shmid_ds *) ptr);
+		break;
+	}
 
-#ifndef CONFIG_MODULES
-void
-scsi_register_module(void)
-{
-	lock_kernel();
-	panic("scsi_register_module");
-	unlock_kernel();
-}
-
-void
-scsi_unregister_module(void)
-{
-	lock_kernel();
-	panic("scsi_unregister_module");
 	unlock_kernel();
+	return ret;
 }
-#endif
 
 /*
  * sys_pipe() is the normal C calling standard for creating
  * a pipe. It's not the way unix traditionally does this, though.
  */
-asmlinkage int sys_pipe(unsigned long * fildes)
+asmlinkage int sys_pipe(int *fildes)
 {
 	int fd[2];
 	int error;
 
-	error = verify_area(VERIFY_WRITE,fildes,8);
+	error = verify_area(VERIFY_WRITE, fildes, 8);
 	if (error)
 		return error;
+	lock_kernel();
 	error = do_pipe(fd);
+	unlock_kernel();
 	if (error)
 		return error;
-	put_user(fd[0],0+fildes);
-	put_user(fd[1],1+fildes);
+	if (__put_user(fd[0],0+fildes)
+	    || __put_user(fd[1],1+fildes))
+		return -EFAULT;	/* should we close the fds? */
 	return 0;
 }
 
@@ -213,13 +199,18 @@
 				  unsigned long fd, off_t offset)
 {
 	struct file * file = NULL;
+	int ret = -EBADF;
+
+	lock_kernel();
 	if (!(flags & MAP_ANONYMOUS)) {
 		if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-			return -EBADF;
+			goto out;
 	}
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
-	return do_mmap(file, addr, len, prot, flags, offset);
+	ret = do_mmap(file, addr, len, prot, flags, offset);
+out:
+	unlock_kernel();
+	return ret;
 }
 
 extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
@@ -233,15 +224,15 @@
 asmlinkage int 
 ppc_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp)
 {
-	int err;
 	if ( (unsigned long)n >= 4096 )
 	{
 		unsigned long *buffer = (unsigned long *)n;
-		if ( get_user(n, buffer) ||
-		     get_user(inp,buffer+1) ||
-		     get_user(outp,buffer+2) ||
-		     get_user(exp,buffer+3) ||
-		     get_user(tvp,buffer+4) )
+		if (verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long))
+		    || __get_user(n, buffer)
+		    || __get_user(inp, ((fd_set **)(buffer+1)))
+		    || __get_user(outp, ((fd_set **)(buffer+2)))
+		    || __get_user(exp, ((fd_set **)(buffer+3)))
+		    || __get_user(tvp, ((struct timeval **)(buffer+4))))
 			return -EFAULT;
 	}
 	return sys_select(n, inp, outp, exp, tvp);
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- v2.1.50/linux/arch/ppc/kernel/time.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/time.c	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,221 @@
+/*
+ * $Id: time.c,v 1.8 1997/08/11 08:37:51 cort Exp $
+ * Common time routines among all ppc machines.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu) to merge
+ * Paul Mackerras' version and mine for PReP and Pmac.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/kernel_stat.h>
+#include <linux/mc146818rtc.h>
+#include <linux/time.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/nvram.h>
+
+#include "time.h"
+
+/* this is set to the appropriate pmac/prep func in init_IRQ() */
+int (*set_rtc_time)(unsigned long);
+
+/* keep track of when we need to update the rtc */
+unsigned long last_rtc_update = 0;
+
+/* The decrementer counts down by 128 every 128ns on a 601. */
+#define DECREMENTER_COUNT_601	(1000000000 / HZ)
+#define COUNT_PERIOD_NUM_601	1
+#define COUNT_PERIOD_DEN_601	1000
+
+unsigned decrementer_count;	/* count value for 1e6/HZ microseconds */
+unsigned count_period_num;	/* 1 decrementer count equals */
+unsigned count_period_den;	/* count_period_num / count_period_den us */
+
+/* Accessor functions for the decrementer register. */
+inline unsigned long
+get_dec(void)
+{
+	int ret;
+
+	asm volatile("mfspr %0,22" : "=r" (ret) :);
+	return ret;
+}
+
+inline void
+set_dec(int val)
+{
+	asm volatile("mtspr 22,%0" : : "r" (val));
+}
+
+/*
+ * timer_interrupt - gets called when the decrementer overflows,
+ * with interrupts disabled.
+ * We set it up to overflow again in 1/HZ seconds.
+ */
+void timer_interrupt(struct pt_regs * regs)
+{
+	int dval, d;
+	while ((dval = get_dec()) < 0) {
+		/*
+		 * Wait for the decrementer to change, then jump
+		 * in and add decrementer_count to its value
+		 * (quickly, before it changes again!)
+		 */
+		while ((d = get_dec()) == dval)
+			;
+		set_dec(d + decrementer_count);
+		do_timer(regs);
+		/*
+		 * update the rtc when needed
+		 */
+		if ( xtime.tv_sec > last_rtc_update + 660 )
+			if (set_rtc_time(xtime.tv_sec) == 0)
+				last_rtc_update = xtime.tv_sec;
+			else
+				last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+	}
+}
+
+/*
+ * This version of gettimeofday has microsecond resolution.
+ */
+void do_gettimeofday(struct timeval *tv)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	*tv = xtime;
+	tv->tv_usec += (decrementer_count - get_dec())
+	    * count_period_num / count_period_den;
+	if (tv->tv_usec >= 1000000) {
+		tv->tv_usec -= 1000000;
+		tv->tv_sec++;
+	}
+	restore_flags(flags);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+	unsigned long flags;
+	int frac_tick;
+	
+	last_rtc_update = 0; /* so the rtc gets updated soon */
+	
+	frac_tick = tv->tv_usec % (1000000 / HZ);
+	save_flags(flags);
+	cli();
+	xtime.tv_sec = tv->tv_sec;
+	xtime.tv_usec = tv->tv_usec - frac_tick;
+	set_dec(frac_tick * count_period_den / count_period_num);
+	restore_flags(flags);
+}
+
+
+void
+time_init(void)
+{
+#ifdef CONFIG_PREP
+	/* pmac hasn't yet called via_cuda_init() */
+	if ( _machine != _MACH_Pmac ) /* prep */
+	{
+		xtime.tv_sec = prep_get_rtc_time();
+		xtime.tv_usec = 0;
+		/*
+		 * mark the rtc/on-chip timer as in sync
+		 * so we don't update right away
+		 */
+		last_rtc_update = xtime.tv_sec;
+	}
+#endif /* CONFIG_PREP */
+	if ((_get_PVR() >> 16) == 1) {
+		/* 601 processor: dec counts down by 128 every 128ns */
+		decrementer_count = DECREMENTER_COUNT_601;
+		count_period_num = COUNT_PERIOD_NUM_601;
+		count_period_den = COUNT_PERIOD_DEN_601;
+	} else {
+		/*
+		 * These should setup decrementer_count 
+		 */
+		if ( _machine == _MACH_Pmac )
+			pmac_calibrate_decr();
+#ifdef CONFIG_PREP
+		else /* PReP */
+			prep_calibrate_decr();
+#endif /* CONFIG_PREP */
+	}
+
+	if ( _machine == _MACH_Pmac )
+		set_rtc_time = pmac_set_rtc_time;
+#ifdef CONFIG_PREP
+	else /* prep */
+		set_rtc_time = prep_set_rtc_time;
+#endif /* CONFIG_PREP */
+		
+	set_dec(decrementer_count);
+}
+
+#ifdef CONFIG_PREP
+/*
+ * Uses the on-board timer to calibrate the on-chip decrementer register
+ * for prep systems.  On the pmac the OF tells us what the frequency is
+ * but on prep we have to figure it out.
+ * -- Cort
+ */
+int calibrate_done = 0;
+volatile int *done_ptr = &calibrate_done;
+void prep_calibrate_decr(void)
+{
+	unsigned long flags;
+	
+	save_flags(flags);
+	
+#define TIMER0_COUNT 0x40
+#define TIMER_CONTROL 0x43
+	/* set timer to periodic mode */
+	outb_p(0x34,TIMER_CONTROL);/* binary, mode 2, LSB/MSB, ch 0 */
+	/* set the clock to ~100 Hz */
+	outb_p(LATCH & 0xff , TIMER0_COUNT);	/* LSB */
+	outb(LATCH >> 8 , TIMER0_COUNT);	/* MSB */
+	
+	if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0)
+		panic("Could not allocate timer IRQ!");
+	__sti();
+	while ( ! *done_ptr ) /* nothing */; /* wait for calibrate */
+        restore_flags(flags);
+	free_irq( 0, NULL);
+}
+
+void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs * regs)
+{
+	int freq, divisor;
+	static unsigned long t1 = 0, t2 = 0;
+
+	if ( !t1 )
+		t1 = get_dec();
+	else if (!t2)
+	{
+		t2 = get_dec();
+		t2 = t1-t2;  /* decr's in 1/HZ */
+		t2 = t2*HZ;  /* # decrs in 1s - thus in Hz */
+		freq = t2 * 60;	/* try to make freq/1e6 an integer */
+		divisor = 60;
+		printk("time_init: decrementer frequency = %d/%d (%luMHz)\n",
+		       freq, divisor,t2>>20);
+		decrementer_count = freq / HZ / divisor;
+		count_period_num = divisor;
+		count_period_den = freq / 1000000;
+		*done_ptr = 1;
+	}
+}
+#endif /* CONFIG_PREP */
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/time.h linux/arch/ppc/kernel/time.h
--- v2.1.50/linux/arch/ppc/kernel/time.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/time.h	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,25 @@
+/*
+ * $Id: time.h,v 1.3 1997/08/12 08:22:14 cort Exp $
+ * Common time prototypes and such for all ppc machines.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu) to merge
+ * Paul Mackerras' version and mine for PReP and Pmac.
+ */
+
+/* time.c */
+__inline__ unsigned long get_dec(void);
+__inline__ void set_dec(int val);
+void prep_calibrate_decr_handler(int, void *,struct pt_regs *);
+void prep_calibrate_decr(void);
+void pmac_calibrate_decr(void);
+extern unsigned decrementer_count;
+extern unsigned count_period_num;
+extern unsigned count_period_den;
+
+/* pmac/prep_time.c */
+unsigned long prep_get_rtc_time(void);
+unsigned long pmac_get_rtc_time(void);
+int prep_set_rtc_time(unsigned long nowtime);
+int pmac_set_rtc_time(unsigned long nowtime);
+void pmac_read_rtc_time(void);
+
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c
--- v2.1.50/linux/arch/ppc/kernel/traps.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/kernel/traps.c	Sat Aug 16 09:51:08 1997
@@ -1,9 +1,15 @@
 /*
  *  linux/arch/ppc/kernel/traps.c
  *
- *  Copyright (C) 1995  Gary Thomas
- *  Adapted for PowerPC by Gary Thomas
+ *  Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
  *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  and Paul Mackerras (paulus@cs.anu.edu.au)
  */
 
 /*
@@ -24,9 +30,21 @@
 #include <linux/config.h>
 
 #include <asm/pgtable.h>
-#include <asm/segment.h>
+#include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/processor.h>
+
+extern int fix_alignment(struct pt_regs *);
+extern void bad_page_fault(struct pt_regs *, unsigned long);
+
+#ifdef CONFIG_XMON
+extern int xmon_bpt(struct pt_regs *regs);
+extern int xmon_sstep(struct pt_regs *regs);
+extern void xmon(struct pt_regs *regs);
+extern int xmon_iabr_match(struct pt_regs *regs);
+extern void (*xmon_fault_handler)(struct pt_regs *regs);
+#endif
 
 /*
  * Trap & Exception support
@@ -43,40 +61,53 @@
 	if (!user_mode(regs))
 	{
 		show_regs(regs);
-		print_backtrace(regs->gpr[1]);
-		panic("Exception in kernel pc %x signal %d",regs->nip,signr);
+		print_backtrace((unsigned long *)regs->gpr[1]);
+#ifdef CONFIG_XMON
+		xmon(regs);
+#endif
+		panic("Exception in kernel pc %lx signal %d",regs->nip,signr);
 	}
 	force_sig(signr, current);
 }
 
+void
 MachineCheckException(struct pt_regs *regs)
 {
 	if ( !user_mode(regs) )
 	{
+#ifdef CONFIG_XMON
+		if (xmon_fault_handler) {
+			xmon_fault_handler(regs);
+			return;
+		}
+#endif
 		printk("Machine check in kernel mode.\n");
 		printk("Caused by (from msr): ");
-		printk("regs %08x ",regs);
+		printk("regs %p ",regs);
 		switch( regs->msr & 0x0000F000)
 		{
 		case (1<<12) :
 			printk("Machine check signal - probably due to mm fault\n"
 				"with mmu off\n");
-		break;
+			break;
 		case (1<<13) :
 			printk("Transfer error ack signal\n");
-		break;
+			break;
 		case (1<<14) :
 			printk("Data parity signal\n");
-		break;
+			break;
 		case (1<<15) :
 			printk("Address parity signal\n");
-		break;
+			break;
 		default:
 			printk("Unknown values in msr\n");
 		}
 		show_regs(regs);
-		print_backtrace(regs->gpr[1]);
-		panic("");
+		print_backtrace((unsigned long *)regs->gpr[1]);
+#ifdef CONFIG_XMON
+		xmon(regs);
+#endif
+		panic("machine check");
 	}
 	_exception(SIGSEGV, regs);	
 }
@@ -105,33 +136,71 @@
 	_exception(SIGTRAP, regs);	
 }
 
+void
 ProgramCheckException(struct pt_regs *regs)
 {
-	if (current->flags & PF_PTRACED)
+	if (regs->msr & 0x100000) {
+		/* IEEE FP exception */
+		_exception(SIGFPE, regs);
+	} else if (regs->msr & 0x20000) {
+		/* trap exception */
+#ifdef CONFIG_XMON
+		if (xmon_bpt(regs))
+			return;
+#endif
 		_exception(SIGTRAP, regs);
-	else
+	} else {
 		_exception(SIGILL, regs);
+	}
 }
 
+void
 SingleStepException(struct pt_regs *regs)
 {
 	regs->msr &= ~MSR_SE;  /* Turn off 'trace' bit */
+#ifdef CONFIG_XMON
+	if (xmon_sstep(regs))
+		return;
+#endif
 	_exception(SIGTRAP, regs);	
 }
 
+void
 AlignmentException(struct pt_regs *regs)
 {
+	int fixed;
+
+	if (last_task_used_math == current)
+		giveup_fpu();
+	fixed = fix_alignment(regs);
+	if (fixed == 1) {
+		regs->nip += 4;	/* skip over emulated instruction */
+		return;
+	}
+	if (fixed == -EFAULT) {
+		/* fixed == -EFAULT means the operand address was bad */
+		bad_page_fault(regs, regs->dar);
+		return;
+	}
 	_exception(SIGBUS, regs);	
 }
 
+void
+PromException(struct pt_regs *regs, int trap)
+{
+	regs->trap = trap;
+#ifdef CONFIG_XMON
+	xmon(regs);
+#endif
+	printk("Exception %lx in prom at PC: %lx, SR: %lx\n",
+	       regs->trap, regs->nip, regs->msr);
+	/* probably should turn up the toes here */
+}
+
+void
 trace_syscall(struct pt_regs *regs)
 {
-	static int count;
-	printk("Task: %08X(%d), PC: %08X/%08X, Syscall: %3d, Result: %s%d\n",
+	printk("Task: %p(%d), PC: %08lX/%08lX, Syscall: %3ld, Result: %s%ld\n",
 	       current, current->pid, regs->nip, regs->link, regs->gpr[0],
 	       regs->ccr&0x10000000?"Error=":"", regs->gpr[3]);
-	if (++count == 20)
-	{
-		count = 0;
-	}
 }
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/ld.script linux/arch/ppc/ld.script
--- v2.1.50/linux/arch/ppc/ld.script	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/ld.script	Wed Dec 31 16:00:00 1969
@@ -1,81 +0,0 @@
-OUTPUT_ARCH(powerpc)
-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)
-    *(.fixup)
-    *(.got1)
-  }
-  _etext = .;
-  PROVIDE (etext = .);
-  .rodata    :
-  {
-    *(.rodata)
-    *(.rodata1)
-  }
-  .fini      : { *(.fini)    } =0
-  .ctors     : { *(.ctors)   }
-  .dtors     : { *(.dtors)   }
-  /* Read-write section, merged into data segment: */
-  . = (. + 0x0FFF) & 0xFFFFF000;
-  .data    :
-  {
-    *(.data)
-    *(.data1)
-    *(.sdata)
-    *(.sdata2)
-    *(.got.plt) *(.got)
-    *(.dynamic)
-    CONSTRUCTORS
-  }
-  _edata  =  .;
-/*
-  . = ALIGN(4096);
-  __init_begin = .;
-  .text.init : { *(.text.init) }
-  .data.init : { *(.data.init) }
-  . = ALIGN(4096);
-  __init_end = .;
-*/
-  __bss_start = .;		/* BSS */
-  PROVIDE (edata = .);
-  __bss_start = .;
-  .bss       :
-  {
-   *(.sbss) *(.scommon)
-   *(.dynbss)
-   *(.bss)
-   *(COMMON)
-  }
-  _end = . ;
-  PROVIDE (end = .);
-}
-
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/lib/Makefile linux/arch/ppc/lib/Makefile
--- v2.1.50/linux/arch/ppc/lib/Makefile	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/lib/Makefile	Sat Aug 16 09:51:08 1997
@@ -1,38 +1,11 @@
-.c.s:
-	$(CC) $(CFLAGS) -S $<
-.s.o:
-	$(AS) $(ASFLAGS) -o $*.o $<
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.S.s:
-	$(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
-.S.o:
-	$(CPP) $(CFLAGS) -D__ASSEMBLY__ $< -o $*.s
-	$(AS) $(ASFLAGS) -o $*.o $*.s
-	rm $*.s
-
-HOST_CC = gcc
-
-L_TARGET = lib.o
-L_OBJS  = checksum.o cksum_support.o string.o
-
-${L_TARGET}: $(L_OBJS)
-	$(LD) -r -o ${L_TARGET} $(L_OBJS)
-
-
-fastdep:
-	$(TOPDIR)/scripts/mkdep *.[Sch] > .depend
-
-dep:
-	$(CPP) -M *.S *.c > .depend
+#
+# Makefile for ppc-specific library files..
+#
 
-modules: 
+.S.o:
+	$(CC) -D__ASSEMBLY__ -c $< -o $*.o
 
-dummy:
+O_TARGET = lib.o
+O_OBJS  = checksum.o string.o strcase.o
 
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/lib/checksum.S linux/arch/ppc/lib/checksum.S
--- v2.1.50/linux/arch/ppc/lib/checksum.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/lib/checksum.S	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,192 @@
+/*
+ * This file contains assembly-language implementations
+ * of IP-style 1's complement checksum routines.
+ *	
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ * Severely hacked about by Paul Mackerras (paulus@cs.anu.edu.au).
+ */
+
+#include <linux/sys.h>
+#include <asm/errno.h>
+#include "../kernel/ppc_asm.tmpl"
+
+_TEXT()
+
+/*
+ * ip_fast_csum(buf, len) -- Optimized for IP header
+ * len is in words and is always >= 5.
+ */
+_GLOBAL(ip_fast_csum)
+	lwz	r0,0(r3)
+	lwzu	r5,4(r3)
+	addi	r4,r4,-2
+	addc	r0,r0,r5
+	mtctr	r4
+1:	lwzu	r4,4(r3)
+	adde	r0,r0,r4
+	bdnz	1b
+	addze	r0,r0		/* add in final carry */
+	rlwinm	r3,r0,16,0,31	/* fold two halves together */
+	add	r3,r0,r3
+	not	r3,r3
+	srwi	r3,r3,16
+	blr
+
+/*
+ * Compute checksum of TCP or UDP pseudo-header:
+ *   csum_tcpudp_magic(saddr, daddr, len, proto, sum)
+ */	
+_GLOBAL(csum_tcpudp_magic)
+	rlwimi	r5,r6,16,0,15	/* put proto in upper half of len */
+	addc	r0,r3,r4	/* add 4 32-bit words together */
+	adde	r0,r0,r5
+	adde	r0,r0,r7
+	addze	r0,r0		/* add in final carry */
+	rlwinm	r3,r0,16,0,31	/* fold two halves together */
+	add	r3,r0,r3
+	not	r3,r3
+	srwi	r3,r3,16
+	blr
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * csum_partial(buff, len, sum)
+ */
+_GLOBAL(csum_partial)
+	addic	r0,r5,0
+	subi	r3,r3,4
+	srwi.	r6,r4,2
+	beq	3f		/* if we're doing < 4 bytes */
+	andi.	r5,r3,2		/* Align buffer to longword boundary */
+	beq+	1f
+	lhz	r5,4(r3)	/* do 2 bytes to get aligned */
+	addi	r3,r3,2
+	subi	r4,r4,2
+	addc	r0,r0,r5
+	srwi.	r6,r4,2		/* # words to do */
+	beq	3f
+1:	mtctr	r6
+2:	lwzu	r5,4(r3)	/* the bdnz has zero overhead, so it should */
+	adde	r0,r0,r5	/* be unnecessary to unroll this loop */
+	bdnz	2b
+	andi.	r4,r4,3
+3:	cmpi	0,r4,2
+	blt+	4f
+	lhz	r5,4(r3)
+	addi	r3,r3,2
+	subi	r4,r4,2
+	adde	r0,r0,r5
+4:	cmpi	0,r4,1
+	bne+	5f
+	lbz	r5,4(r3)
+	slwi	r5,r5,8		/* Upper byte of word */
+	adde	r0,r0,r5
+5:	addze	r3,r0		/* add in final carry */
+	blr
+
+/*
+ * Computes the checksum of a memory block at src, length len,
+ * and adds in "sum" (32-bit), while copying the block to dst.
+ * If an access exception occurs on src or dst, it stores -EFAULT
+ * to *src_err or *dst_err respectively, and (for an error on
+ * src) zeroes the rest of dst.
+ *
+ * csum_partial_copy_generic(src, dst, len, sum, src_err, dst_err)
+ */
+_GLOBAL(csum_partial_copy_generic)
+	addic	r0,r6,0
+	subi	r3,r3,4
+	subi	r4,r4,4
+	srwi.	r6,r5,2
+	beq	3f		/* if we're doing < 4 bytes */
+	andi.	r9,r4,2		/* Align dst to longword boundary */
+	beq+	1f
+81:	lhz	r6,4(r3)	/* do 2 bytes to get aligned */
+	addi	r3,r3,2
+	subi	r5,r5,2
+91:	sth	r6,4(r4)
+	addi	r4,r4,2
+	addc	r0,r0,r6
+	srwi.	r6,r5,2		/* # words to do */
+	beq	3f
+1:	mtctr	r6
+82:	lwzu	r6,4(r3)	/* the bdnz has zero overhead, so it should */
+92:	stwu	r6,4(r4)	/* be unnecessary to unroll this loop */
+	adde	r0,r0,r6
+	bdnz	82b
+	andi.	r5,r5,3
+3:	cmpi	0,r5,2
+	blt+	4f
+83:	lhz	r6,4(r3)
+	addi	r3,r3,2
+	subi	r5,r5,2
+93:	sth	r6,4(r4)
+	addi	r4,r4,2
+	adde	r0,r0,r6
+4:	cmpi	0,r5,1
+	bne+	5f
+84:	lbz	r6,4(r3)
+94:	stb	r6,4(r4)
+	slwi	r6,r6,8		/* Upper byte of word */
+	adde	r0,r0,r6
+5:	addze	r3,r0		/* add in final carry */
+	blr
+
+.section .fixup,"ax"
+
+src_error_1:
+	li	r6,0
+	subi	r5,r5,2
+95:	sth	r6,4(r4)
+	addi	r4,r4,2
+	srwi.	r6,r5,2
+	beq	3f
+	mtctr	r6
+src_error_2:
+	li	r6,0
+96:	stwu	r6,4(r4)
+	bdnz	96b
+3:	andi.	r5,r5,3
+	beq	src_error
+src_error_3:
+	li	r6,0
+	mtctr	r5
+	addi	r4,r4,3
+97:	stbu	r6,1(r4)
+	bdnz	97b
+src_error:
+	cmpi	0,r7,0
+	beq	1f
+	li	r6,-EFAULT
+	stw	r6,0(r7)
+1:	addze	r3,r0
+	blr
+
+dst_error:
+	cmpi	0,r8,0
+	beq	1f
+	li	r6,-EFAULT
+	stw	r6,0(r8)
+1:	addze	r3,r0
+	blr
+
+.section __ex_table,"a"
+	.long	81b,src_error_1
+	.long	91b,dst_error
+	.long	82b,src_error_2
+	.long	92b,dst_error
+	.long	83b,src_error_3
+	.long	93b,dst_error
+	.long	84b,src_error_3
+	.long	94b,dst_error
+	.long	95b,dst_error
+	.long	96b,dst_error
+	.long	97b,dst_error
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/lib/checksum.c linux/arch/ppc/lib/checksum.c
--- v2.1.50/linux/arch/ppc/lib/checksum.c	Wed Dec 18 00:49:52 1996
+++ linux/arch/ppc/lib/checksum.c	Wed Dec 31 16:00:00 1969
@@ -1,136 +0,0 @@
-/*
- * INET		An implementation of the TCP/IP protocol suite for the LINUX
- *		operating system.  INET is implemented using the  BSD Socket
- *		interface as the means of communication with the user level.
- *
- *		IP/TCP/UDP checksumming routines
- *
- * Authors:	Jorge Cwik, <jorge@laser.satlink.net>
- *		Arnt Gulbrandsen, <agulbra@nvg.unit.no>
- *		Tom May, <ftom@netcom.com>
- *		Lots of code moved from tcp.c and ip.c; see those files
- *		for more names.
- *
- * Adapted for PowerPC by Gary Thomas <gdt@mc.com>
- *
- *		This program is free software; you can redistribute it and/or
- *		modify it under the terms of the GNU General Public License
- *		as published by the Free Software Foundation; either version
- *		2 of the License, or (at your option) any later version.
- */
-
-#include <net/checksum.h>
-
-/*
- * computes the checksum of a memory block at buff, length len,
- * and adds in "sum" (32-bit)
- *
- * returns a 32-bit number suitable for feeding into itself
- * or csum_tcpudp_magic
- *
- * this function must be called with even lengths, except
- * for the last fragment, which may be odd
- *
- * it's best to have buff aligned on a 32-bit boundary
- */
-unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
-{
-	unsigned long result = ~_csum_partial(buff, len, sum);
-#if 0	
-printk("Csum partial(%x, %d, %x) = %x\n", buff, len, sum, result);
-dump_buf(buff, len);
-#endif
-	return result;
-}
-
-/*
- * the same as csum_partial, but copies from src while it
- * checksums
- *
- * here even more important to align src and dst on a 32-bit boundary
- */
-
-unsigned int csum_partial_copy(const char *src, char *dst, int len, int sum)
-{
-	/*
-	 * The whole idea is to do the copy and the checksum at
-	 * the same time, but we do it the easy way now.
-	 *
-	 * At least csum on the source, not destination, for cache
-	 * reasons..
-	 */
-	sum = csum_partial(src, len, sum);
-	memcpy(dst, src, len);
-	return sum;
-}
-
-extern unsigned short _ip_fast_csum(unsigned char *buf);
-
-unsigned short
-ip_fast_csum(unsigned char *buf, unsigned int len)
-{
-	unsigned short _val;
-	_val = _ip_fast_csum(buf);
-#if 0
-	printk("IP CKSUM(%x, %d) = %x\n", buf, len, _val);
-	dump_buf(buf, len*4);
-#endif	
-	return (_val);
-}
-
-extern unsigned short _ip_compute_csum(unsigned char *buf, int len);
-
-unsigned short
-ip_compute_csum(unsigned char *buf, int len)
-{
-	unsigned short _val;
-	_val = _ip_compute_csum(buf, len);
-#if 0
-	printk("Compute IP CKSUM(%x, %d) = %x\n", buf, len, _val);
-	dump_buf(buf, len);
-#endif	
-	return (_val);
-}
-
-unsigned short
-_udp_check(unsigned char *buf, int len, int saddr, int daddr, int hdr);
-
-unsigned short
-udp_check(unsigned char *buf, int len, int saddr, int daddr)
-{
-	unsigned short _val;
-	int hdr;
-	hdr = (len << 16) + IPPROTO_UDP;
-	_val = _udp_check(buf, len, saddr, daddr, hdr);
-#if 0
-	printk("UDP CSUM(%x,%d,%x,%x) = %x\n", buf, len, saddr, daddr, _val);
-	dump_buf(buf, len);
-#endif	
-	return (_val);
-}
-
-unsigned short
-_tcp_check(unsigned char *buf, int len, int saddr, int daddr, int hdr);
-
-unsigned short
-csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len, unsigned short proto, unsigned int sum)
-{
-	unsigned short _val;
-	_val = _csum_tcpudp_magic(saddr, daddr, sum, (len<<16)+proto);
-#if 0
-	printk("TCP Magic(%x, %x, %x, %x) = %x\n", saddr, daddr, (len<<16)+proto, sum, _val);
-#endif
-	return (_val);
-}
-
-/*
- *	Fold a partial checksum without adding pseudo headers
- */
-
-unsigned int csum_fold(unsigned int sum)
-{
-	sum = (sum & 0xffff) + (sum >> 16);
-	sum = (sum & 0xffff) + (sum >> 16);
-	return ~sum;
-}
-
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/lib/cksum_support.S linux/arch/ppc/lib/cksum_support.S
--- v2.1.50/linux/arch/ppc/lib/cksum_support.S	Mon May 27 02:00:58 1996
+++ linux/arch/ppc/lib/cksum_support.S	Wed Dec 31 16:00:00 1969
@@ -1,125 +0,0 @@
-/*
- * This module contains the PowerPC interrupt fielders
- * set of code at specific locations, based on function
- */
-
-#include <linux/sys.h>
-#include "../kernel/ppc_asm.tmpl"
-
-_TEXT()
-
-/*
- * Compute IP checksums
- *   _ip_fast_csum(buf, len) -- Optimized for IP header
- *   _ip_compute_csum(buf, len)
- */
-
-_GLOBAL(_ip_fast_csum)
-	li	r0,0
-	addic	r0,r0,0		/* Clear initial carry */
-	lwz	r4,0(r3)
-	lwz	r5,4(r3)
-	adde	r0,r0,r4
-	lwz	r4,8(r3)
-	adde	r0,r0,r5
-	lwz	r5,12(r3)
-	adde	r0,r0,r4
-	lwz	r4,16(r3)
-	adde	r0,r0,r5
-	adde	r0,r0,r4
-	mr	r3,r0
-	andi.	r3,r3,0xFFFF
-	srwi	r0,r0,16
-	adde	r3,r3,r0
-	andis.	r0,r3,1
-	beq	10f
-	addi	r3,r3,1
-10:	not	r3,r3
-	andi.	r3,r3,0xFFFF
-	blr
-
-_GLOBAL(_ip_compute_csum)
-	li	r0,0
-	addic	r0,r0,0
-finish_ip_csum:	
-	subi	r3,r3,4
-	andi.	r5,r3,2		/* Align buffer to longword boundary */
-	beq	10f
-	lhz	r5,4(r3)
-	adde	r0,r0,r5
-	addi	r3,r3,2
-	subi	r4,r4,2
-10:	cmpi	0,r4,16		/* unrolled loop - 16 bytes at a time */
-	blt	20f
-	lwz	r5,4(r3)
-	lwz	r6,8(r3)
-	adde	r0,r0,r5
-	lwz	r5,12(r3)
-	adde	r0,r0,r6
-	lwzu	r6,16(r3)
-	adde	r0,r0,r5
-	adde	r0,r0,r6
-	subi	r4,r4,16
-	b	10b
-20:	cmpi	0,r4,4
-	blt	30f
-	lwzu	r5,4(r3)
-	adde	r0,r0,r5
-	subi	r4,r4,4
-	b	20b
-30:	cmpi	0,r4,2
-	blt	40f
-	lhz	r5,4(r3)
-	addi	r3,r3,2
-	adde	r0,r0,r5
-	subi	r4,r4,2
-40:	cmpi	0,r4,1
-	bne	50f
-	lbz	r5,4(r3)
-	slwi	r5,r5,8		/* Upper byte of word */
-	adde	r0,r0,r5
-50:	mr	r3,r0
-	andi.	r3,r3,0xFFFF
-	srwi	r0,r0,16
-	adde	r3,r3,r0
-	andis.	r0,r3,1
-	beq	60f
-	addi	r3,r3,1
-60:	not	r3,r3
-	andi.	r3,r3,0xFFFF
-	blr
-
-_GLOBAL(_udp_check)
-	addc	r0,r5,r6	/* Add in header fields */
-	adde	r0,r0,r7
-	b	finish_ip_csum	
-
-_GLOBAL(_tcp_check)
-	addc	r0,r5,r6	/* Add in header fields */
-	adde	r0,r0,r7
-	b	finish_ip_csum	
-
-_GLOBAL(_csum_partial)
-	li	r0,0
-	addc	r0,r5,r0
-	b	finish_ip_csum	
-
-/*
- * Compute 16 bit sum:
- *   _csum_tcpudp_magic(int saddr, int daddr, int sum, int proto)
- */	
-_GLOBAL(_csum_tcpudp_magic)
-	addc	r0,r3,r4
-	adde	r0,r0,r5
-	adde	r0,r0,r6
-	mr	r3,r0
-	andi.	r3,r3,0xFFFF
-	srwi	r0,r0,16
-	adde	r3,r3,r0
-	andis.	r0,r3,1			/* Carry out of 16 bits? */
-	beq	10f
-	addi	r3,r3,1
-10:	not	r3,r3
-	andi.	r3,r3,0xFFFF
-	blr
-
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/lib/strcase.c linux/arch/ppc/lib/strcase.c
--- v2.1.50/linux/arch/ppc/lib/strcase.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/lib/strcase.c	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,12 @@
+#include <linux/ctype.h>
+
+int strcasecmp(const char *s1, const char *s2)
+{
+	int c1, c2;
+
+	do {
+		c1 = tolower(*s1++);
+		c2 = tolower(*s2++);
+	} while (c1 == c2 && c1 != 0);
+	return c1 - c2;
+}
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/lib/string.S linux/arch/ppc/lib/string.S
--- v2.1.50/linux/arch/ppc/lib/string.S	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/lib/string.S	Sat Aug 16 09:51:08 1997
@@ -94,6 +94,7 @@
 8:	stbu	r4,1(r6)
 	bdnz	8b
 	blr
+
 	.globl	bcopy
 bcopy:
 	mr	r6,r3
@@ -189,7 +190,7 @@
 	.globl	memcmp
 memcmp:
 	cmpwi	0,r5,0
-	blelr
+	ble-	2f
 	mtctr	r5
 	addi	r6,r3,-1
 	addi	r4,r4,-1
@@ -198,6 +199,22 @@
 	subf.	r3,r0,r3
 	bdnzt	2,1b
 	blr
+2:	li	r3,0
+	blr
+
+	.global	memchr
+memchr:
+	cmpwi	0,r5,0
+	ble-	2f
+	mtctr	r5
+	addi	r3,r3,-1
+1:	lbzu	r0,1(r3)
+	cmpw	0,r0,r4
+	bdnzf	2,1b
+	beqlr
+2:	li	r3,0
+	blr
+
 	.globl	__copy_tofrom_user
 __copy_tofrom_user:
 	rlwinm.	r7,r5,32-3,3,31		/* r0 = r5 >> 3 */
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/mkdist linux/arch/ppc/mkdist
--- v2.1.50/linux/arch/ppc/mkdist	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/mkdist	Sat Aug 16 09:51:08 1997
@@ -1,9 +1,13 @@
 #!/bin/bash
 
-N=`basename $PWD`
-V=`echo $N | sed 's/linux-//'`
+V=`egrep ^VERSION Makefile | awk '{print $3}'`
+P=`egrep ^PATCHLEVEL Makefile | awk '{print $3}'`
+S=`egrep ^SUBLEVEL Makefile | awk '{print $3}'`
 date=`date +'%y%m%d'`
-mkdir -p ../dist
-mv zImage ../dist/zImage-$V-$date
-mv System.map ../dist/System.map-$V-$date
+
+echo zImage-$V.$P.$S-$date
+echo System.map-$V.$P.$S-$date
+
+rcp zImage charon:ppc/dist/kernel-images/zImage-$V.$P.$S-$date
+rcp System.map charon:ppc/dist/kernel-images/System.map-$V.$P.$S-$date
 
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/mktar linux/arch/ppc/mktar
--- v2.1.50/linux/arch/ppc/mktar	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/mktar	Sat Aug 16 09:51:08 1997
@@ -1,7 +1,9 @@
 #!/bin/bash
 
-N=`basename $PWD`
+V=`egrep ^VERSION Makefile | awk '{print $3}'`
+P=`egrep ^PATCHLEVEL Makefile | awk '{print $3}'`
+S=`egrep ^SUBLEVEL Makefile | awk '{print $3}'`
 date=`date +'%y%m%d'`
 cd ../
 mkdir -p dist
-tar -zcf dist/ppc$N-$date.tar.gz -X $N/arch/ppc/ignore $N
+tar -vzcf ppclinux-$V.$P.$S-$date.tar.gz -X linux/arch/ppc/ignore linux
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/mm/Makefile linux/arch/ppc/mm/Makefile
--- v2.1.50/linux/arch/ppc/mm/Makefile	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/mm/Makefile	Sat Aug 16 09:51:08 1997
@@ -7,28 +7,7 @@
 #
 # Note 2! The CFLAGS definition is now in the main makefile...
 
-.c.o:
-	$(CC) $(CFLAGS) -c $<
-.s.o:
-	$(AS) -o $*.o $<
-.c.s:
-	$(CC) $(CFLAGS) -S $<
+O_TARGET := mm.o
+O_OBJS	= fault.o init.o extable.o
 
-OBJS	= fault.o init.o extable.o
-
-mm.o: $(OBJS)
-	$(LD) -r -o mm.o $(OBJS)
-
-modules:
-
-dep:
-
-fastdep:
-	$(TOPDIR)/scripts/mkdep *.[Sch] > .depend
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c
--- v2.1.50/linux/arch/ppc/mm/fault.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/mm/fault.c	Sat Aug 16 09:51:08 1997
@@ -1,8 +1,12 @@
 /*
  *  arch/ppc/mm/fault.c
  *
- *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
- *  Ported to PPC by Gary Thomas
+ *  PowerPC version 
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Derived from "arch/i386/mm/fault.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
  *  Modified by Cort Dougan and Paul Mackerras.
  *
  *  This program is free software; you can redistribute it and/or
@@ -26,40 +30,42 @@
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/mmu.h>
 #include <asm/mmu_context.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
 
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_XMON
+extern void xmon(struct pt_regs *);
 extern void (*xmon_fault_handler)(void);
-#endif
-
-/* the linux norm for the function name is show_regs() so
-   make it call dump_regs() on the mac -- Cort */
-#ifdef CONFIG_PMAC 
-#define show_regs dump_regs
+extern int xmon_dabr_match(struct pt_regs *);
+int xmon_kernel_faults;
 #endif
 
 extern void die_if_kernel(char *, struct pt_regs *, long);
 void bad_page_fault(struct pt_regs *, unsigned long);
 void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
-void print_pte(struct _PTE);
 
-void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code)     
+/*
+ * The error_code parameter is DSISR for a data fault, SRR1 for
+ * an instruction fault.
+ */
+void do_page_fault(struct pt_regs *regs, unsigned long address,
+		   unsigned long error_code)
 {
-	struct task_struct *tsk = current;
-	extern unsigned _end[];
 	struct vm_area_struct * vma;
 	struct mm_struct *mm = current->mm;
-	pgd_t *dir;
-	pmd_t *pmd;
-	pte_t *pte;
-	
-	/*printk("do_page_fault() %s/%d addr %x nip %x regs %x error %x\n",
-	       current->comm,current->pid,address,regs->nip,regs,error_code);*/
-#ifdef CONFIG_PMAC
+
+#ifdef CONFIG_XMON
 	if (xmon_fault_handler && regs->trap == 0x300) {
 		xmon_fault_handler();
 		return;
 	}
+	if (error_code & 0x00400000) {
+		/* DABR match */
+		if (xmon_dabr_match(regs))
+			return;
+	}
 #endif
 	if (in_interrupt()) {
 		static int complained;
@@ -68,14 +74,18 @@
 			printk("page fault in interrupt handler, addr=%lx\n",
 			       address);
 			show_regs(regs);
+#ifdef CONFIG_XMON
+			if (xmon_kernel_faults)
+				xmon(regs);
+#endif
 		}
 	}
-	if (current == NULL)
-		goto bad_area;
-	
-do_page:
+	if (current == NULL) {
+		bad_page_fault(regs, address);
+		return;
+	}
 	down(&mm->mmap_sem);
-	vma = find_vma(tsk->mm, address);
+	vma = find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
 	if (vma->vm_start <= address)
@@ -84,7 +94,7 @@
 		goto bad_area;
 	if (expand_stack(vma, address))
 		goto bad_area;
-  
+
 good_area:
 	if (error_code & 0xb5700000)
 		/* an error such as lwarx to I/O controller space,
@@ -98,67 +108,45 @@
 	/* a read */
 	} else {
 		/* protection fault */
-		if ( error_code & 0x08000000 )
+		if (error_code & 0x08000000)
 			goto bad_area;
 		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
 			goto bad_area;
 	}
 	handle_mm_fault(current, vma, address, error_code & 0x02000000);
-        up(&mm->mmap_sem);
-	/*printk("do_page_fault() return %s/%d addr %x msr %x\n",
-	      current->comm,current->pid,address,regs->msr);*/
-	/* not needed since flush_page_to_ram() works */
-#if 0
-	flush_page(address);
-#endif
+	up(&mm->mmap_sem);
 	return;
-  
+
 bad_area:
-	up(&current->mm->mmap_sem);
+	up(&mm->mmap_sem);
 	bad_page_fault(regs, address);
 }
 
-
 void
 bad_page_fault(struct pt_regs *regs, unsigned long address)
 {
-	extern unsigned int probingmem;
-	struct task_struct *tsk = current;
 	unsigned long fixup;
-	
+
+	if (user_mode(regs)) {
+		force_sig(SIGSEGV, current);
+		return;
+	}
 	
 	/* Are we prepared to handle this fault?  */
 	if ((fixup = search_exception_table(regs->nip)) != 0) {
-		if ( user_mode(regs) )
-			printk("Exception from user mode\n");
-#if 0    
-		printk(KERN_DEBUG "Exception at %lx (%lx)\n", regs->nip, fixup);
-#endif    
 		regs->nip = fixup;
 		return;
 	}
 
-	if ( user_mode(regs) )
-	{
-		force_sig(SIGSEGV, tsk);
-		return;
-	}
-  
-bad_kernel_access:
-	/* make sure it's not a bootup probe test */
-	if ( probingmem )
-	{
-		probingmem = 0;
-		return;
-	}
 	/* kernel has accessed a bad area */
 	show_regs(regs);
-	print_backtrace( regs->gpr[1] );
-#ifdef CONFIG_PMAC
-	xmon(regs);
+	print_backtrace( (unsigned long *)regs->gpr[1] );
+#ifdef CONFIG_XMON
+	if (xmon_kernel_faults)
+		xmon(regs);
 #endif
-	panic("kernel access of bad area\n pc %x address %X tsk %s/%d",
-	      regs->nip,address,tsk->comm,tsk->pid);
+	panic("kernel access of bad area\n pc %lx address %lX tsk %s/%d",
+	      regs->nip,address,current->comm,current->pid);
 }
 
 unsigned long va_to_phys(unsigned long address)
@@ -189,6 +177,10 @@
 	return (0);
 }
 
+#if 0
+/*
+ * Misc debugging functions.  Please leave them here. -- Cort
+ */
 void print_pte(struct _PTE p)
 {
 	printk(
@@ -210,7 +202,8 @@
 	for ( ptr = Hash ; ptr < Hash_end ; ptr++ )
 	{
 		if ( ptr->rpn == (address>>12) )
-			printk("phys %08X -> va ???\n",
+			printk("phys %08lX -> va ???\n",
 			       address);
 	}
 }
+#endif
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.1.50/linux/arch/ppc/mm/init.c	Mon Aug  4 16:25:36 1997
+++ linux/arch/ppc/mm/init.c	Sat Aug 16 09:51:08 1997
@@ -31,54 +31,48 @@
 #include <linux/mm.h>
 #include <linux/swap.h>
 #include <linux/stddef.h>
-#ifdef CONFIG_PMAC
 #include <asm/prom.h>
-#endif
 #include <asm/io.h>
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
 #include <asm/mmu.h>
-#ifdef CONFIG_PREP
 #include <asm/residual.h>
+#ifdef CONFIG_BLK_DEV_INITRD
+#include <linux/blk.h>		/* for initrd_* */
 #endif
 
+int prom_trashed;
 int next_mmu_context;
+unsigned long _SDR1;
+PTE *Hash, *Hash_end;
+unsigned long Hash_size, Hash_mask;
+unsigned long *end_of_DRAM;
+int mem_init_done;
 extern pgd_t swapper_pg_dir[];
 extern char _start[], _end[];
 extern char etext[], _stext[];
-/* References to section boundaries */
 extern char __init_begin, __init_end;
+extern RESIDUAL res;
 
-extern void die_if_kernel(char *,struct pt_regs *,long);
-extern void show_net_buffers(void);
-extern unsigned long *find_end_of_memory(void);
 
-#undef MAP_RAM_WITH_SEGREGS 1
-
-#ifdef CONFIG_PMAC
 void *find_mem_piece(unsigned, unsigned);
 static void mapin_ram(void);
 static void inherit_prom_translations(void);
-#endif
-#ifdef CONFIG_PREP
-inline void MMU_invalidate_page(struct mm_struct *mm, unsigned long va);
-int inline MMU_hash_page(struct task_struct *,unsigned long,pte *);     
-#endif
-
 static void hash_init(void);
 static void *MMU_get_page(void);
-void map_page(struct thread_struct *, unsigned long va,
+void map_page(struct task_struct *, unsigned long va,
 		     unsigned long pa, int flags);
+extern void die_if_kernel(char *,struct pt_regs *,long);
+extern void show_net_buffers(void);
+extern unsigned long *find_end_of_memory(void);
 
-PTE *Hash, *Hash_end;
-unsigned long Hash_size, Hash_mask;
-unsigned long *end_of_DRAM;
-int mem_init_done;
+/*
+ * this tells the prep system to map all of ram with the segregs
+ * instead of the bats.  I'd like to get this to apply to the
+ * pmac as well then have everything use the bats -- Cort
+ */
+#undef MAP_RAM_WITH_SEGREGS 1 
 
-#ifdef CONFIG_PREP
-#ifdef HASHSTATS
-extern unsigned long evicts;
-#endif /* HASHSTATS */
 /*
  * these are used to setup the initial page tables
  * They can waste up to an entire page since the
@@ -88,8 +82,6 @@
 unsigned int probingmem = 0;
 unsigned int mmu_pages_count = 0;
 char mmu_pages[(MAX_MMU_PAGES+1)*PAGE_SIZE];
-unsigned long _TotalMemory;
-#endif /* CONFIG_PREP */
 
 /*
  * BAD_PAGE is the page that is used for page faults when linux
@@ -120,7 +112,6 @@
 	return pte_mkdirty(mk_pte(empty_bad_page, PAGE_SHARED));
 }
 
-#ifdef CONFIG_PMAC
 #define MAX_MEM_REGIONS	32
 phandle memory_pkg;
 
@@ -128,7 +119,6 @@
 	int n_regions;
 	struct reg_property regions[MAX_MEM_REGIONS];
 };
-
 struct mem_pieces phys_mem;
 struct mem_pieces phys_avail;
 struct mem_pieces prom_mem;
@@ -138,7 +128,6 @@
 static void print_mem_pieces(struct mem_pieces *);
 
 unsigned long avail_start;
-int prom_trashed;
 
 /*
  * Read in a property describing some pieces of memory.
@@ -272,7 +261,7 @@
  * Our text, data, bss use something over 1MB, starting at 0.
  * Open Firmware may be using 1MB at the 4MB point.
  */
-unsigned long *find_end_of_memory(void)
+unsigned long *pmac_find_end_of_memory(void)
 {
 	unsigned long a, total;
 	unsigned long h, kstart, ksize;
@@ -353,6 +342,9 @@
 	int i;
 	unsigned long a, free;
 	unsigned long start, end;
+	
+	if ( _machine != _MACH_Pmac )
+		return 0;
 
 	free = 0;
 	for (i = 0; i < phys_avail.n_regions - 1; ++i) {
@@ -366,7 +358,6 @@
 	avail_start = (unsigned long) __va(a);
 	return avail_start;
 }
-#endif /* CONFIG_PMAC */
 
 void show_mem(void)
 {
@@ -399,14 +390,21 @@
 	       "Ctx", "Ctx<<4", "Last Sys", "pc", "task");
 	for_each_task(p)
 	{	
-		printk("%-8.8s %3d %3d %8d %8d %8d %c%08x %08x",
+		printk("%-8.8s %3d %3d %8ld %8ld %8ld %c%08lx %08lx ",
 		       p->comm,p->pid,
 		       p->mm->count,p->mm->context,
 		       p->mm->context<<4, p->tss.last_syscall,
 		       user_mode(p->tss.regs) ? 'u' : 'k', p->tss.regs->nip,
-		       p);
+		       (ulong)p);
 		if ( p == current )
-			printk(" current");
+			printk("current");
+		if ( p == last_task_used_math )
+		{
+			if ( p == current )
+				printk(",");
+			printk("last math");
+		}
+
 		printk("\n");
 	}
 }
@@ -434,76 +432,68 @@
 void mem_init(unsigned long start_mem, unsigned long end_mem)
 {
 	unsigned long addr;
-#ifdef CONFIG_PMAC
 	int i;
-	unsigned long lim;
-#endif
+	unsigned long a, lim;
 	int codepages = 0;
 	int datapages = 0;
 	int initpages = 0;
 
 	end_mem &= PAGE_MASK;
 	high_memory = (void *) end_mem;
-	num_physpages = max_mapnr = MAP_NR(high_memory);
-	
-	/* clear the zero-page */
-	memset(empty_zero_page, 0, PAGE_SIZE);
-	
+	max_mapnr = MAP_NR(high_memory);
+	num_physpages = max_mapnr;	/* RAM is assumed contiguous */
+
 	/* mark usable pages in the mem_map[] */
 	start_mem = PAGE_ALIGN(start_mem);
-	
-#ifdef CONFIG_PMAC
-	remove_mem_piece(&phys_avail, __pa(avail_start),
-			 start_mem - avail_start, 1);
-
-	for (a = KERNELBASE ; a < end_mem; a += PAGE_SIZE)
-		set_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
-
-	for (i = 0; i < phys_avail.n_regions; ++i) {
-		a = (unsigned long) __va(phys_avail.regions[i].address);
-		lim = a + phys_avail.regions[i].size;
-		a = PAGE_ALIGN(a);
-		for (; a < lim; a += PAGE_SIZE) {
-			clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
-			mem_map[MAP_NR(a)].count = 1;
-			free_page(a);
-		}
-	}
-	phys_avail.n_regions = 0;
 
-	/* free the prom's memory */
-	for (i = 0; i < prom_mem.n_regions; ++i) {
-		a = (unsigned long) __va(prom_mem.regions[i].address);
-		lim = a + prom_mem.regions[i].size;
-		a = PAGE_ALIGN(a);
-		for (; a < lim; a += PAGE_SIZE) {
-			clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
-			mem_map[MAP_NR(a)].count = 1;
-			free_page(a);
+	if ( _machine == _MACH_Pmac )
+	{
+		remove_mem_piece(&phys_avail, __pa(avail_start),
+				 start_mem - avail_start, 1);
+		
+		for (addr = KERNELBASE ; addr < end_mem; addr += PAGE_SIZE)
+			set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+		
+		for (i = 0; i < phys_avail.n_regions; ++i) {
+			a = (unsigned long) __va(phys_avail.regions[i].address);
+			lim = a + phys_avail.regions[i].size;
+			a = PAGE_ALIGN(a);
+			for (; a < lim; a += PAGE_SIZE)
+				clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
+		}
+		phys_avail.n_regions = 0;
+		
+		/* free the prom's memory */
+		for (i = 0; i < prom_mem.n_regions; ++i) {
+			a = (unsigned long) __va(prom_mem.regions[i].address);
+			lim = a + prom_mem.regions[i].size;
+			a = PAGE_ALIGN(a);
+			for (; a < lim; a += PAGE_SIZE)
+				clear_bit(PG_reserved, &mem_map[MAP_NR(a)].flags);
 		}
+		prom_trashed = 1;
 	}
-	prom_trashed = 1;
-#endif /* CONFIG_PMAC */
-
-#ifdef CONFIG_PREP
-	/* mark mem used by kernel as reserved, mark other unreserved */
-	for (addr = PAGE_OFFSET ; addr < end_mem; addr += PAGE_SIZE)
+	else /* prep */
 	{
-		/* skip hash table gap */
-		if ( (addr > (ulong)_end) && (addr < (ulong)Hash))
-			continue;
-		if ( addr < (ulong) /*Hash_end*/ start_mem )
-			set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
-		else
-			clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+		/* mark mem used by kernel as reserved, mark other unreserved */
+		for (addr = PAGE_OFFSET ; addr < end_mem; addr += PAGE_SIZE)
+		{
+			/* skip hash table gap */
+			if ( (addr > (ulong)_end) && (addr < (ulong)Hash))
+				continue;
+			if ( addr < (ulong) /*Hash_end*/ start_mem )
+				set_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+			else
+				clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
+		}
 	}
 
 	for (addr = PAGE_OFFSET; addr < end_mem; addr += PAGE_SIZE) {
-		if(PageReserved(mem_map + MAP_NR(addr))) {
+		if (PageReserved(mem_map + MAP_NR(addr))) {
 			if (addr < (ulong) etext)
 				codepages++;
-			/*else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
-                                initpages++;*/
+			else if((addr >= (unsigned long)&__init_begin && addr < (unsigned long)&__init_end))
+                                initpages++;
                         else if (addr < (ulong) start_mem)
 				datapages++;
 			continue;
@@ -515,9 +505,8 @@
 #endif /* CONFIG_BLK_DEV_INITRD */
 			free_page(addr);
 	}
-	
-#endif /* CONFIG_PREP */
-        printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08lx,%08lx]\n",
+
+        printk("Memory: %luk available (%dk kernel code, %dk data, %dk init) [%08x,%08lx]\n",
 	       (unsigned long) nr_free_pages << (PAGE_SHIFT-10),
 	       codepages << (PAGE_SHIFT-10),
 	       datapages << (PAGE_SHIFT-10), 
@@ -534,7 +523,6 @@
  */
 void free_initmem(void)
 {
-	unsigned long addr;
 	unsigned long a;
 	unsigned long num_freed_pages = 0;
 
@@ -548,16 +536,14 @@
 		num_freed_pages++;
 	}
 
-#if 0
-	addr = (unsigned long)(&__init_begin);
-	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
-		num_freed_pages++;
-		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
-		mem_map[MAP_NR(addr)].count = 1;
-		free_page(addr);
+	a = (unsigned long)(&__init_begin);
+	for (; a < (unsigned long)(&__init_end); a += PAGE_SIZE) {
+		mem_map[MAP_NR(a)].flags &= ~(1 << PG_reserved);
+		atomic_set(&mem_map[MAP_NR(a)].count, 1);
+		free_page(a);
 	}
-#endif	
-	printk ("Freeing unused kernel memory: %dk freed\n",
+
+	printk ("Freeing unused kernel memory: %ldk freed\n",
 		(num_freed_pages * PAGE_SIZE) >> 10);
 }
 
@@ -576,19 +562,13 @@
 		val->totalram++;
 		if (!atomic_read(&mem_map[i].count))
 			continue;
-		val->sharedram += atomic_read(&mem_map[i].count)-1;
+		val->sharedram += atomic_read(&mem_map[i].count) - 1;
 	}
 	val->totalram <<= PAGE_SHIFT;
 	val->sharedram <<= PAGE_SHIFT;
 	return;
 }
 
-/* Kernel MMU setup & lowest level hardware support */
-
-unsigned long _SDR1;		/* Hardware SDR1 image */
-
-#ifdef CONFIG_PREP
-
 BAT BAT0 =
 {
   {
@@ -635,7 +615,11 @@
     0x00000000>>17,		/* brpn */
     0,			/* w */
     0,			/* i */
+#ifdef __SMP__    
     1,			/* m */
+#else    
+    0,			/* m */
+#endif    
     0,			/* g */
     BPP_RW			/* pp */
   }
@@ -724,61 +708,41 @@
  * this will likely stay seperate from the pmac.
  * -- Cort
  */
-unsigned long *find_end_of_memory(void)
+unsigned long *prep_find_end_of_memory(void)
 {
-	extern RESIDUAL res;
-	extern unsigned long resptr;
-	int i, p;
+	int i;
 	unsigned long h;
-
-	/* copy residual data */
-	if ( resptr )
-		memcpy( &res, (void *)(resptr+KERNELBASE), sizeof(RESIDUAL) );
-	else
-		/* clearing bss probably clears this but... */
-		memset( &res, sizeof(RESIDUAL), 0 );
-	_TotalMemory = res.TotalMemory;
-	
-	/* this really has nothing to do with the mmu_init() but is
-	   necessary for early setup -- Cort */
-	if (!strncmp(res.VitalProductData.PrintableModel,"IBM",3))
-	{
-		_machine = _MACH_IBM;
-	}
-	else
-		_machine = _MACH_Motorola;
-  
 	/* setup the hash table */
-	if (_TotalMemory == 0 )
+	if (res.TotalMemory == 0 )
 	{
 		/*
 		 * I need a way to probe the amount of memory if the residual
 		 * data doesn't contain it. -- Cort
 		 */
 		printk("Ramsize from residual data was 0 -- Probing for value\n");
-		_TotalMemory = 0x03000000;
-		printk("Ramsize default to be %dM\n", _TotalMemory>>20);
+		res.TotalMemory = 0x03000000;
+		printk("Ramsize default to be %ldM\n", res.TotalMemory>>20);
 	}
 	
 #if 0
 	/* linux has trouble with > 64M ram -- Cort */
-	if ( _TotalMemory > 0x04000000 /* 64M */ )
+	if ( res.TotalMemory > 0x04000000 /* 64M */ )
 	{
 		printk("Only using first 64M of ram.\n");
-		_TotalMemory = 0x04000000;
+		res.TotalMemory = 0x04000000;
 	}
 #endif	
 	
 	/* setup the bat2 mapping to cover physical ram */
 	BAT2.batu.bl = 0x1; /* 256k mapping */
-	for ( h = 256*1024 /* 256k */ ; (h <= _TotalMemory) && (h <= 256*1024*1024);
+	for ( h = 256*1024 /* 256k */ ; (h <= res.TotalMemory) && (h <= 256*1024*1024);
 	      h *= 2 )
 		BAT2.batu.bl = (BAT2.batu.bl << 1) | BAT2.batu.bl;
 	/*
 	 * Allow 64k of hash table for every 16MB of memory,
 	 * up to a maximum of 2MB.
 	 */
-	for (h = 64<<10; h < _TotalMemory / 256 && h < 2<<20; h *= 2)
+	for (h = 64<<10; h < res.TotalMemory / 256 && h < 2<<20; h *= 2)
 		;
 	Hash_size = h;
 	Hash_mask = (h >> 6) - 1;
@@ -799,11 +763,11 @@
 	if ( _get_PVR() == 1 )
 	{
 		/* map in rest of ram with seg regs */
-		if ( _TotalMemory > 0x01000000 /* 16M */)
+		if ( res.TotalMemory > 0x01000000 /* 16M */)
 		{
 			for (i = KERNELBASE+0x01000000;
-			     i < KERNELBASE+_TotalMemory;  i += PAGE_SIZE)
-				map_page(&init_task.tss, i, __pa(i),
+			     i < KERNELBASE+res.TotalMemory;  i += PAGE_SIZE)
+				map_page(&init_task, i, __pa(i),
 					 _PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
 		}
 	}
@@ -815,25 +779,23 @@
 	memset(&BAT2_601, sizeof(BAT2), 0); /* in case we're on a 601 */
 	memset(&BAT3_601, sizeof(BAT2), 0);
 	/* map all of ram for kernel with segregs */
-	for (i = KERNELBASE;  i < KERNELBASE+_TotalMemory;  i += PAGE_SIZE)
+	for (i = KERNELBASE;  i < KERNELBASE+res.TotalMemory;  i += PAGE_SIZE)
 	{
 		if ( i < (unsigned long)etext )
-			map_page(&init_task.tss, i, __pa(i),
+			map_page(&init_task, i, __pa(i),
 				 _PAGE_PRESENT/*| _PAGE_RW*/|_PAGE_DIRTY|_PAGE_ACCESSED);
 		else
-			map_page(&init_task.tss, i, __pa(i),
+			map_page(&init_task, i, __pa(i),
 				 _PAGE_PRESENT| _PAGE_RW|_PAGE_DIRTY|_PAGE_ACCESSED);
 	}
 #endif /* MAP_RAM_WITH_SEGREGS */
 	
 	printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
-	       _TotalMemory >> 20, Hash_size >> 10, Hash);
-	return ((unsigned long *)_TotalMemory);
+	       res.TotalMemory >> 20, Hash_size >> 10, Hash);
+	return ((unsigned long *)res.TotalMemory);
 }
-#endif /* CONFIG_PREP */
 
 
-#ifdef CONFIG_PMAC
 /*
  * Map in all of physical memory starting at KERNELBASE.
  */
@@ -854,7 +816,10 @@
 	    f = _PAGE_PRESENT | _PAGE_ACCESSED;
 	    if ((char *) v < _stext || (char *) v >= etext)
 		f |= _PAGE_RW | _PAGE_DIRTY | _PAGE_HWWRITE;
-	    map_page(&init_task.tss, v, p, f);
+	    else
+		/* On the powerpc, no user access forces R/W kernel access */
+		f |= _PAGE_USER;
+	    map_page(&init_task, v, p, f);
 	    v += PAGE_SIZE;
 	    p += PAGE_SIZE;
 	}
@@ -889,7 +854,7 @@
 
 	for (tp = prom_translations, i = 0; i < n_translations; ++i, ++tp) {
 		/* ignore stuff mapped down low */
-		if (tp->virt < 0x10000000)
+		if (tp->virt < 0x10000000 && tp->phys < 0x10000000)
 			continue;
 		/* map PPC mmu flags to linux mm flags */
 		f = (tp->flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU
@@ -900,13 +865,12 @@
 		p = tp->phys;
 		n = tp->size;
 		for (; n != 0; n -= PAGE_SIZE) {
-			map_page(&init_task.tss, v, p, f);
+			map_page(&init_task, v, p, f);
 			v += PAGE_SIZE;
 			p += PAGE_SIZE;
 		}
 	}
 }
-#endif
 
 /*
  * Initialize the hash table and patch the instructions in head.S.
@@ -943,8 +907,8 @@
 	 * out from the data cache and invalidated in the instruction
 	 * cache, on those machines with split caches.
 	 */
-	store_cache_range((unsigned long) hash_page_patch_A,
-			  (unsigned long) (hash_page_patch_C + 1));
+	flush_icache_range((unsigned long) hash_page_patch_A,
+			   (unsigned long) (hash_page_patch_C + 1));
 }
 
 
@@ -958,71 +922,74 @@
 void
 MMU_init(void)
 {
-        end_of_DRAM = find_end_of_memory();
+	if ( _machine == _MACH_Pmac )
+		end_of_DRAM = pmac_find_end_of_memory();
+	else /* prep */
+		end_of_DRAM = prep_find_end_of_memory();
+		
         hash_init();
         _SDR1 = __pa(Hash) | (Hash_mask >> 10);
-#ifdef CONFIG_PMAC
-        /* Force initial page tables */
-	/* this done by INIT_TSS in processor.h on prep -- Cort */
-        init_task.tss.pg_tables = (unsigned long *)swapper_pg_dir;
-
-	/* Map in all of RAM starting at KERNELBASE */
-	mapin_ram();
-	/* Copy mappings from the prom */
-	inherit_prom_translations();
-#endif /* CONFIG_PMAC */
+
+	if ( _machine == _MACH_Pmac )
+	{
+		/* Map in all of RAM starting at KERNELBASE */
+		mapin_ram();
+		/* Copy mappings from the prom */
+		inherit_prom_translations();
+	}
 }
 
 static void *
 MMU_get_page()
 {
-  void *p;
-  
-  if (mem_init_done) {
-    p = (void *) __get_free_page(GFP_KERNEL);
-    if (p == 0)
-      panic("couldn't get a page in MMU_get_page");
-  } else {
-#ifdef CONFIG_PREP
-    mmu_pages_count++;
-    if ( mmu_pages_count > MAX_MMU_PAGES )
-      printk("out of mmu pages!\n");
-    p = (pte *)(PAGE_ALIGN((unsigned long)mmu_pages)+
-		(mmu_pages_count+PAGE_SIZE));
-#endif
-#ifdef CONFIG_PMAC
-    p = find_mem_piece(PAGE_SIZE, PAGE_SIZE);
-#endif
-  }
-  memset(p, 0, PAGE_SIZE);
-  return p;
+	void *p;
+
+	if (mem_init_done) {
+		p = (void *) __get_free_page(GFP_KERNEL);
+		if (p == 0)
+			panic("couldn't get a page in MMU_get_page");
+	} else {
+		if ( is_prep )
+		{
+			mmu_pages_count++;
+			if ( mmu_pages_count > MAX_MMU_PAGES )
+				printk("out of mmu pages!\n");
+			p = (pte *)(PAGE_ALIGN((unsigned long)mmu_pages)+
+				    (mmu_pages_count+PAGE_SIZE));
+		}
+		else /* pmac */
+		{
+			p = find_mem_piece(PAGE_SIZE, PAGE_SIZE);
+		}
+	}
+	memset(p, 0, PAGE_SIZE);
+	return p;
 }
 
-#ifdef CONFIG_PMAC
 void *
 ioremap(unsigned long addr, unsigned long size)
 {
 	unsigned long p, end = addr + size;
 
 	for (p = addr & PAGE_MASK; p < end; p += PAGE_SIZE)
-		map_page(&init_task.tss, p, p, pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED);
+		map_page(&init_task, p, p, pgprot_val(PAGE_KERNEL_CI) | _PAGE_GUARDED);
 	return (void *) addr;
 }
-#endif
 
 void
-map_page(struct thread_struct *tss, unsigned long va,
+map_page(struct task_struct *tsk, unsigned long va,
 	 unsigned long pa, int flags)
 {
 	pmd_t *pd;
 	pte_t *pg;
+	
 
-	if (tss->pg_tables == NULL) {
+	if (tsk->mm->pgd == NULL) {
 		/* Allocate upper level page map */
-		tss->pg_tables = (unsigned long *) MMU_get_page();
+		tsk->mm->pgd = (pgd_t *) MMU_get_page();
 	}
 	/* Use upper 10 bits of VA to index the first level map */
-	pd = (pmd_t *) (tss->pg_tables + (va >> PGDIR_SHIFT));
+	pd = (pmd_t *) (tsk->mm->pgd + (va >> PGDIR_SHIFT));
 	if (pmd_none(*pd)) {
 		/* Need to allocate second-level table */
 		pg = (pte_t *) MMU_get_page();
@@ -1084,26 +1051,6 @@
 	}
 }
 
-
-void
-flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
-{
-	unsigned vsid;
-	
-	if ( vmaddr < TASK_SIZE) {
-		/*vsid = (vma->vm_mm->context << 4) | (vmaddr >> 28);*/
-		flush_hash_page(vma->vm_mm->context/*vsid*/, vmaddr);
-		/* this is needed on prep at the moment -- don't know why
-		   -- Cort*/
-		MMU_invalidate_page(vma->vm_mm,vmaddr);
-	}
-	else
-	{
-		/*printk("flush_tlb_page() vmaddr > TASK_SIZE %08x\n", vmaddr);*/
-	}
-}
-
-
 /* for each page addr in the range, call MMU_invalidate_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
@@ -1113,15 +1060,10 @@
 void
 flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
 {
-        start &= PAGE_MASK;
+	start &= PAGE_MASK;
 	for (; start < end && start < TASK_SIZE; start += PAGE_SIZE)
 	{
-		/*flush_hash_page(VSID_FROM_CONTEXT( start>>28, mm->context),
-				start );*/
 		flush_hash_page(mm->context, start);
-		/* this is needed on prep at the moment -- don't know why
-		   -- Cort*/
-		MMU_invalidate_page(mm,start);
 	}
 }
 
@@ -1135,78 +1077,17 @@
 mmu_context_overflow(void)
 {
 	struct task_struct *tsk;
-	int nr;
 
-	printk(KERN_INFO "mmu_context_overflow\n");
-	for (nr = 0; nr < NR_TASKS; ++nr) {
-		tsk = task[nr];
-		if (tsk && tsk->mm)
+	printk(KERN_DEBUG "mmu_context_overflow\n");
+	read_lock(&tasklist_lock);
+ 	for_each_task(tsk) {
+		if (tsk->mm)
 			tsk->mm->context = NO_CONTEXT;
 	}
+	read_unlock(&tasklist_lock);
 	flush_hash_segments(0x10, 0xffffff);
-	_tlbia();
 	next_mmu_context = 0;
-}
-
-#ifdef CONFIG_PREP
-/*
- * it's not a simple matter to get rid of these and switch to the
- * ones paul is using. it will take some time and thought  -- Cort
- */
-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;
-	int flags = 0;
-	page_index = ((int)va & 0x0FFFF000) >> 12;
-	segment = (unsigned int)va >> 28;
-	api = page_index >> 10;
-	vsid = VSID_FROM_CONTEXT(segment,mm->context);
-	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];
-		for (i = 0;  i < 8;  i++, _pte++)
-		{
-			if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api)
-			{ /* Found it! */
-				_tlbie(va); /* Clear TLB */
-				if (_pte->r) flags |= _PAGE_ACCESSED;
-				if (_pte->c) flags |= _PAGE_DIRTY;
-				_pte->v = 0;
-				return /*(flags)*/;
-			}
-		}
-	}
-	_tlbie(va);
-	return /*(flags)*/;
-}
-#endif
-
-#include <asm/mmu.h>
-void print_mm_info(void)
-{
-	struct _SEGREG s;
-	long a;
-	struct _BATU bu;
-	struct _BATL bl;
-	unsigned long i;
-
-	for ( i = 0x70000000 ; i <= 0x90000000 ; i+= 0x10000000 )
-	{
-		a = get_SR(i);
-		memcpy(&s,&a,4);
-		printk("sr %2d t:%1d ks:%d kp:%d n:%d vsid:%x  %x\n",
-		       i>>28, s.t, s.ks, s.kp, s.n, s.vsid, a);
-	}
-
-	asm("mfspr %0,532; mfspr %1, 533\n" : "=r" (bu), "=r" (bl));
-	printk("bat2 bepi: %0x vs: %1x vp: %1x wimg: %x%x%x%x pp: %1x\n",
-       	       bu.bepi<<17, bu.vs, bu.vp, bl.w, bl.i, bl.m, bl.g, bl.pp);
+	/* make sure current always has a context */
+	current->mm->context = MUNGE_CONTEXT(++next_mmu_context);
+	set_context(current->mm->context);
 }
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/pmac_defconfig linux/arch/ppc/pmac_defconfig
--- v2.1.50/linux/arch/ppc/pmac_defconfig	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/pmac_defconfig	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,274 @@
+#
+# Automatically generated make config: don't edit
+#
+
+#
+# Platform support
+#
+CONFIG_NATIVE=y
+CONFIG_PMAC=y
+# CONFIG_PREP is not set
+CONFIG_MCOMMON=y
+# CONFIG_M601 is not set
+# CONFIG_M603 is not set
+# CONFIG_M604 is not set
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KERNELD=y
+CONFIG_PCI=y
+CONFIG_NET=y
+CONFIG_SYSCTL=y
+CONFIG_SYSVIPC=y
+CONFIG_BINFMT_ELF=y
+CONFIG_KERNEL_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_BINFMT_JAVA=m
+CONFIG_PMAC_CONSOLE=y
+CONFIG_MAC_KEYBOARD=y
+CONFIG_MAC_FLOPPY=y
+CONFIG_PROC_DEVICETREE=y
+CONFIG_XMON=y
+CONFIG_ATY_VIDEO=y
+CONFIG_IMSTT_VIDEO=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Floppy, IDE, and other block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+CONFIG_BLK_DEV_IDEDISK=y
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_TRITON is not set
+# CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_BLK_DEV_EZ is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_SEAGATE is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_ULTRASTOR is not set
+CONFIG_SCSI_MESH=y
+CONFIG_SCSI_MESH_SYNC_RATE=10
+CONFIG_SCSI_MAC53C94=y
+CONFIG_SCSI_QLOGIC_PMAC=m
+
+#
+# Network device support
+#
+
+#
+# Networking options
+#
+# CONFIG_NETLINK is not set
+# CONFIG_FIREWALL is not set
+CONFIG_NET_ALIAS=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ACCT is not set
+# CONFIG_IP_ROUTER is not set
+CONFIG_NET_IPIP=m
+# CONFIG_IP_MROUTE is not set
+CONFIG_IP_ALIAS=y
+# CONFIG_SYN_COOKIES is not set
+
+#
+# (it is safe to leave these untouched)
+#
+# CONFIG_INET_PCTCP is not set
+CONFIG_INET_RARP=y
+CONFIG_PATH_MTU_DISCOVERY=y
+CONFIG_IP_NOSR=y
+CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_AX25 is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_NETDEVICES=y
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MACE=y
+CONFIG_DEC_ELCP=m
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_EISA is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FDDI is not set
+# CONFIG_DLCI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+
+#
+# CCP compressors for PPP are only built as modules.
+#
+# CONFIG_NET_RADIO is not set
+# CONFIG_SLIP is not set
+# CONFIG_TR is not set
+# CONFIG_SHAPER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Filesystems
+#
+# CONFIG_QUOTA is not set
+CONFIG_MINIX_FS=m
+CONFIG_EXT2_FS=y
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_NFS_FS=y
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+# CONFIG_SMB_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_HPFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_UFS_FS is not set
+CONFIG_MAC_PARTITION=y
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_PRINTER is not set
+# CONFIG_MOUSE is not set
+# CONFIG_UMISC is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_FTAPE is not set
+# CONFIG_APM is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_RTC is not set
+CONFIG_NVRAM=y
+# CONFIG_JOYSTICK is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+# CONFIG_PAS is not set
+# CONFIG_SB is not set
+# CONFIG_ADLIB is not set
+# CONFIG_GUS is not set
+# CONFIG_MPU401 is not set
+# CONFIG_PSS is not set
+# CONFIG_GUS16 is not set
+# CONFIG_GUSMAX is not set
+# CONFIG_MSS is not set
+# CONFIG_SSCAPE is not set
+# CONFIG_TRIX is not set
+# CONFIG_MAD16 is not set
+# CONFIG_CS4232 is not set
+# CONFIG_MAUI is not set
+# CONFIG_YM3812 is not set
+CONFIG_LOWLEVEL_SOUND=y
+# CONFIG_ACI_MIXER is not set
+# CONFIG_AWE32_SYNTH is not set
+# CONFIG_AEDSP16 is not set
+CONFIG_AWACS=y
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/prep_defconfig linux/arch/ppc/prep_defconfig
--- v2.1.50/linux/arch/ppc/prep_defconfig	Mon Aug  4 16:25:37 1997
+++ linux/arch/ppc/prep_defconfig	Sat Aug 16 09:51:08 1997
@@ -1,30 +1,31 @@
 #
 # Automatically generated by make menuconfig: don't edit
 #
+
+#
+# Platform support
+#
 CONFIG_NATIVE=y
 # CONFIG_PMAC is not set
 CONFIG_PREP=y
-# CONFIG_HEARTBEAT is not set
-# CONFIG_POWERSAVING is not set
 CONFIG_MCOMMON=y
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KERNELD=y
 CONFIG_PCI=y
 CONFIG_PCI_OPTIMIZE=y
 CONFIG_NET=y
 CONFIG_SYSCTL=y
 CONFIG_SYSVIPC=y
-# CONFIG_BINFMT_JAVA is not set
 CONFIG_BINFMT_ELF=y
 CONFIG_KERNEL_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_BINFMT_JAVA is not set
 
 #
 # Plug and Play support
@@ -46,10 +47,10 @@
 # CONFIG_BLK_DEV_RZ1000 is not set
 # CONFIG_BLK_DEV_TRITON is not set
 # CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
-# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_BLK_DEV_EZ is not set
 # CONFIG_BLK_DEV_HD is not set
@@ -100,7 +101,6 @@
 # CONFIG_SCSI_ULTRASTOR is not set
 # CONFIG_SCSI_MESH is not set
 # CONFIG_SCSI_MAC53C94 is not set
-# CONFIG_SCSI_QLOGIC_PMAC is not set
 
 #
 # Network device support
@@ -117,6 +117,7 @@
 # CONFIG_IP_ACCT is not set
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
+# CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_PCTCP is not set
 # CONFIG_INET_RARP is not set
 CONFIG_PATH_MTU_DISCOVERY=y
@@ -155,6 +156,7 @@
 # CONFIG_DEC_ELCP is not set
 # CONFIG_DGRS is not set
 # CONFIG_EEXPRESS_PRO100 is not set
+# CONFIG_TLAN is not set
 # CONFIG_ES3210 is not set
 # CONFIG_ZNET is not set
 # CONFIG_NET_POCKET is not set
@@ -183,16 +185,13 @@
 # CONFIG_QUOTA is not set
 # CONFIG_MINIX_FS is not set
 CONFIG_EXT2_FS=y
-CONFIG_BEXT2_FS=y
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
 # CONFIG_VFAT_FS is not set
 # CONFIG_UMSDOS_FS is not set
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-# CONFIG_RNFS_BOOTP is not set
-# CONFIG_RNFS_RARP is not set
+# CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
@@ -205,7 +204,6 @@
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_UFS_FS is not set
 CONFIG_MAC_PARTITION=y
-CONFIG_HFS_FS=y
 
 #
 # Character devices
@@ -213,12 +211,7 @@
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_SERIAL=y
-CONFIG_SERIAL_EXTENDED=y
-# CONFIG_SERIAL_MANY_PORTS is not set
-# CONFIG_SERIAL_SHARE_IRQ is not set
-# CONFIG_SERIAL_MULTIPORT is not set
-# CONFIG_HUB6 is not set
-# CONFIG_SERIAL_CONSOLE is not set
+# CONFIG_SERIAL_EXTENDED is not set
 # CONFIG_SERIAL_NONSTANDARD is not set
 # CONFIG_PRINTER is not set
 CONFIG_MOUSE=y
@@ -227,13 +220,39 @@
 # CONFIG_MS_BUSMOUSE is not set
 CONFIG_PSMOUSE=y
 # CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_UMISC is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_FTAPE is not set
 # CONFIG_APM is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_RTC is not set
+# CONFIG_NVRAM is not set
+# CONFIG_JOYSTICK is not set
 
 #
 # Sound
 #
-# CONFIG_SOUND is not set
+#CONFIG_SOUND=y
+# CONFIG_PAS is not set
+# CONFIG_SB is not set
+# CONFIG_ADLIB is not set
+# CONFIG_GUS is not set
+# CONFIG_MPU401 is not set
+# CONFIG_PSS is not set
+# CONFIG_GUS16 is not set
+# CONFIG_GUSMAX is not set
+# CONFIG_MSS is not set
+# CONFIG_SSCAPE is not set
+# CONFIG_TRIX is not set
+# CONFIG_MAD16 is not set
+CONFIG_CS4232=y
+# CONFIG_MAUI is not set
+# CONFIG_YM3812 is not set
+CS4232_BASE=830
+CS4232_IRQ=10
+CS4232_DMA=6
+CS4232_DMA2=7
+CS4232_MPU_BASE=330
+CS4232_MPU_IRQ=9
+# CONFIG_LOWLEVEL_SOUND is not set
diff -u --recursive --new-file v2.1.50/linux/arch/ppc/vmlinux.lds linux/arch/ppc/vmlinux.lds
--- v2.1.50/linux/arch/ppc/vmlinux.lds	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/vmlinux.lds	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,80 @@
+OUTPUT_ARCH(powerpc)
+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)
+    *(.fixup)
+    *(.got1)
+  }
+  _etext = .;
+  PROVIDE (etext = .);
+  .rodata    :
+  {
+    *(.rodata)
+    *(.rodata1)
+  }
+  .fini      : { *(.fini)    } =0
+  .ctors     : { *(.ctors)   }
+  .dtors     : { *(.dtors)   }
+  /* Read-write section, merged into data segment: */
+  . = (. + 0x0FFF) & 0xFFFFF000;
+  .data    :
+  {
+    *(.data)
+    *(.data1)
+    *(.sdata)
+    *(.sdata2)
+    *(.got.plt) *(.got)
+    *(.dynamic)
+    CONSTRUCTORS
+  }
+  _edata  =  .;
+
+  . = ALIGN(4096);
+  __init_begin = .;
+  .text.init : { *(.text.init) }
+  .data.init : { *(.data.init) }
+  . = ALIGN(4096);
+  __init_end = .;
+
+  PROVIDE (edata = .);
+  __bss_start = .;
+  .bss       :
+  {
+   *(.sbss) *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+  }
+  _end = . ;
+  PROVIDE (end = .);
+}
+
diff -u --recursive --new-file v2.1.50/linux/arch/sparc/ap1000/aplib.c linux/arch/sparc/ap1000/aplib.c
--- v2.1.50/linux/arch/sparc/ap1000/aplib.c	Sun Jan 26 02:07:06 1997
+++ linux/arch/sparc/ap1000/aplib.c	Sat Aug 16 09:51:08 1997
@@ -455,7 +455,8 @@
 
 	while (counter == aplib->rbuf_flag1 + aplib->rbuf_flag2) {
 		tnet_check_completion();
-		if (need_resched) break;
+		if (resched_needed())
+			break;
 		if (current->signal & ~current->blocked) break;
 	}
 	return 0;
diff -u --recursive --new-file v2.1.50/linux/arch/sparc/ap1000/mpp.c linux/arch/sparc/ap1000/mpp.c
--- v2.1.50/linux/arch/sparc/ap1000/mpp.c	Tue May 13 22:41:03 1997
+++ linux/arch/sparc/ap1000/mpp.c	Sat Aug 16 09:51:08 1997
@@ -28,7 +28,7 @@
 void mpp_schedule(struct cap_request *req)
 {
 	mpp_current_task = req->data[0];
-	need_resched = 1;
+	resched_force();
 	mark_bh(TQUEUE_BH);
 }
 
diff -u --recursive --new-file v2.1.50/linux/arch/sparc/ap1000/msc.c linux/arch/sparc/ap1000/msc.c
--- v2.1.50/linux/arch/sparc/ap1000/msc.c	Sun Jan 26 02:07:06 1997
+++ linux/arch/sparc/ap1000/msc.c	Sat Aug 16 09:51:08 1997
@@ -338,7 +338,7 @@
 #endif
 		MSC_OUT(MSC_INTR, AP_SET_INTR_MASK << MSC_INTR_QBMFUL_SH);
 		intr_mask |= (AP_INTR_REQ << MSC_INTR_QBMFUL_SH);
-		need_resched = 1;
+		resched_force();
 		block_parallel_tasks = 1;
 		mark_bh(TQUEUE_BH);
 	}
diff -u --recursive --new-file v2.1.50/linux/arch/sparc/ap1000/tnet.c linux/arch/sparc/ap1000/tnet.c
--- v2.1.50/linux/arch/sparc/ap1000/tnet.c	Sun Jan 26 02:07:06 1997
+++ linux/arch/sparc/ap1000/tnet.c	Sat Aug 16 09:51:08 1997
@@ -613,7 +613,7 @@
 
 static void reschedule(void)
 {
-	need_resched = 1;  
+	resched_force();
 	mark_bh(TQUEUE_BH);
 }
 
diff -u --recursive --new-file v2.1.50/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v2.1.50/linux/arch/sparc/defconfig	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc/defconfig	Sat Aug 16 09:51:08 1997
@@ -49,6 +49,7 @@
 #
 CONFIG_SUN_OPENPROMIO=m
 CONFIG_SUN_MOSTEK_RTC=y
+# CONFIG_SAB82532 is not set
 # CONFIG_SUN_BPP is not set
 # CONFIG_SUN_VIDEOPIX is not set
 
@@ -105,6 +106,7 @@
 CONFIG_IP_ALIAS=m
 # CONFIG_ARPD is not set
 # CONFIG_SYN_COOKIES is not set
+# CONFIG_XTP is not set
 
 #
 # (it is safe to leave these untouched)
@@ -184,7 +186,7 @@
 CONFIG_EXT2_FS=y
 CONFIG_FAT_FS=m
 CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
+# CONFIG_VFAT_FS is not set
 # CONFIG_UMSDOS_FS is not set
 CONFIG_PROC_FS=y
 CONFIG_NFS_FS=y
@@ -207,6 +209,7 @@
 CONFIG_UFS_FS=y
 CONFIG_BSD_DISKLABEL=y
 CONFIG_SMD_DISKLABEL=y
+# CONFIG_MAC_PARTITION is not set
 
 #
 # Kernel hacking
diff -u --recursive --new-file v2.1.50/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c
--- v2.1.50/linux/arch/sparc/kernel/process.c	Thu Jul 17 10:06:03 1997
+++ linux/arch/sparc/kernel/process.c	Sat Aug 16 10:00:14 1997
@@ -105,6 +105,8 @@
 /* This is being executed in task 0 'user space'. */
 int cpu_idle(void *unused)
 {
+	extern volatile int smp_commenced;
+
 	current->priority = -100;
 	while(1) {
 		/*
@@ -118,7 +120,8 @@
 		}
 		/* endless idle loop with no priority at all */
 		current->counter = -100;
-		schedule();
+		if(!smp_commenced || resched_needed())
+			schedule();
 	}
 }
 
diff -u --recursive --new-file v2.1.50/linux/arch/sparc/kernel/ptrace.c linux/arch/sparc/kernel/ptrace.c
--- v2.1.50/linux/arch/sparc/kernel/ptrace.c	Thu May 15 16:48:01 1997
+++ linux/arch/sparc/kernel/ptrace.c	Sat Aug 16 09:51:08 1997
@@ -886,7 +886,7 @@
 	current->exit_code = SIGTRAP;
 	current->state = TASK_STOPPED;
 	current->tss.flags ^= MAGIC_CONSTANT;
-	notify_parent(current);
+	notify_parent(current, SIGCHLD);
 	schedule();
 	/*
 	 * this isn't the same as continuing with a signal, but it will do
diff -u --recursive --new-file v2.1.50/linux/arch/sparc/kernel/rtrap.S linux/arch/sparc/kernel/rtrap.S
--- v2.1.50/linux/arch/sparc/kernel/rtrap.S	Mon Apr 14 16:28:07 1997
+++ linux/arch/sparc/kernel/rtrap.S	Sat Aug 16 09:51:08 1997
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.46 1997/04/01 02:21:48 davem Exp $
+/* $Id: rtrap.S,v 1.47 1997/08/10 04:49:24 davem Exp $
  * rtrap.S: Return from Sparc trap low-level code.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -65,12 +65,14 @@
 
 	wr	%t_psr, 0x0, %psr
 	b	ret_trap_kernel
-	 nop
+	 mov	1, %o0
 
 1:
+	ld	[%curptr + AOFF_task_processor], %o1
 	ld	[%twin_tmp1 + %lo(C_LABEL(need_resched))], %g2
+	sll	%o0, %o1, %o0
 
-	cmp	%g2, 0
+	andcc	%g2, %o0, %g0
 	be	signal_p
 	 nop
 
diff -u --recursive --new-file v2.1.50/linux/arch/sparc/kernel/signal.c linux/arch/sparc/kernel/signal.c
--- v2.1.50/linux/arch/sparc/kernel/signal.c	Thu May 15 16:48:01 1997
+++ linux/arch/sparc/kernel/signal.c	Sat Aug 16 09:51:08 1997
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.74 1997/05/15 19:57:09 davem Exp $
+/*  $Id: signal.c,v 1.75 1997/08/05 19:19:26 davem Exp $
  *  linux/arch/sparc/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -722,7 +722,7 @@
 			/* This happens to be SMP safe so no need to
 			 * grab master kernel lock even in this case.
 			 */
-			notify_parent(current);
+			notify_parent(current, SIGCHLD);
 			schedule();
 			if (!(signr = current->exit_code))
 				continue;
@@ -773,7 +773,7 @@
 				/* notify_parent() is SMP safe */
 				if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
 				     SA_NOCLDSTOP))
-					notify_parent(current);
+					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
 
diff -u --recursive --new-file v2.1.50/linux/arch/sparc/kernel/smp.c linux/arch/sparc/kernel/smp.c
--- v2.1.50/linux/arch/sparc/kernel/smp.c	Thu May 15 16:48:01 1997
+++ linux/arch/sparc/kernel/smp.c	Sat Aug 16 09:51:08 1997
@@ -87,7 +87,7 @@
 #define SMP_PRINTK(x)
 #endif
 
-static volatile int smp_commenced = 0;
+volatile int smp_commenced = 0;
 
 static char smp_buf[512];
 
@@ -558,7 +558,7 @@
 /* Reschedule call back. */
 void smp_reschedule_irq(void)
 {
-	need_resched=1;
+	resched_force();
 }
 
 /* Running cross calls. */
@@ -623,7 +623,7 @@
 
 			if(--current->counter < 0) {
 				current->counter = 0;
-				need_resched = 1;
+				resched_force();
 			}
 
 			spin_lock(&ticker_lock);
diff -u --recursive --new-file v2.1.50/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c
--- v2.1.50/linux/arch/sparc/kernel/sys_sunos.c	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc/kernel/sys_sunos.c	Sat Aug 16 10:00:14 1997
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.81 1997/07/20 05:59:31 davem Exp $
+/* $Id: sys_sunos.c,v 1.80 1997/07/17 02:20:22 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
diff -u --recursive --new-file v2.1.50/linux/arch/sparc/mm/srmmu.c linux/arch/sparc/mm/srmmu.c
--- v2.1.50/linux/arch/sparc/mm/srmmu.c	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc/mm/srmmu.c	Sat Aug 16 09:51:08 1997
@@ -1,4 +1,4 @@
-/* $Id: srmmu.c,v 1.149 1997/07/20 05:59:34 davem Exp $
+/* $Id: srmmu.c,v 1.150 1997/07/25 23:06:17 davem Exp $
  * srmmu.c:  SRMMU specific routines for memory management.
  *
  * Copyright (C) 1995 David S. Miller  (davem@caip.rutgers.edu)
@@ -2601,7 +2601,7 @@
 }
 
 /* turbosparc.S */
-extern void turbosparc_flush_cache_all();
+extern void turbosparc_flush_cache_all(void);
 extern void turbosparc_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr);
 
 static void poke_turbosparc(void)
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.1.50/linux/arch/sparc64/config.in	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/config.in	Sat Aug 16 09:51:08 1997
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.9 1997/07/04 11:33:05 davem Exp $
+# $Id: config.in,v 1.10 1997/08/11 14:35:45 davem Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -43,6 +43,7 @@
 	define_bool CONFIG_SUN_CONSOLE y
 	define_bool CONFIG_SUN_AUXIO y
 	define_bool CONFIG_SUN_IO y
+	define_bool CONFIG_PCI y
 	source drivers/sbus/char/Config.in
 fi
 
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.1.50/linux/arch/sparc64/defconfig	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc64/defconfig	Sat Aug 16 09:51:08 1997
@@ -29,6 +29,7 @@
 CONFIG_SUN_CONSOLE=y
 CONFIG_SUN_AUXIO=y
 CONFIG_SUN_IO=y
+CONFIG_PCI=y
 
 #
 # SBUS Frame Buffer support
@@ -49,6 +50,7 @@
 #
 CONFIG_SUN_OPENPROMIO=m
 CONFIG_SUN_MOSTEK_RTC=y
+# CONFIG_SAB82532 is not set
 # CONFIG_SUN_BPP is not set
 # CONFIG_SUN_VIDEOPIX is not set
 CONFIG_SUN_OPENPROMFS=m
@@ -85,6 +87,7 @@
 # CONFIG_IP_ROUTER is not set
 # CONFIG_NET_IPIP is not set
 # CONFIG_SYN_COOKIES is not set
+# CONFIG_XTP is not set
 
 #
 # (it is safe to leave these untouched)
@@ -187,6 +190,7 @@
 CONFIG_UFS_FS=m
 CONFIG_BSD_DISKLABEL=y
 CONFIG_SMD_DISKLABEL=y
+# CONFIG_MAC_PARTITION is not set
 
 #
 # Kernel hacking
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/Makefile linux/arch/sparc64/kernel/Makefile
--- v2.1.50/linux/arch/sparc64/kernel/Makefile	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc64/kernel/Makefile	Sat Aug 16 09:51:08 1997
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.30 1997/07/24 14:48:04 davem Exp $
+# $Id: Makefile,v 1.34 1997/08/12 04:12:36 ecd Exp $
 # Makefile for the linux kernel.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -29,9 +29,10 @@
 
 O_TARGET := kernel.o
 O_OBJS   := process.o setup.o cpu.o idprom.o \
-	    systbls.o traps.o devices.o auxio.o ioport.o \
+	    traps.o devices.o auxio.o ioport.o \
 	    irq.o ptrace.o time.o sys_sparc.o signal.o \
-	    unaligned.o sys_sunos32.o sunos_ioctl32.o
+	    unaligned.o sys_sunos32.o sunos_ioctl32.o \
+	    central.o psycho.o ebus.o
 OX_OBJS  := sparc64_ksyms.o
 
 ifdef SMP
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/auxio.c linux/arch/sparc64/kernel/auxio.c
--- v2.1.50/linux/arch/sparc64/kernel/auxio.c	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc64/kernel/auxio.c	Sat Aug 16 09:51:08 1997
@@ -3,15 +3,20 @@
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
  */
 
+#include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/init.h>
+#include <linux/delay.h>
+
 #include <asm/oplib.h>
 #include <asm/io.h>
 #include <asm/auxio.h>
 #include <asm/sbus.h>
+#include <asm/ebus.h>
+#include <asm/fhc.h>
 
 /* Probe and map in the Auxiliary I/O register */
 unsigned char *auxio_register;
@@ -31,9 +36,32 @@
         }
 
 	if (!sdev) {
+#ifdef CONFIG_PCI
+		struct linux_ebus *ebus;
+		struct linux_ebus_device *edev = 0;
+
+		for_all_ebusdev(edev, ebus)
+			if (!strcmp(edev->prom_name, "auxio"))
+				break;
+
+		if (edev) {
+			auxio_register = (unsigned char *)
+				sparc_alloc_io(edev->regs[0].phys_addr, 0,
+					       edev->regs[0].reg_size,
+					       "auxiliaryIO",
+					       edev->regs[0].which_io, 0x0);
+			*(auxio_register) = 0x01;
+			return;
+		}
+#endif
+		if(central_bus) {
+			auxio_register = NULL;
+			return;
+		}
 		prom_printf("Cannot find auxio node, cannot continue...\n");
 		prom_halt();
 	}
+
 	prom_getproperty(sdev->prom_node, "reg", (char *) auxregs, sizeof(auxregs));
 	prom_apply_sbus_ranges(sdev->my_bus, auxregs, 0x1, sdev);
 	/* Map the register both read and write */
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/central.c linux/arch/sparc64/kernel/central.c
--- v2.1.50/linux/arch/sparc64/kernel/central.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/kernel/central.c	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,131 @@
+/* $Id: central.c,v 1.3 1997/08/12 14:51:55 davem Exp $
+ * central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+
+#include <asm/page.h>
+#include <asm/fhc.h>
+
+struct linux_central *central_bus = NULL;
+
+static inline unsigned long long_align(unsigned long addr)
+{
+	return ((addr + (sizeof(unsigned long) - 1)) &
+		~(sizeof(unsigned long) - 1));
+}
+
+extern void prom_central_ranges_init(int cnode, struct linux_central *central);
+extern void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc);
+
+unsigned long central_probe(unsigned long memory_start)
+{
+	struct linux_prom_registers fpregs[6];
+	struct linux_fhc *fhc;
+	char namebuf[128];
+	int cnode, fnode, err;
+
+	prom_printf("CENTRAL: ");
+	printk("CENTRAL: ");
+	cnode = prom_finddevice("/central");
+	if(cnode == 0 || cnode == -1) {
+		prom_printf("no central found.\n");
+		printk("no central found.\n");
+		return memory_start;
+	}
+	prom_printf("found central PROM node.\n");
+	printk("found central PROM node.\n");
+
+	/* Ok we got one, grab some memory for software state. */
+	memory_start = long_align(memory_start);
+	central_bus = (struct linux_central *) (memory_start);
+
+	prom_printf("CENTRAL: central_bus[%p] ", central_bus);
+	memory_start += sizeof(struct linux_central);
+	memory_start = long_align(memory_start);
+	fhc = (struct linux_fhc *)(memory_start);
+	memory_start += sizeof(struct linux_fhc);
+	memory_start = long_align(memory_start);
+
+	prom_printf("fhc[%p] ", fhc);
+
+	/* First init central. */
+	central_bus->child = fhc;
+	central_bus->prom_node = cnode;
+
+	prom_getstring(cnode, "name", namebuf, sizeof(namebuf));
+	strcpy(central_bus->prom_name, namebuf);
+
+	prom_printf("init_central_ranges ");
+	prom_central_ranges_init(cnode, central_bus);
+
+	/* And then central's FHC. */
+	fhc->next = NULL;
+	fhc->parent = central_bus;
+	fnode = prom_searchsiblings(prom_getchild(cnode), "fhc");
+	if(fnode == 0 || fnode == -1) {
+		prom_printf("Critical error, central board lacks fhc.\n");
+		prom_halt();
+	}
+	fhc->prom_node = fnode;
+	prom_getstring(fnode, "name", namebuf, sizeof(namebuf));
+	strcpy(fhc->prom_name, namebuf);
+
+	prom_printf("cnode[%x] fnode[%x] init_fhc_ranges\n", cnode, fnode);
+	prom_fhc_ranges_init(fnode, fhc);
+
+	/* Finally, map in FHC register set.  (From the prtconf dumps
+	 * I have seen on Ex000 boxes only the central ranges need to
+	 * be applied to the fhc internal register set) -DaveM
+	 */
+	err = prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs));
+	if(err == -1) {
+		prom_printf("CENTRAL: fatal error, cannot get fhc regs.\n");
+		prom_halt();
+	}
+	prom_apply_central_ranges(central_bus, &fpregs[0], 6);
+	prom_printf("CENTRAL: FHC_REGS[(%08x,%08x) (%08x,%08x) "
+		    "(%08x,%08x) (%08x,%08x) (%08x,%08x) (%08x,%08x)]\n",
+		    fpregs[0].which_io, fpregs[0].phys_addr,
+		    fpregs[1].which_io, fpregs[1].phys_addr,
+		    fpregs[2].which_io, fpregs[2].phys_addr,
+		    fpregs[3].which_io, fpregs[3].phys_addr,
+		    fpregs[4].which_io, fpregs[4].phys_addr,
+		    fpregs[5].which_io, fpregs[5].phys_addr);
+	fhc->fhc_regs.pregs = (struct fhc_internal_regs *)
+		__va((((unsigned long)fpregs[0].which_io)<<32) |
+		     (((unsigned long)fpregs[0].phys_addr)));
+	fhc->fhc_regs.ireg = (struct fhc_ign_reg *)
+		__va((((unsigned long)fpregs[1].which_io)<<32) |
+		     (((unsigned long)fpregs[1].phys_addr)));
+	fhc->fhc_regs.ffregs = (struct fhc_fanfail_regs *)
+		__va((((unsigned long)fpregs[2].which_io)<<32) |
+		     (((unsigned long)fpregs[2].phys_addr)));
+	fhc->fhc_regs.sregs = (struct fhc_system_regs *)
+		__va((((unsigned long)fpregs[3].which_io)<<32) |
+		     (((unsigned long)fpregs[3].phys_addr)));
+	fhc->fhc_regs.uregs = (struct fhc_uart_regs *)
+		__va((((unsigned long)fpregs[4].which_io)<<32) |
+		     (((unsigned long)fpregs[4].phys_addr)));
+	fhc->fhc_regs.tregs = (struct fhc_tod_regs *)
+		__va((((unsigned long)fpregs[5].which_io)<<32) |
+		     (((unsigned long)fpregs[5].phys_addr)));
+	prom_printf("CENTRAL: FHC_REGS[%p %p %p %p %p %p]\n",
+		    fhc->fhc_regs.pregs, fhc->fhc_regs.ireg,
+		    fhc->fhc_regs.ffregs, fhc->fhc_regs.sregs,
+		    fhc->fhc_regs.uregs, fhc->fhc_regs.tregs);
+
+	prom_printf("CENTRAL: reading FHC_ID register... ");
+	err = fhc->fhc_regs.pregs->fhc_id;
+	prom_printf("VALUE[%x]\n", err);
+	printk("FHC Version[%x] PartID[%x] Manufacturer[%x]\n",
+	       ((err & FHC_ID_VERS) >> 28),
+	       ((err & FHC_ID_PARTID) >> 12),
+	       ((err & FHC_ID_MANUF) >> 1));
+
+	return memory_start;
+}
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/cpu.c linux/arch/sparc64/kernel/cpu.c
--- v2.1.50/linux/arch/sparc64/kernel/cpu.c	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc64/kernel/cpu.c	Sat Aug 16 09:51:08 1997
@@ -46,8 +46,13 @@
 
 #define NSPARCCHIPS  (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info))
 
-char *sparc_cpu_type[NCPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
-char *sparc_fpu_type[NCPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
+#ifdef __SMP__
+char *sparc_cpu_type[NR_CPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" };
+char *sparc_fpu_type[NR_CPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" };
+#else
+char *sparc_cpu_type[NR_CPUS] = { "cpu-oops", };
+char *sparc_fpu_type[NR_CPUS] = { "fpu-oops", };
+#endif
 
 unsigned int fsr_storage;
 
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/devices.c linux/arch/sparc64/kernel/devices.c
--- v2.1.50/linux/arch/sparc64/kernel/devices.c	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc64/kernel/devices.c	Sat Aug 16 09:51:08 1997
@@ -17,13 +17,14 @@
 int linux_num_cpus = 0;
 
 extern void cpu_probe(void);
+extern unsigned long central_probe(unsigned long);
 
 __initfunc(unsigned long
 device_scan(unsigned long mem_start))
 {
 	char node_str[128];
 	int nd, prom_node_cpu, thismid;
-	int cpu_nds[NCPUS];  /* One node for each cpu */
+	int cpu_nds[NR_CPUS];  /* One node for each cpu */
 	int cpu_ctr = 0;
 
 	prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str));
@@ -43,11 +44,14 @@
 			if(strcmp(node_str, "cpu") == 0) {
 				cpu_nds[cpu_ctr] = scan;
 				linux_cpus[cpu_ctr].prom_node = scan;
-				prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid));
+				prom_getproperty(scan, "upa-portid",
+						 (char *) &thismid, sizeof(thismid));
 				linux_cpus[cpu_ctr].mid = thismid;
 				prom_printf("Found CPU %d <node=%08x,mid=%d>\n",
 					    cpu_ctr, (unsigned) scan,
 					    thismid);
+				printk("Found CPU %d <node=%08x,mid=%d>\n",
+				       cpu_ctr, (unsigned) scan, thismid);
 				cpu_ctr++;
 			}
 		};
@@ -62,5 +66,5 @@
 	linux_num_cpus = cpu_ctr;
 
 	cpu_probe();
-	return mem_start;
+	return central_probe(mem_start);
 }
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/dtlb_miss.S linux/arch/sparc64/kernel/dtlb_miss.S
--- v2.1.50/linux/arch/sparc64/kernel/dtlb_miss.S	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/dtlb_miss.S	Sat Aug 16 09:51:08 1997
@@ -1,4 +1,4 @@
-/* $Id: dtlb_miss.S,v 1.12 1997/06/26 12:47:08 jj Exp $
+/* $Id: dtlb_miss.S,v 1.13 1997/08/14 19:27:15 davem Exp $
  * dtlb_miss.S:	Data TLB miss code, this is included directly
  *              into the trap table.
  *
@@ -62,7 +62,7 @@
   /*0x40*/	sllx		%g1, 22, %g5			! This is now physical page + PAGE_OFFSET
   /*0x44*/	brgez,pn	%g5, 4f				! If >= 0, then walk down page tables
   /*0x48*/	 sethi		%uhi(KERN_HIGHBITS), %g1	! Construct PTE ^ PAGE_OFFSET
-  /*0x4c*/	andcc		%g3, 0x80, %g0			! Slick trick...
+  /*0x4c*/	andcc		%g3, 0x400, %g0			! Slick trick...
   /*0x50*/	sllx		%g1, 32, %g1			! Move high bits up
   /*0x54*/	or		%g1, (KERN_LOWBITS), %g1	! Assume not IO
   /*0x58*/	bne,a,pn	%icc, 5f			! Is it an IO page?
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/dtlb_prot.S linux/arch/sparc64/kernel/dtlb_prot.S
--- v2.1.50/linux/arch/sparc64/kernel/dtlb_prot.S	Sat May 24 09:10:23 1997
+++ linux/arch/sparc64/kernel/dtlb_prot.S	Sat Aug 16 09:51:08 1997
@@ -1,4 +1,4 @@
-/* $Id: dtlb_prot.S,v 1.12 1997/05/18 10:04:43 davem Exp $
+/* $Id: dtlb_prot.S,v 1.14 1997/08/03 09:07:00 davem Exp $
  * dtlb_prot.S:	Data TLB protection code, this is included directly
  *              into the trap table.
  *
@@ -36,17 +36,17 @@
 				/* ICACHE line 3 */
   /*0x40*/	add		%g2, 7, %g5				! Compute mask
   /*0x44*/	andn		%g4, %g5, %g4				! Mask page
-  /*0x48*/	or		%g4, 0x10, %g4				! 2ndary Context
-  /*0x4c*/	stxa		%g0, [%g4] ASI_DMMU_DEMAP		! TLB flush page
-  /*0x50*/	membar		#Sync					! Synchronize
-  /*0x54*/	stxa		%g3, [%g1] ASI_PHYS_USE_EC		! Update sw PTE
-  /*0x58*/	stxa		%g3, [%g0] ASI_DTLB_DATA_IN		! TLB load
-  /*0x5c*/	retry							! Trap return
+  /*0x48*/	mov		TLB_SFSR, %g5				! read SFSR
+  /*0x4c*/	ldxa		[%g5] ASI_DMMU, %g5			! from DMMU for
+  /*0x50*/	and		%g5, 0x10, %g5				! context bit
+  /*0x54*/	or		%g4, %g5, %g4				! for prot trap
+1:/*0x58*/	stxa		%g0, [%g4] ASI_DMMU_DEMAP		! TLB flush page
+  /*0x5c*/	membar		#Sync					! Synchronize
 
 				/* ICACHE line 4 */
-  /*0x60*/	nop
-  /*0x64*/	nop
-  /*0x68*/	nop
+  /*0x60*/	stxa		%g3, [%g1] ASI_PHYS_USE_EC		! Update sw PTE
+  /*0x64*/	stxa		%g3, [%g0] ASI_DTLB_DATA_IN		! TLB load
+  /*0x68*/	retry							! Trap return
   /*0x6c*/	nop
   /*0x70*/	nop
   /*0x74*/	nop
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/ebus.c linux/arch/sparc64/kernel/ebus.c
--- v2.1.50/linux/arch/sparc64/kernel/ebus.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/kernel/ebus.c	Sat Aug 16 09:51:08 1997
@@ -0,0 +1,169 @@
+/* $Id: ebus.c,v 1.2 1997/08/15 06:44:13 davem Exp $
+ * ebus.c: PCI to EBus bridge device.
+ *
+ * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/system.h>
+#include <asm/pbm.h>
+#include <asm/ebus.h>
+#include <asm/oplib.h>
+#include <asm/bpp.h>
+
+struct linux_ebus *ebus_chain = 0;
+
+static char lbuf[128];
+
+extern void prom_ebus_ranges_init(struct linux_ebus *);
+
+#ifdef CONFIG_SUN_OPENPROMIO
+extern int openprom_init(void);
+#endif
+#ifdef CONFIG_SUN_MOSTEK_RTC
+extern int rtc_init(void);
+#endif
+#ifdef CONFIG_SPARCAUDIO
+extern int sparcaudio_init(void);
+#endif
+#ifdef CONFIG_SUN_AUXIO
+extern void auxio_probe(void);
+#endif
+
+__initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev))
+{
+	int irqs[PROMINTR_MAX];
+	int i, len;
+
+	dev->prom_node = node;
+	prom_getstring(node, "name", lbuf, sizeof(lbuf));
+	strcpy(dev->prom_name, lbuf);
+
+	len = prom_getproperty(node, "reg", (void *)dev->regs,
+			       sizeof(dev->regs));
+	if (len % sizeof(struct linux_prom_registers)) {
+		prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
+			    dev->prom_name, len,
+			    (int)sizeof(struct linux_prom_registers));
+		panic(__FUNCTION__);
+	}
+	dev->num_registers = len / sizeof(struct linux_prom_registers);
+
+	prom_apply_ebus_ranges(dev->parent, dev->regs, dev->num_registers);
+#if 0 /* XXX No longer exists/needed in new framework... */
+	prom_apply_pbm_ranges(dev->parent->parent, dev->regs,
+			      dev->num_registers);
+#endif
+
+	len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
+	if ((len == -1) || (len == 0)) {
+		dev->irqs[0].pri = 0;
+		dev->num_irqs = 0;
+	} else {
+		dev->num_irqs = len / sizeof(irqs[0]);
+		for (i = 0; i < dev->num_irqs; i++)
+			dev->irqs[i].pri = irqs[i];
+	}
+
+	printk("Found '%s' at %x.%08x", dev->prom_name,
+	       dev->regs[0].which_io, dev->regs[0].phys_addr);
+	if (dev->num_irqs) {
+		printk(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
+		for (i = 0; i < dev->num_irqs; i++)
+			printk(" %03x", dev->irqs[i].pri);
+	}
+	printk("\n");
+}
+
+__initfunc(unsigned long ebus_init(unsigned long memory_start,
+				   unsigned long memory_end))
+{
+	struct linux_ebus_device *dev;
+	struct linux_ebus *ebus;
+	int nd, ebusnd, topnd;
+	int num_ebus = 0;
+
+#ifndef CONFIG_PCI
+	return memory_start;
+#endif
+
+	memory_start = ((memory_start + 7) & (~7));
+
+	topnd = psycho_root->pbm_B.prom_node;
+	if (!topnd)
+		return memory_start;
+
+	ebusnd = prom_searchsiblings(prom_getchild(topnd), "ebus");
+	if (ebusnd == 0) {
+		printk("EBUS: No EBUS's found.\n");
+		return memory_start;
+	}
+
+	ebus_chain = ebus = (struct linux_ebus *)memory_start;
+	memory_start += sizeof(struct linux_ebus);
+	ebus->next = 0;
+
+	while (ebusnd) {
+		printk("ebus%d: ", num_ebus);
+
+		prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf));
+		ebus->prom_node = ebusnd;
+		strcpy(ebus->prom_name, lbuf);
+		ebus->parent = &psycho_root->pbm_B;
+
+		prom_ebus_ranges_init(ebus);
+
+		nd = prom_getchild(ebusnd);
+		ebus->devices = (struct linux_ebus_device *)memory_start;
+		memory_start += sizeof(struct linux_ebus_device);
+
+		dev = ebus->devices;
+		dev->next = 0;
+		dev->parent = ebus;
+		fill_ebus_device(nd, dev);
+
+		while ((nd = prom_getsibling(nd))) {
+			dev->next = (struct linux_ebus_device *)memory_start;
+			memory_start += sizeof(struct linux_ebus_device);
+
+			dev = dev->next;
+			dev->next = 0;
+			dev->parent = ebus;
+			fill_ebus_device(nd, dev);
+		}
+
+		ebusnd = prom_searchsiblings(prom_getsibling(ebusnd), "ebus");
+		++num_ebus;
+	}
+
+#ifdef CONFIG_SUN_OPENPROMIO
+	openprom_init();
+#endif
+#ifdef CONFIG_SUN_MOSTEK_RTC
+	rtc_init();
+#endif
+#ifdef CONFIG_SPARCAUDIO
+	sparcaudio_init();
+#endif
+#ifdef CONFIG_SUN_BPP
+	bpp_init();
+#endif
+#ifdef CONFIG_SUN_AUXIO
+	if (sparc_cpu_model == sun4u)
+		auxio_probe();
+#endif
+#ifdef __sparc_v9__
+	if (sparc_cpu_model == sun4u) {
+		extern void sun4u_start_timers(void);
+		extern void clock_probe(void);
+
+		sun4u_start_timers();
+		clock_probe();
+	}
+#endif
+	return memory_start;
+}
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- v2.1.50/linux/arch/sparc64/kernel/entry.S	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc64/kernel/entry.S	Sat Aug 16 09:51:08 1997
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.51 1997/07/24 12:15:04 davem Exp $
+/* $Id: entry.S,v 1.61 1997/08/15 06:44:16 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -50,41 +50,39 @@
 
 	bgu,a,pn	%icc, winfix_trampoline
 	 rdpr		%tpc, %g3
+	sethi		%hi(109f), %g7
 	ba,pt		%xcc, etrap
-	 rd		%pc, %g7
+109:	 or		%g7, %lo(109b), %g7
 	b,pt		%xcc, 1f
 	 mov		1, %o2
+	.align		32
 sparc64_dtlb_refbit_catch:
 	srlx		%g5, 9, %g4
 	and		%g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
-
 	cmp		%g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9)
 	be,a,pt		%xcc, 2f
 	 mov		1, %g4
 	wr		%g0, ASI_DMMU, %asi
 	rdpr		%pstate, %g1
 	wrpr		%g1, PSTATE_AG|PSTATE_MG, %pstate
+
 	rdpr		%tl, %g3
 	ldxa		[%g0 + TLB_TAG_ACCESS] %asi, %g5
-
 	cmp		%g3, 1
 	bgu,pn		%icc, winfix_trampoline
 	 rdpr		%tpc, %g3
+	sethi		%hi(109f), %g7
 	b,pt		%xcc, etrap
-	 rd		%pc, %g7
+109:	 or		%g7, %lo(109b), %g7
+
 	clr		%o2
 1:	srlx		%l5, PAGE_SHIFT, %o1
 	add		%sp, STACK_BIAS + REGWIN_SZ, %o0
-
 	call		do_sparc64_fault
 	 sllx		%o1, PAGE_SHIFT, %o1
 	b,pt		%xcc, rtrap
 	 clr		%l6
-	nop
-	nop
-	nop
-	nop
-
+	.align		32
 sparc64_itlb_refbit_catch:
 	srlx		%g5, 9, %g4
 	and		%g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
@@ -95,17 +93,21 @@
 	wrpr		%g1, PSTATE_AG|PSTATE_MG, %pstate
 	rdpr		%tpc, %g5
 
+	sethi		%hi(109f), %g7
 	b,pt		%xcc, etrap
-	 rd		%pc, %g7
+109:	 or		%g7, %lo(109b), %g7
 	b,pt		%xcc, 1b
 	 clr		%o2
+
+	.align		32
 2:	sllx		%g4, 63, %g4				! _PAGE_VALID
 	or		%g5, _PAGE_ACCESSED, %g5
 	or		%g5, %g4, %g5
 	stxa		%g5, [%g3 + %g1] ASI_PHYS_USE_EC	! store new PTE
-
 	stxa		%g5, [%g0] ASI_DTLB_DATA_IN		! TLB load
 	retry
+
+	.align		32
 3:	sllx		%g4, 63, %g4				! _PAGE_VALID
 	or		%g5, _PAGE_ACCESSED, %g5
 	or		%g5, %g4, %g5
@@ -172,6 +174,7 @@
 	or		%g2, %lo((((PAGE_SIZE<<1)-((64*4)+(2*8))) & ~(64 - 1))), %g2
 	add		%g6, %g2, %g2
 	mov		SECONDARY_CONTEXT, %g3
+	ldxa		[%g3] ASI_DMMU, %g7
 	stxa		%g0, [%g3] ASI_DMMU
 	flush		%g2
 	wr		%g0, ASI_BLK_S, %asi	! grrr, where is ASI_BLK_NUCLEUS 8-(
@@ -182,9 +185,12 @@
 	ldda		[%g2 + 0x080] %asi, %f32
 	ldda		[%g2 + 0x0c0] %asi, %f48
 	ldx		[%g2 + 0x100], %fsr
-	ldx		[%g2 + 0x108], %g2
+	ldx		[%g2 + 0x108], %g4
 	membar		#Sync
-	wr		%g2, 0, %gsr
+	wr		%g4, 0, %gsr
+
+	stxa		%g7, [%g3] ASI_DMMU
+	flush		%g2
 fpdis_exit:
 	rdpr		%tstate, %g3
 	sethi		%hi(TSTATE_PEF), %g4
@@ -192,10 +198,7 @@
 	wrpr		%g3, %tstate
 	retry
 
-#ifdef __SMP__
-	/* Note check out head.h, this code isn't even used for UP,
-	 * for SMP things will be different.  In particular the data
-	 * registers for cross calls will be:
+	/* The registers for cross calls will be:
 	 *
 	 * DATA 0: [low 32-bits]  Address of function to call, jmp to this
 	 *         [high 32-bits] MMU Context Argument 0, place in %g5
@@ -205,11 +208,17 @@
 	 * With this method we can do most of the cross-call tlb/cache
 	 * flushing very quickly.
 	 */
+	.data
+	.align  8
+	.globl	ivec_spurious_cookie
+ivec_spurious_cookie:	.xword	0
+
+	.text
 	.align	32
-	.globl	do_ivec, do_ivec_return
+	.globl	do_ivec
 do_ivec:
-	ldxa		[%g0] ASI_INTR_RECEIVE, %g1
-	andcc		%g1, 0x20, %g0
+	ldxa		[%g0] ASI_INTR_RECEIVE, %g5
+	andcc		%g5, 0x20, %g0
 	be,pn		%xcc, do_ivec_return
 	 mov		0x40, %g2
 
@@ -230,32 +239,35 @@
 	 * which is completely harmless.
 	 */
 	wr		%g2, 0x0, %set_softint
-
 do_ivec_return:
-	/* Acknowledge the UPA */
 	stxa		%g0, [%g0] ASI_INTR_RECEIVE
 	membar		#Sync
 	retry
 do_ivec_xcall:
 	srlx		%g3, 32, %g5
 	add		%g2, 0x10, %g2
-	sra		%g3, 0, %g3
+	srl		%g3, 0, %g3
 	ldxa		[%g2] ASI_UDB_INTR_R, %g6
 	add		%g2, 0x10, %g2
+	ldxa		[%g2] ASI_UDB_INTR_R, %g7
+	stxa		%g0, [%g0] ASI_INTR_RECEIVE
 	jmpl		%g3, %g0
-	 ldxa		[%g2] ASI_UDB_INTR_R, %g7
+	 membar		#Sync
 do_ivec_spurious:
+	srl		%g3, 3, %g3
+	sethi		%hi(ivec_spurious_cookie), %g2
+	stx		%g3, [%g2 + %lo(ivec_spurious_cookie)]
 	stxa		%g0, [%g0] ASI_INTR_RECEIVE
 	membar		#Sync
-	rdpr		%pstate, %g1
-	wrpr		%g1, PSTATE_IG | PSTATE_AG, %pstate
+	rdpr		%pstate, %g5
+	wrpr		%g5, PSTATE_IG | PSTATE_AG, %pstate
+	sethi		%hi(109f), %g7
 	ba,pt		%xcc, etrap
-	 rd		%pc, %g7
+109:	 or		%g7, %lo(109b), %g7
 	call		report_spurious_ivec
 	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
 	ba,pt		%xcc, rtrap
 	 clr		%l6
-#endif /* __SMP__ */
 
 	.globl		getcc, setcc
 getcc:
@@ -359,8 +371,9 @@
 floppy_dosoftint:
 	rdpr		%pil, %g2
 	wrpr		%g0, 15, %pil
+	sethi		%hi(109f), %g7
 	b,pt		%xcc, etrap_irq
-	 rd		%pc, %g7
+109:	 or		%g7, %lo(109b), %g7
 
 	mov		11, %o0
 	mov		0, %o1
@@ -386,8 +399,9 @@
 	cmp		%g3, 1
 	bgu,a,pn	%icc, winfix_mna
 	 rdpr		%tpc, %g3
+	sethi		%hi(109f), %g7
 	ba,pt		%xcc, etrap
-	 rd		%pc, %g7
+109:	 or		%g7, %lo(109b), %g7
 	call		mem_address_unaligned
 	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
 	ba,pt		%xcc, rtrap
@@ -573,14 +587,8 @@
 sys_vfork:	mov		SIGCHLD, %o0
 		clr		%o1
 sys_clone:	mov		%o7, %l5
-/*???*/		save		%sp, -REGWIN_SZ, %sp
-		flushw
-/*???*/		restore		%g0, %g0, %g0
-		rdpr		%cwp, %o4
 		add		%sp, STACK_BIAS + REGWIN_SZ, %o2
-
 		movrz		%o1, %fp, %o1
-		stx		%o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0]
 		call		do_fork
 		 mov		%l5, %o7
 #ifdef __SMP__
@@ -611,9 +619,9 @@
 	cmp		%g1, NR_SYSCALLS			! IEU1	Group
 	bgeu,pn		%xcc, linux_sparc_ni_syscall		! CTI
 	 mov		%i0, %o0				! IEU0
-	sll		%g1, 3, %l4				! IEU0	Group
+	sll		%g1, 2, %l4				! IEU0	Group
 	mov		%i1, %o1				! IEU1
-	ldx		[%l7 + %l4], %l7			! Load
+	lduw		[%l7 + %l4], %l7			! Load
 syscall_is_too_hard:
 	mov		%i2, %o2				! IEU0	Group
 	ldx		[%curptr + AOFF_task_flags], %l5	! Load
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/etrap.S linux/arch/sparc64/kernel/etrap.S
--- v2.1.50/linux/arch/sparc64/kernel/etrap.S	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/etrap.S	Sat Aug 16 09:51:08 1997
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.30 1997/06/30 10:31:37 jj Exp $
+/* $Id: etrap.S,v 1.34 1997/08/08 08:33:40 jj Exp $
  * etrap.S: Preparing for entry into the kernel on Sparc V9.
  *
  * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -16,6 +16,11 @@
 #define		TASK_REGOFF		((((PAGE_SIZE<<1)-FPUREG_SZ)&~(64-1)) - \
 					 TRACEREG_SZ-REGWIN_SZ)
 
+/*
+ * On entry, %g7 is return address - 0x4.
+ * %g4 and %g5 will be preserved %l4 and %l5 respectively.
+ */
+
 		.text
 		.align			32
 		.globl			etrap, etrap_irq, etraptl1
@@ -111,18 +116,23 @@
 		membar			#Sync
 
 		sub			%g2, (TRACEREG_SZ + REGWIN_SZ), %g2
-2:		b,pt			%xcc, etrap_after_fpu
+2:		bne,pn			%xcc, etrap_after_fpu
 		 wr			%g0, 0, %fprs
-3:		/* Because Ultra lacks ASI_BLK_NUCLEUS a hack has to take place. */
-		mov			SECONDARY_CONTEXT, %g3
+		ld			[%g6 + AOFF_task_tss + AOFF_thread_ctx], %g3
+		wr			%g0, ASI_DMMU, %asi
+		nop
+		stxa			%g3, [%g0 + SECONDARY_CONTEXT] %asi
+		flush			%g2
+
+		b,pt			%xcc, etrap_after_fpu
+		 nop
+3:		mov			SECONDARY_CONTEXT, %g3
 		stxa			%g0, [%g3] ASI_DMMU
 		flush			%g2
 		wr			%g0, ASI_BLK_S, %asi
-		nop
-
 		b,pt			%xcc, 1b
 		 mov			FPRS_FEF, %g3
-		nop
+
 etraptl1:	rdpr			%tstate, %g1
 		sub			%sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
 		ba,pt			%xcc, etrap_maybe_fpu
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S
--- v2.1.50/linux/arch/sparc64/kernel/head.S	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/head.S	Sat Aug 16 09:51:08 1997
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.43 1997/07/07 03:05:25 davem Exp $
+/* $Id: head.S,v 1.46 1997/08/08 08:33:30 jj Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -21,6 +21,7 @@
 #include <asm/processor.h>
 #include <asm/lsu.h>
 #include <asm/head.h>
+#include <asm/ttable.h>
 	
 /* This section from from _start to sparc64_boot_end should fit into
  * 0x0000.0000.0040.4000 to 0x0000.0000.0040.8000 and will be sharing space
@@ -89,6 +90,28 @@
          */
 	wrpr    %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
 
+#ifdef __SMP__
+	/* Ugly but necessary... */
+	sethi	%hi(KERNBASE), %g7
+	sethi	%hi(sparc64_cpu_startup), %g5
+	or	%g5, %lo(sparc64_cpu_startup), %g5
+	sub	%g5, %g7, %g5
+	sethi	%hi(sparc64_cpu_startup_end), %g6
+	or	%g6, %lo(sparc64_cpu_startup_end), %g6
+	sub	%g6, %g7, %g6
+	sethi	%hi(smp_trampoline), %g3
+	or	%g3, %lo(smp_trampoline), %g3
+	sub	%g3, %g7, %g3
+1:	ldx	[%g5], %g1
+	stx	%g1, [%g3]
+	membar	#StoreStore
+	flush	%g3
+	add	%g5, 8, %g5
+	cmp	%g5, %g6
+	blu,pt	%xcc, 1b
+	 add	%g3, 8, %g3
+#endif
+
 create_mappings:
 	/* %g5 holds the tlb data */
         sethi   %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
@@ -340,7 +363,7 @@
 	mov	0x40, %g2			/* INTR data 0 register */
 
 	/* Ok, we're done setting up all the state our trap mechanims needs,
-	 * now get back into normal globals and let the PROM know what it up.
+	 * now get back into normal globals and let the PROM know what is up.
 	 */
 	wrpr	%g0, %g0, %wstate
 	wrpr	%o1, PSTATE_IE, %pstate
@@ -374,6 +397,7 @@
 ! 0x0000000000408000
 
 #include "ttable.S"
+#include "systbls.S"
 #include "etrap.S"
 #include "rtrap.S"
 #include "winfixup.S"
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.1.50/linux/arch/sparc64/kernel/ioctl32.c	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc64/kernel/ioctl32.c	Sat Aug 16 10:00:14 1997
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.14 1997/07/17 06:21:12 davem Exp $
+/* $Id: ioctl32.c,v 1.13 1997/07/17 02:20:38 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/ioport.c linux/arch/sparc64/kernel/ioport.c
--- v2.1.50/linux/arch/sparc64/kernel/ioport.c	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc64/kernel/ioport.c	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/* $Id: ioport.c,v 1.11 1997/07/22 06:14:04 davem Exp $
+/* $Id: ioport.c,v 1.12 1997/08/08 05:07:02 davem Exp $
  * ioport.c:  Simple io mapping allocator.
  *
  * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu)
@@ -45,7 +45,7 @@
 		      u32 bus_type, int rdonly)
 {
 	unsigned long vaddr, base_address;
-	unsigned long addr = ((unsigned long) address) + (((unsigned long) bus_type) << 32);
+	unsigned long addr = ((unsigned long)address) + (((unsigned long)bus_type)<<32);
 	unsigned long offset = (addr & (~PAGE_MASK));
 
 	if (virtual) {
@@ -64,7 +64,12 @@
 		/* Tell Linux resource manager about the mapping */
 		request_region ((vaddr | offset), len, name);
 	} else {
-		return __va(addr);
+		unsigned long vaddr = (unsigned long) __va(addr);
+
+		if(!check_region(vaddr, len))
+			request_region(vaddr, len, name);
+
+		return (void *) vaddr;
 	}
 
 	base_address = vaddr;
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c
--- v2.1.50/linux/arch/sparc64/kernel/irq.c	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc64/kernel/irq.c	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.19 1997/07/24 12:15:04 davem Exp $
+/* $Id: irq.c,v 1.34 1997/08/15 06:44:18 davem Exp $
  * irq.c: UltraSparc IRQ handling/init/registry.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -28,8 +28,18 @@
 #include <asm/hardirq.h>
 #include <asm/softirq.h>
 
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#include <asm/pbm.h>
+#endif
+
 /* Internal flag, should not be visible elsewhere at all. */
-#define SA_SYSIO_MASKED		0x100
+#define SA_IMAP_MASKED		0x100
+
+#ifdef __SMP__
+void distribute_irqs(void);
+static int irqs_have_been_distributed = 0;
+#endif
 
 /* UPA nodes send interrupt packet to UltraSparc with first data reg value
  * low 5 bits holding the IRQ identifier being delivered.  We must translate
@@ -37,10 +47,39 @@
  * make things even more swift we store the complete mask here.
  */
 
-#define NUM_IVECS	2048	/* XXX may need more on sunfire/wildfire */
+#define NUM_HARD_IVECS	2048
+#define NUM_IVECS	(NUM_HARD_IVECS + 64)	/* For SMP IRQ distribution alg. */
 
 unsigned long ivector_to_mask[NUM_IVECS];
 
+struct ino_bucket {
+	struct ino_bucket *next;
+	unsigned int ino;
+	unsigned int *imap;
+	unsigned int *iclr;
+};
+
+#define INO_HASHSZ	(NUM_HARD_IVECS >> 2)
+#define NUM_INO_STATIC	4
+static struct ino_bucket *ino_hash[INO_HASHSZ] = { NULL, };
+static struct ino_bucket static_ino_buckets[NUM_INO_STATIC];
+static int static_ino_bucket_count = 0;
+
+static inline struct ino_bucket *__ino_lookup(unsigned int hash, unsigned int ino)
+{
+	struct ino_bucket *ret = ino_hash[hash];
+
+	for(ret = ino_hash[hash]; ret && ret->ino != ino; ret = ret->next)
+		;
+
+	return ret;
+}
+
+static inline struct ino_bucket *ino_lookup(unsigned int ino)
+{
+	return __ino_lookup((ino & (INO_HASHSZ - 1)), ino);
+}
+
 /* This is based upon code in the 32-bit Sparc kernel written mostly by
  * David Redman (djhr@tadpole.co.uk).
  */
@@ -76,12 +115,12 @@
 	return len;
 }
 
-/* INO number to Sparc PIL level. */
-unsigned char ino_to_pil[] = {
-	0, 1, 2, 3, 5, 7, 8, 9,		/* SBUS slot 0 */
-	0, 1, 2, 3, 5, 7, 8, 9,		/* SBUS slot 1 */
-	0, 1, 2, 3, 5, 7, 8, 9,		/* SBUS slot 2 */
-	0, 1, 2, 3, 5, 7, 8, 9,		/* SBUS slot 3 */
+/* SBUS SYSIO INO number to Sparc PIL level. */
+unsigned char sysio_ino_to_pil[] = {
+	0, 1, 2, 7, 5, 7, 8, 9,		/* SBUS slot 0 */
+	0, 1, 2, 7, 5, 7, 8, 9,		/* SBUS slot 1 */
+	0, 1, 2, 7, 5, 7, 8, 9,		/* SBUS slot 2 */
+	0, 1, 2, 7, 5, 7, 8, 9,		/* SBUS slot 3 */
 	3, /* Onboard SCSI */
 	5, /* Onboard Ethernet */
 /*XXX*/	8, /* Onboard BPP */
@@ -112,7 +151,7 @@
  */
 #define offset(x) ((unsigned long)(&(((struct sysio_regs *)0)->x)))
 #define bogon     ((unsigned long) -1)
-static unsigned long irq_offsets[] = {
+static unsigned long sysio_irq_offsets[] = {
 /* SBUS Slot 0 --> 3, level 1 --> 7 */
 offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),
 offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),
@@ -134,29 +173,29 @@
 
 #undef bogon
 
-#define NUM_IRQ_ENTRIES (sizeof(irq_offsets) / sizeof(irq_offsets[0]))
+#define NUM_SYSIO_OFFSETS (sizeof(sysio_irq_offsets) / sizeof(sysio_irq_offsets[0]))
 
-/* Convert an "interrupts" property IRQ level to an SBUS/SYSIO
- * Interrupt Mapping register pointer, or NULL if none exists.
+/* XXX Old compatability cruft, get rid of me when all drivers have been
+ * XXX converted to dcookie registry calls... -DaveM
  */
-static unsigned int *irq_to_imap(unsigned int irq)
+static unsigned int *sysio_irq_to_imap(unsigned int irq)
 {
 	unsigned long offset;
 	struct sysio_regs *sregs;
 
 	if((irq == 14) ||
-	   (irq >= NUM_IRQ_ENTRIES) ||
-	   ((offset = irq_offsets[irq]) == ((unsigned long)-1)))
+	   (irq >= NUM_SYSIO_OFFSETS) ||
+	   ((offset = sysio_irq_offsets[irq]) == ((unsigned long)-1)))
 		return NULL;
 	sregs = SBus_chain->iommu->sysio_regs;
 	offset += ((unsigned long) sregs);
-	return ((unsigned int *)offset) + 1;
+	return ((unsigned int *)offset);
 }
 
 /* Convert Interrupt Mapping register pointer to assosciated
- * Interrupt Clear register pointer.
+ * Interrupt Clear register pointer, SYSIO specific version.
  */
-static unsigned int *imap_to_iclr(unsigned int *imap)
+static unsigned int *sysio_imap_to_iclr(unsigned int *imap)
 {
 	unsigned long diff;
 
@@ -166,32 +205,63 @@
 
 #undef offset
 
-/* For non-SBUS IRQ's we do nothing, else we must enable them in the
- * appropriate SYSIO interrupt map registers.
+#ifdef CONFIG_PCI
+/* PCI PSYCHO INO number to Sparc PIL level. */
+unsigned char psycho_ino_to_pil[] = {
+	7, 5, 5, 2,			/* PCI A slot 0  Int A, B, C, D */
+	7, 5, 5, 2,			/* PCI A slot 1  Int A, B, C, D */
+	0, 0, 0, 0,
+	0, 0, 0, 0,
+	6, 4, 3, 1,			/* PCI B slot 0  Int A, B, C, D */
+	6, 4, 3, 1,			/* PCI B slot 1  Int A, B, C, D */
+	6, 4, 3, 1,			/* PCI B slot 2  Int A, B, C, D */
+	6, 4, 3, 1,			/* PCI B slot 3  Int A, B, C, D */
+	3, /* SCSI */
+	3, /* Ethernet */
+	2, /* Parallel Port */
+	8, /* Audio Record */
+	7, /* Audio Playback */
+	8, /* PowerFail */
+	7, /* Keyboard/Mouse/Serial */
+	8, /* Floppy */
+	2, /* Spare Hardware */
+	4, /* Keyboard */
+	4, /* Mouse */
+	7, /* Serial */
+	6, /* Timer 0 */
+	6, /* Timer 1 */
+	8, /* Uncorrectable ECC */
+	8, /* Correctable ECC */
+	8, /* PCI Bus A Error */
+	7, /* PCI Bus B Error */
+	1, /* Power Management */
+};
+
+/* INO number to IMAP register offset for PSYCHO external IRQ's.
  */
-void enable_irq(unsigned int irq)
+#define psycho_offset(x) ((unsigned long)(&(((struct psycho_regs *)0)->x)))
+
+#define psycho_imap_offset(ino)							\
+	((ino & 0x20) ? (psycho_offset(imap_scsi) + (((ino) & 0x1f) << 3)) :	\
+			(psycho_offset(imap_a_slot0) + (((ino) & 0x3c) << 1)))
+
+#define psycho_iclr_offset(ino)							\
+	((ino & 0x20) ? (psycho_offset(iclr_scsi) + (((ino) & 0x1f) << 3)) :	\
+			(psycho_offset(iclr_a_slot0[0]) + (((ino) & 0x1f) << 3)))
+
+#endif
+
+/* Now these are always passed a true fully specified sun4u INO. */
+void enable_irq(unsigned int ino)
 {
+	struct ino_bucket *bucket = ino_lookup(ino);
 	unsigned long tid;
 	unsigned int *imap;
 
-	/* If this is for the tick interrupt, just ignore, note
-	 * that this is the one and only locally generated interrupt
-	 * source, all others come from external sources (essentially
-	 * any UPA device which is an interruptor).  (actually, on
-	 * second thought Ultra can generate local interrupts for
-	 * async memory errors and we may setup handlers for those
-	 * at some point as well)
-	 *
-	 * XXX See commentary below in request_irq() this assumption
-	 * XXX is broken and needs to be fixed.
-	 */
-	if(irq == 14)
+	if(!bucket)
 		return;
 
-	/* Check for bogons. */
-	imap = irq_to_imap(irq);
-	if(imap == NULL)
-		goto do_the_stb_watoosi;
+	imap = bucket->imap;
 
 	/* We send it to our UPA MID, for SMP this will be different. */
 	__asm__ __volatile__("ldxa [%%g0] %1, %0" : "=r" (tid) : "i" (ASI_UPA_CONFIG));
@@ -202,28 +272,22 @@
 	 * Register, the hardware just mirrors that value here.
 	 * However for Graphics and UPA Slave devices the full
 	 * SYSIO_IMAP_INR field can be set by the programmer here.
-	 * (XXX we will have to handle those for FFB etc. XXX)
+	 *
+	 * Things like FFB can now be handled via the dcookie mechanism.
 	 */
 	*imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
-	return;
-
-do_the_stb_watoosi:
-	printk("Cannot enable irq(%d), doing the \"STB Watoosi\" instead.", irq);
-	panic("Trying to enable bogon IRQ");
 }
 
-void disable_irq(unsigned int irq)
+/* This now gets passed true ino's as well. */
+void disable_irq(unsigned int ino)
 {
+	struct ino_bucket *bucket = ino_lookup(ino);
 	unsigned int *imap;
 
-	/* XXX Grrr, I know this is broken... */
-	if(irq == 14)
+	if(!bucket)
 		return;
 
-	/* Check for bogons. */
-	imap = irq_to_imap(irq);
-	if(imap == NULL)
-		goto do_the_stb_watoosi;
+	imap = bucket->imap;
 
 	/* NOTE: We do not want to futz with the IRQ clear registers
 	 *       and move the state to IDLE, the SCSI code does call
@@ -231,34 +295,218 @@
 	 *       SCSI adapter driver code.  Thus we'd lose interrupts.
 	 */
 	*imap &= ~(SYSIO_IMAP_VALID);
-	return;
+}
+
+static void get_irq_translations(int *cpu_irq, int *ivindex_fixup,
+				 unsigned int **imap, unsigned int **iclr,
+				 void *busp, unsigned long flags,
+				 unsigned int irq)
+{
+	if(*cpu_irq != -1 && *imap != NULL && *iclr != NULL)
+		return;
+
+	if(*cpu_irq != -1 || *imap != NULL || *iclr != NULL || busp == NULL) {
+		printk("get_irq_translations: Partial specification, this is bad.\n");
+		printk("get_irq_translations: cpu_irq[%d] imap[%p] iclr[%p] busp[%p]\n",
+		       *cpu_irq, *imap, *iclr, busp);
+		panic("Bad IRQ translations...");
+	}
+
+	if(SA_BUS(flags) == SA_SBUS) {
+		struct linux_sbus *sbusp = busp;
+		struct sysio_regs *sregs = sbusp->iommu->sysio_regs;
+		unsigned long offset;
+
+		*cpu_irq = sysio_ino_to_pil[irq];
+		if(*cpu_irq == 0) {
+			printk("get_irq_translations: Bad SYSIO INO[%x]\n", irq);
+			panic("Bad SYSIO IRQ translations...");
+		}
+		offset = sysio_irq_offsets[irq];
+		if(offset == ((unsigned long)-1)) {
+			printk("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n",
+			       irq, *cpu_irq);
+			panic("BAD SYSIO IRQ offset...");
+		}
+		offset += ((unsigned long)sregs);
+		*imap = ((unsigned int *)offset);
+
+		/* SYSIO inconsistancy.  For external SLOTS, we have to select
+		 * the right ICLR register based upon the lower SBUS irq level
+		 * bits.
+		 */
+		if(irq >= 0x20) {
+			*iclr = sysio_imap_to_iclr(*imap);
+		} else {
+			unsigned long iclraddr;
+			int sbus_slot = (irq & 0x18)>>3;
+			int sbus_level = irq & 0x7;
+
+			switch(sbus_slot) {
+			case 0:
+				*iclr = &sregs->iclr_slot0;
+				break;
+			case 1:
+				*iclr = &sregs->iclr_slot1;
+				break;
+			case 2:
+				*iclr = &sregs->iclr_slot2;
+				break;
+			case 3:
+				*iclr = &sregs->iclr_slot3;
+				break;
+			};
+
+			iclraddr = (unsigned long) *iclr;
+			iclraddr += ((sbus_level - 1) * 8);
+			*iclr = (unsigned int *) iclraddr;
+
+#if 0 /* DEBUGGING */
+			printk("SYSIO_FIXUP: slot[%x] level[%x] iclr[%p] ",
+			       sbus_slot, sbus_level, *iclr);
+#endif
 
-do_the_stb_watoosi:
-	printk("Cannot disable irq(%d), doing the \"STB Watoosi\" instead.", irq);
-	panic("Trying to enable bogon IRQ");
+			/* Also, make sure this is accounted for in ivindex
+			 * computations done by the caller.
+			 */
+			*ivindex_fixup = sbus_level;
+		}
+		return;
+	}
+#ifdef CONFIG_PCI
+	if(SA_BUS(flags) == SA_PCI) {
+		struct pci_bus *pbusp = busp;
+		struct linux_pbm_info *pbm = pbusp->sysdata;
+		struct psycho_regs *pregs = pbm->parent->psycho_regs;
+		unsigned long offset;
+
+		*cpu_irq = psycho_ino_to_pil[irq & 0x3f];
+		if(*cpu_irq == 0) {
+			printk("get_irq_translations: Bad PSYCHO INO[%x]\n", irq);
+			panic("Bad PSYCHO IRQ translations...");
+		}
+		offset = psycho_imap_offset(irq);
+		if(offset == ((unsigned long)-1)) {
+			printk("get_irq_translations: Bad PSYCHO INO[%x] cpu[%d]\n",
+			       irq, *cpu_irq);
+			panic("Bad PSYCHO IRQ offset...");
+		}
+		offset += ((unsigned long)pregs);
+		*imap = ((unsigned int *)offset) + 1;
+		*iclr = (unsigned int *)
+			(((unsigned long)pregs) + psycho_imap_offset(irq));
+		return;
+	}
+#endif
+#if 0	/* XXX More to do before we can use this. -DaveM */
+	if(SA_BUS(flags) == SA_FHC) {
+		struct fhc_bus *fbusp = busp;
+		struct fhc_regs *fregs = fbusp->regs;
+		unsigned long offset;
+
+		*cpu_irq = fhc_ino_to_pil[irq];
+		if(*cpu_irq == 0) {
+			printk("get_irq_translations: Bad FHC INO[%x]\n", irq);
+			panic("Bad FHC IRQ translations...");
+		}
+		offset = fhc_irq_offset[*cpu_irq];
+		if(offset == ((unsigned long)-1)) {
+			printk("get_irq_translations: Bad FHC INO[%x] cpu[%d]\n",
+			       irq, *cpu_irq);
+			panic("Bad FHC IRQ offset...");
+		}
+		offset += ((unsigned long)pregs);
+		*imap = (((unsigned int *)offset)+1);
+		*iclr = fhc_imap_to_iclr(*imap);
+		return;
+	}
+#endif
+	printk("get_irq_translations: IRQ register for unknown bus type.\n");
+	printk("get_irq_translations: BUS[%lx] IRQ[%x]\n",
+	       SA_BUS(flags), irq);
+	panic("Bad IRQ bus type...");
+}
+
+/* Once added, they are never removed. */
+static struct ino_bucket *add_ino_hash(unsigned int ivindex,
+				       unsigned int *imap, unsigned int *iclr,
+				       unsigned long flags)
+{
+	struct ino_bucket *new = NULL, **hashp;
+	unsigned int hash = (ivindex & (INO_HASHSZ - 1));
+
+	new = __ino_lookup(hash, ivindex);
+	if(new)
+		return new;
+	if(flags & SA_STATIC_ALLOC) {
+		if(static_ino_bucket_count < NUM_INO_STATIC)
+			new = &static_ino_buckets[static_ino_bucket_count++];
+		else
+			printk("Request for ino bucket SA_STATIC_ALLOC failed "
+			       "using kmalloc\n");
+	}
+	if(new == NULL)
+		new = kmalloc(sizeof(struct ino_bucket), GFP_KERNEL);
+	if(new) {
+		hashp = &ino_hash[hash];
+		new->imap = imap;
+		new->iclr = iclr;
+		new->ino  = ivindex;
+		new->next = *hashp;
+		*hashp = new;
+	}
+	return new;
 }
 
 int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-		unsigned long irqflags, const char *name, void *dev_cookie)
+		unsigned long irqflags, const char *name, void *dev_id)
 {
 	struct irqaction *action, *tmp = NULL;
+	struct devid_cookie *dcookie = NULL;
+	struct ino_bucket *bucket = NULL;
 	unsigned long flags;
-	unsigned int cpu_irq, *imap, *iclr;
+	unsigned int *imap, *iclr;
+	void *bus_id = NULL;
+	int ivindex, ivindex_fixup, cpu_irq = -1;
 	
-	/* XXX This really is not the way to do it, the "right way"
-	 * XXX is to have drivers set SA_SBUS or something like that
-	 * XXX in irqflags and we base our decision here on whether
-	 * XXX that flag bit is set or not.
-	 */
-	if(irq == 14)
-		cpu_irq = irq;
-	else
-		cpu_irq = ino_to_pil[irq];
-
 	if(!handler)
 	    return -EINVAL;
 
-	imap = irq_to_imap(irq);
+	imap = iclr = NULL;
+
+	ivindex_fixup = 0;
+	if(irqflags & SA_DCOOKIE) {
+		if(!dev_id) {
+			printk("request_irq: SA_DCOOKIE but dev_id is NULL!\n");
+			panic("Bogus irq registry.");
+		}
+		dcookie		= dev_id;
+		dev_id		= dcookie->real_dev_id;
+		cpu_irq		= dcookie->pil;
+		imap		= dcookie->imap;
+		iclr		= dcookie->iclr;
+		bus_id		= dcookie->bus_cookie;
+		get_irq_translations(&cpu_irq, &ivindex_fixup, &imap,
+				     &iclr, bus_id, irqflags, irq);
+	} else {
+		/* XXX NOTE: This code is maintained for compatability until I can
+		 * XXX       verify that all drivers sparc64 will use are updated
+		 * XXX       to use the new IRQ registry dcookie interface.  -DaveM
+		 */
+		if(irq == 14)
+			cpu_irq = irq;
+		else
+			cpu_irq = sysio_ino_to_pil[irq];
+		imap = sysio_irq_to_imap(irq);
+		if(!imap) {
+			printk("request_irq: BAD, null imap for old style "
+			       "irq registry IRQ[%x].\n", irq);
+			panic("Bad IRQ registery...");
+		}
+		iclr = sysio_imap_to_iclr(imap);
+	}
+	ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
+	ivindex += ivindex_fixup;
 
 	action = *(cpu_irq + irq_action);
 	if(action) {
@@ -297,52 +545,61 @@
 		return -ENOMEM;
 	}
 
-	if(imap) {
-		int ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
+	bucket = add_ino_hash(ivindex, imap, iclr, irqflags);
+	if(!bucket) {
+		kfree(action);
+		restore_flags(flags);
+		return -ENOMEM;
+	}
 
-		ivector_to_mask[ivindex] = (1<<cpu_irq);
-		iclr = imap_to_iclr(imap);
-		action->mask = (unsigned long) iclr;
-		irqflags |= SA_SYSIO_MASKED;
-	} else {
-		action->mask = 0;
+	ivector_to_mask[ivindex] = (1 << cpu_irq);
+
+	if(dcookie) {
+		dcookie->ret_ino = ivindex;
+		dcookie->ret_pil = cpu_irq;
 	}
 
+	action->mask = (unsigned long) bucket;
 	action->handler = handler;
-	action->flags = irqflags;
+	action->flags = irqflags | SA_IMAP_MASKED;
 	action->name = name;
 	action->next = NULL;
-	action->dev_id = dev_cookie;
+	action->dev_id = dev_id;
 
 	if(tmp)
 		tmp->next = action;
 	else
 		*(cpu_irq + irq_action) = action;
 
-	enable_irq(irq);
+	enable_irq(ivindex);
 	restore_flags(flags);
+#ifdef __SMP__
+	if(irqs_have_been_distributed)
+		distribute_irqs();
+#endif
 	return 0;
 }
 
-void free_irq(unsigned int irq, void *dev_cookie)
+void free_irq(unsigned int irq, void *dev_id)
 {
 	struct irqaction *action;
 	struct irqaction *tmp = NULL;
 	unsigned long flags;
 	unsigned int cpu_irq;
+	int ivindex = -1;
 
 	if(irq == 14)
 		cpu_irq = irq;
 	else
-		cpu_irq = ino_to_pil[irq];
+		cpu_irq = sysio_ino_to_pil[irq];
 	action = *(cpu_irq + irq_action);
 	if(!action->handler) {
 		printk("Freeing free IRQ %d\n", irq);
 		return;
 	}
-	if(dev_cookie) {
+	if(dev_id) {
 		for( ; action; action = action->next) {
-			if(action->dev_id == dev_cookie)
+			if(action->dev_id == dev_id)
 				break;
 			tmp = action;
 		}
@@ -351,7 +608,7 @@
 			return;
 		}
 	} else if(action->flags & SA_SHIRQ) {
-		printk("Trying to free shared IRQ %d with NULL device cookie\n", irq);
+		printk("Trying to free shared IRQ %d with NULL device ID\n", irq);
 		return;
 	}
 
@@ -367,29 +624,37 @@
 	else
 		*(cpu_irq + irq_action) = action->next;
 
-	if(action->flags & SA_SYSIO_MASKED) {
-		unsigned int *imap = irq_to_imap(irq);
-		if(imap != NULL)
-			ivector_to_mask[*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)] = 0;
+	if(action->flags & SA_IMAP_MASKED) {
+		struct ino_bucket *bucket = (struct ino_bucket *)action->mask;
+		unsigned int *imap = bucket->imap;
+
+		if(imap != NULL) {
+			ivindex = bucket->ino;
+			ivector_to_mask[ivindex] = 0;
+		}
 		else
 			printk("free_irq: WHeee, SYSIO_MASKED yet no imap reg.\n");
 	}
 
 	kfree(action);
-	if(!*(cpu_irq + irq_action))
-		disable_irq(irq);
+	if(ivindex != -1)
+		disable_irq(ivindex);
 
 	restore_flags(flags);
 }
 
-/* Per-processor IRQ locking depth, both SMP and non-SMP code use this. */
-unsigned int local_irq_count[NR_CPUS];
+/* Only uniprocessor needs this IRQ locking depth, on SMP it lives in the per-cpu
+ * structure for cache reasons.
+ */
+#ifndef __SMP__
+unsigned int local_irq_count;
+#endif
 
 #ifndef __SMP__
 int __sparc64_bh_counter = 0;
 
-#define irq_enter(cpu, irq)	(local_irq_count[cpu]++)
-#define irq_exit(cpu, irq)	(local_irq_count[cpu]--)
+#define irq_enter(cpu, irq)	(local_irq_count++)
+#define irq_exit(cpu, irq)	(local_irq_count--)
 
 #else
 
@@ -407,18 +672,31 @@
 /* Global IRQ locking depth. */
 atomic_t global_irq_count = ATOMIC_INIT(0);
 
-static inline void wait_on_irq(int cpu)
+static unsigned long previous_irqholder;
+
+#undef INIT_STUCK
+#define INIT_STUCK 100000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; }
+
+static inline void wait_on_irq(int cpu, unsigned long where)
 {
-	int local_count = local_irq_count[cpu];
+	int stuck = INIT_STUCK;
+	int local_count = local_irq_count;
 
 	while(local_count != atomic_read(&global_irq_count)) {
 		atomic_sub(local_count, &global_irq_count);
 		spin_unlock(&global_irq_lock);
 		for(;;) {
+			STUCK;
+			membar("#StoreLoad | #LoadLoad");
 			if (atomic_read(&global_irq_count))
 				continue;
-			if (*((unsigned char *)&global_irq_lock))
+			if (*((volatile unsigned char *)&global_irq_lock))
 				continue;
+			membar("#LoadLoad | #LoadStore");
 			if (spin_trylock(&global_irq_lock))
 				break;
 		}
@@ -426,25 +704,41 @@
 	}
 }
 
-static inline void get_irqlock(int cpu)
+#undef INIT_STUCK
+#define INIT_STUCK 10000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;}
+
+static inline void get_irqlock(int cpu, unsigned long where)
 {
+	int stuck = INIT_STUCK;
+
 	if (!spin_trylock(&global_irq_lock)) {
+		membar("#StoreLoad | #LoadLoad");
 		if ((unsigned char) cpu == global_irq_holder)
 			return;
 		do {
-			barrier();
+			do {
+				STUCK;
+				membar("#LoadLoad");
+			} while(*((volatile unsigned char *)&global_irq_lock));
 		} while (!spin_trylock(&global_irq_lock));
 	}
-	wait_on_irq(cpu);
+	wait_on_irq(cpu, where);
 	global_irq_holder = cpu;
+	previous_irqholder = where;
 }
 
 void __global_cli(void)
 {
 	int cpu = smp_processor_id();
+	unsigned long where;
 
+	__asm__ __volatile__("mov %%i7, %0" : "=r" (where));
 	__cli();
-	get_irqlock(cpu);
+	get_irqlock(cpu, where);
 }
 
 void __global_sti(void)
@@ -453,11 +747,6 @@
 	__sti();
 }
 
-unsigned long __global_save_flags(void)
-{
-	return global_irq_holder == (unsigned char) smp_processor_id();
-}
-
 void __global_restore_flags(unsigned long flags)
 {
 	if (flags & 1) {
@@ -472,15 +761,24 @@
 	}
 }
 
+#undef INIT_STUCK
+#define INIT_STUCK 200000000
+
+#undef STUCK
+#define STUCK \
+if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;}
+
 void irq_enter(int cpu, int irq)
 {
+	int stuck = INIT_STUCK;
+
 	hardirq_enter(cpu);
-	barrier();
-	while (*((unsigned char *)&global_irq_lock)) {
+	while (*((volatile unsigned char *)&global_irq_lock)) {
 		if ((unsigned char) cpu == global_irq_holder)
 			printk("irq_enter: Frosted Lucky Charms, "
 			       "they're magically delicious!\n");
-		barrier();
+		STUCK;
+		membar("#LoadLoad");
 	}
 }
 
@@ -492,8 +790,7 @@
 
 void synchronize_irq(void)
 {
-	int cpu = smp_processor_id();
-	int local_count = local_irq_count[cpu];
+	int local_count = local_irq_count;
 	unsigned long flags;
 
 	if (local_count != atomic_read(&global_irq_count)) {
@@ -506,8 +803,10 @@
 
 void report_spurious_ivec(struct pt_regs *regs)
 {
-	printk("IVEC: Spurious interrupt vector received at (%016lx)\n",
-	       regs->tpc);
+	extern unsigned long ivec_spurious_cookie;
+
+	printk("IVEC: Spurious interrupt vector (%016lx) received at (%016lx)\n",
+	       ivec_spurious_cookie, regs->tpc);
 	return;
 }
 
@@ -547,13 +846,20 @@
 	irq_enter(cpu, irq);
 	action = *(irq + irq_action);
 	kstat.interrupts[irq]++;
-	do {
-		if(!action || !action->handler)
-			unexpected_irq(irq, 0, regs);
-		action->handler(irq, action->dev_id, regs);
-		if(action->flags & SA_SYSIO_MASKED)
-			*((unsigned int *)action->mask) = SYSIO_ICLR_IDLE;
-	} while((action = action->next) != NULL);
+	if(!action) {
+		unexpected_irq(irq, 0, regs);
+	} else {
+		do {
+			action->handler(irq, action->dev_id, regs);
+			if(action->flags & SA_IMAP_MASKED) {
+				struct ino_bucket *bucket =
+					(struct ino_bucket *)action->mask;
+
+				*(bucket->iclr) = SYSIO_ICLR_IDLE;
+				membar("#MemIssue");
+			}
+		} while((action = action->next) != NULL);
+	}
 	irq_exit(cpu, irq);
 }
 
@@ -567,7 +873,7 @@
 
 	irq_enter(cpu, irq);
 	floppy_interrupt(irq, dev_cookie, regs);
-	if(action->flags & SA_SYSIO_MASKED)
+	if(action->flags & SA_IMAP_MASKED)
 		*((unsigned int *)action->mask) = SYSIO_ICLR_IDLE;
 	irq_exit(cpu, irq);
 }
@@ -595,7 +901,7 @@
 	insns[0] = SPARC_BRANCH(((unsigned long) handler),
 				((unsigned long)&insns[0]));
 	insns[1] = SPARC_NOP;
-	__asm__ __volatile__("flush %0" : : "r" (ttent));
+	__asm__ __volatile__("membar #StoreStore; flush %0" : : "r" (ttent));
 }
 
 int request_fast_irq(unsigned int irq,
@@ -605,6 +911,7 @@
 	struct irqaction *action;
 	unsigned long flags;
 	unsigned int cpu_irq, *imap, *iclr;
+	int ivindex = -1;
 
 	/* XXX This really is not the way to do it, the "right way"
 	 * XXX is to have drivers set SA_SBUS or something like that
@@ -616,11 +923,11 @@
 	 */
 	if(irq == 14)
 		return -EINVAL;
-	cpu_irq = ino_to_pil[irq];
+	cpu_irq = sysio_ino_to_pil[irq];
 
 	if(!handler)
 		return -EINVAL;
-	imap = irq_to_imap(irq);
+	imap = sysio_irq_to_imap(irq);
 	action = *(cpu_irq + irq_action);
 	if(action) {
 		if(action->flags & SA_SHIRQ)
@@ -648,12 +955,12 @@
 	install_fast_irq(cpu_irq, handler);
 
 	if(imap) {
-		int ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
-
+		ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO));
 		ivector_to_mask[ivindex] = (1 << cpu_irq);
-		iclr = imap_to_iclr(imap);
+		iclr = sysio_imap_to_iclr(imap);
 		action->mask = (unsigned long) iclr;
-		irqflags |= SA_SYSIO_MASKED;
+		irqflags |= SA_IMAP_MASKED;
+		add_ino_hash(ivindex, imap, iclr, irqflags);
 	} else
 		action->mask = 0;
 
@@ -665,7 +972,9 @@
 
 	*(cpu_irq + irq_action) = action;
 
-	enable_irq(irq);
+	if(ivindex != -1)
+		enable_irq(ivindex);
+
 	restore_flags(flags);
 	return 0;
 }
@@ -675,31 +984,27 @@
  */
 unsigned long probe_irq_on(void)
 {
-  return 0;
+	return 0;
 }
 
 int probe_irq_off(unsigned long mask)
 {
-  return 0;
+	return 0;
 }
 
 struct sun5_timer *linux_timers = NULL;
 
-/* This is called from sbus_init() to get the jiffies timer going.
- * We need to call this after there exists a valid SBus_chain so
- * that the IMAP/ICLR registers can be accessed.
- *
- * XXX That is because the whole startup sequence is broken.  I will
- * XXX fix it all up very soon.  -DaveM
- */
+/* This is gets the master level10 timer going. */
 void init_timers(void (*cfunc)(int, void *, struct pt_regs *))
 {
 	struct linux_prom64_registers pregs[3];
+	struct devid_cookie dcookie;
+	unsigned int *imap, *iclr;
 	u32 pirqs[2];
 	int node, err;
 
 	node = prom_finddevice("/counter-timer");
-	if(node == 0) {
+	if(node == 0 || node == -1) {
 		prom_printf("init_timers: Cannot find counter-timer PROM node.\n");
 		prom_halt();
 	}
@@ -715,13 +1020,22 @@
 		prom_halt();
 	}
 	linux_timers = (struct sun5_timer *) __va(pregs[0].phys_addr);
+	iclr = (((unsigned int *)__va(pregs[1].phys_addr))+1);
+	imap = (((unsigned int *)__va(pregs[2].phys_addr))+1);
 
 	/* Shut it up first. */
 	linux_timers->limit0 = 0;
 
 	/* Register IRQ handler. */
-	err = request_irq(pirqs[0] & 0x3f, /* XXX Fix this for big Enterprise XXX */
-			  cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL);
+	dcookie.real_dev_id = NULL;
+	dcookie.imap = imap;
+	dcookie.iclr = iclr;
+	dcookie.pil = 10;
+	dcookie.bus_cookie = NULL;
+
+	err = request_irq(pirqs[0], cfunc,
+			  (SA_DCOOKIE | SA_INTERRUPT | SA_STATIC_ALLOC),
+			  "timer", &dcookie);
 
 	if(err) {
 		prom_printf("Serious problem, cannot register timer interrupt\n");
@@ -824,6 +1138,52 @@
 	prom_timers->limit0 = prom_limit0;
 	prom_timers->count0 = 0;
 }
+
+#ifdef __SMP__
+/* Called from smp_commence, when we know how many cpus are in the system
+ * and can have device IRQ's directed at them.
+ */
+void distribute_irqs(void)
+{
+	unsigned long flags;
+	int cpu, level;
+
+	printk("SMP: redistributing interrupts...\n");
+	save_and_cli(flags);
+	cpu = 0;
+	for(level = 0; level < NR_IRQS; level++) {
+		struct irqaction *p = irq_action[level];
+
+		while(p) {
+			if(p->flags & SA_IMAP_MASKED) {
+				struct ino_bucket *bucket = (struct ino_bucket *)p->mask;
+				unsigned int *imap = bucket->imap;
+				unsigned int val;
+				unsigned long tid = linux_cpus[cpu].mid << 9;
+
+				val = *imap;
+				*imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID);
+
+				printk("SMP: Redirecting IGN[%x] INO[%x] "
+				       "to cpu %d [%s]\n",
+				       (val & SYSIO_IMAP_IGN) >> 6,
+				       (val & SYSIO_IMAP_INO), cpu,
+				       p->name);
+
+				cpu += 1;
+				while(!(cpu_present_map & (1UL << cpu))) {
+					cpu += 1;
+					if(cpu >= smp_num_cpus)
+						cpu = 0;
+				}
+			}
+			p = p->next;
+		}
+	}
+	restore_flags(flags);
+	irqs_have_been_distributed = 1;
+}
+#endif
 
 __initfunc(void init_IRQ(void))
 {
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.1.50/linux/arch/sparc64/kernel/process.c	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc64/kernel/process.c	Sat Aug 16 10:00:14 1997
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.31 1997/07/24 12:15:05 davem Exp $
+/*  $Id: process.c,v 1.29 1997/07/17 02:20:40 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -27,18 +27,21 @@
 #include <linux/a.out.h>
 #include <linux/config.h>
 #include <linux/reboot.h>
+#include <linux/delay.h>
 
 #include <asm/oplib.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#include <asm/delay.h>
 #include <asm/processor.h>
 #include <asm/pstate.h>
 #include <asm/elf.h>
 #include <asm/fpumacro.h>
 
+#define PGTCACHE_HIGH_WATER		50
+#define PGTCACHE_LOW_WATER		25
+
 #ifndef __SMP__
 
 /*
@@ -53,6 +56,16 @@
 	current->priority = -100;
 	current->counter = -100;
 	for (;;) {
+		if(pgtable_cache_size > PGTCACHE_LOW_WATER) {
+			do {
+				if(pgd_quicklist)
+					free_page((unsigned long) get_pgd_fast());
+				if(pmd_quicklist)
+					free_page((unsigned long) get_pmd_fast());
+				if(pte_quicklist)
+					free_page((unsigned long) get_pte_fast());
+			} while(pgtable_cache_size > PGTCACHE_HIGH_WATER);
+		}
 		run_task_queue(&tq_scheduler);
 		schedule();
 	}
@@ -68,13 +81,26 @@
 {
 	current->priority = -100;
 	while(1) {
+		if(pgtable_cache_size > PGTCACHE_LOW_WATER) {
+			do {
+				if(pgd_quicklist)
+					free_page((unsigned long) get_pgd_fast());
+				if(pmd_quicklist)
+					free_page((unsigned long) get_pmd_fast());
+				if(pte_quicklist)
+					free_page((unsigned long) get_pte_fast());
+			} while(pgtable_cache_size > PGTCACHE_HIGH_WATER);
+		}
 		if(tq_scheduler) {
 			lock_kernel();
 			run_task_queue(&tq_scheduler);
 			unlock_kernel();
 		}
+		barrier();
 		current->counter = -100;
-		schedule();
+		if(resched_needed())
+			schedule();
+		barrier();
 	}
 }
 
@@ -251,8 +277,20 @@
 	} while ((size -= sizeof(unsigned)));
 }
 
-void show_regs(struct pt_regs * regs)
+#ifdef __SMP__
+static spinlock_t regdump_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
+void __show_regs(struct pt_regs * regs)
 {
+#ifdef __SMP__
+	unsigned long flags;
+
+	spin_lock_irqsave(&regdump_lock, flags);
+	printk("CPU[%d]: local_irq_count[%ld] global_irq_count[%d]\n",
+	       smp_processor_id(), local_irq_count,
+	       atomic_read(&global_irq_count));
+#endif
         printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x\n", regs->tstate,
 	       regs->tpc, regs->tnpc, regs->y);
 	printk("g0: %016lx g1: %016lx g2: %016lx g3: %016lx\n",
@@ -268,6 +306,21 @@
 	       regs->u_regs[12], regs->u_regs[13], regs->u_regs[14],
 	       regs->u_regs[15]);
 	show_regwindow(regs);
+#ifdef __SMP__
+	spin_unlock_irqrestore(&regdump_lock, flags);
+#endif
+}
+
+void show_regs(struct pt_regs *regs)
+{
+	__show_regs(regs);
+#ifdef __SMP__
+	{
+		extern void smp_report_regs(void);
+
+		smp_report_regs();
+	}
+#endif
 }
 
 void show_regs32(struct pt_regs32 *regs)
@@ -337,12 +390,16 @@
 	/* Now, this task is no longer a kernel thread. */
 	current->tss.current_ds = USER_DS;
 	if(current->tss.flags & SPARC_FLAG_KTHREAD) {
+		extern spinlock_t scheduler_lock;
+
 		current->tss.flags &= ~SPARC_FLAG_KTHREAD;
 
 		/* exec_mmap() set context to NO_CONTEXT, here is
 		 * where we grab a new one.
 		 */
+		spin_lock(&scheduler_lock);
 		get_mmu_context(current);
+		spin_unlock(&scheduler_lock);
 	}
 	current->tss.ctx = current->mm->context & 0x1fff;
 	spitfire_set_secondary_context (current->tss.ctx);
@@ -437,10 +494,14 @@
 			struct reg_window *rwin = &tp->reg_window[window];
 
 			if(copy_to_user((char *)sp, rwin, winsize))
-				do_exit(SIGILL);
+				goto barf;
 		} while(window--);
 	}
 	current->tss.w_saved = 0;
+	return;
+barf:
+	lock_kernel();
+	do_exit(SIGILL);
 }
 
 /* Copy a Sparc thread.  The fork() return value conventions
@@ -483,7 +544,7 @@
 	p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8;
 #endif
 	p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window));
-	p->tss.cwp = regs->u_regs[UREG_G0];
+	p->tss.cwp = (regs->tstate + 1) & TSTATE_CWP;
 	if(regs->tstate & TSTATE_PRIV) {
 		p->tss.kregs->u_regs[UREG_FP] = p->tss.ksp;
 		p->tss.flags |= SPARC_FLAG_KTHREAD;
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/psycho.c linux/arch/sparc64/kernel/psycho.c
--- v2.1.50/linux/arch/sparc64/kernel/psycho.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/kernel/psycho.c	Sat Aug 16 09:51:09 1997
@@ -0,0 +1,668 @@
+/* $Id: psycho.c,v 1.5 1997/08/15 06:44:18 davem Exp $
+ * psycho.c: Ultra/AX U2P PCI controller support.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <asm/ebus.h>
+#include <asm/sbus.h> /* for sanity check... */
+
+#ifndef CONFIG_PCI
+
+int pcibios_present(void)
+{
+	return 0;
+}
+
+asmlinkage int sys_pciconfig_read(unsigned long bus,
+				  unsigned long dfn,
+				  unsigned long off,
+				  unsigned long len,
+				  unsigned char *buf)
+{
+	return 0;
+}
+
+asmlinkage int sys_pciconfig_write(unsigned long bus,
+				   unsigned long dfn,
+				   unsigned long off,
+				   unsigned long len,
+				   unsigned char *buf)
+{
+	return 0;
+}
+
+#else
+
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+
+#include <asm/io.h>
+#include <asm/oplib.h>
+#include <asm/pbm.h>
+#include <asm/uaccess.h>
+
+struct linux_psycho *psycho_root = NULL;
+
+/* This is used to make the scan_bus in the generic PCI code be
+ * a nop, as we need to control the actual bus probing sequence.
+ * After that we leave it on of course.
+ */
+static int pci_probe_enable = 0;
+
+static inline unsigned long long_align(unsigned long addr)
+{
+	return ((addr + (sizeof(unsigned long) - 1)) &
+		~(sizeof(unsigned long) - 1));
+}
+
+extern void prom_pbm_ranges_init(int node, struct linux_pbm_info *pbm);
+
+unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)
+{
+	struct linux_prom64_registers pr_regs[3];
+	char namebuf[128];
+	u32 portid;
+	int node;
+
+	/* prom_printf("PSYCHO: Probing for controllers.\n"); */
+	printk("PSYCHO: Probing for controllers.\n");
+
+	memory_start = long_align(memory_start);
+	node = prom_getchild(prom_root_node);
+	while((node = prom_searchsiblings(node, "pci")) != 0) {
+		struct linux_psycho *psycho = (struct linux_psycho *)memory_start;
+		struct linux_psycho *search;
+		struct linux_pbm_info *pbm = NULL;
+		u32 busrange[2];
+		int err, is_pbm_a;
+
+		portid = prom_getintdefault(node, "upa-portid", 0xff);
+		for(search = psycho_root; search; search = search->next) {
+			if(search->upa_portid == portid) {
+				psycho = search;
+
+				/* This represents _this_ instance, so it's
+				 * which ever one does _not_ have the prom node
+				 * info filled in yet.
+				 */
+				is_pbm_a = (psycho->pbm_A.prom_node == 0);
+				goto other_pbm;
+			}
+		}
+
+		memory_start = long_align(memory_start + sizeof(struct linux_psycho));
+
+		memset(psycho, 0, sizeof(*psycho));
+
+		psycho->next = psycho_root;
+		psycho_root = psycho;
+
+		psycho->upa_portid = portid;
+
+		/* Map in PSYCHO register set and report the presence of this PSYCHO. */
+		err = prom_getproperty(node, "reg",
+				       (char *)&pr_regs[0], sizeof(pr_regs));
+		if(err == 0 || err == -1) {
+			prom_printf("PSYCHO: Error, cannot get U2P registers "
+				    "from PROM.\n");
+			prom_halt();
+		}
+
+		/* Third REG in property is base of entire PSYCHO register space. */
+		psycho->psycho_regs = sparc_alloc_io((pr_regs[2].phys_addr & 0xffffffff),
+						     NULL, sizeof(struct psycho_regs),
+						     "PSYCHO Registers",
+						     (pr_regs[2].phys_addr >> 32), 0);
+		if(psycho->psycho_regs == NULL) {
+			prom_printf("PSYCHO: Error, cannot map PSYCHO "
+				    "main registers.\n");
+			prom_halt();
+		}
+
+		prom_printf("PSYCHO: Found controller, main regs at %p\n",
+			    psycho->psycho_regs);
+		printk("PSYCHO: Found controller, main regs at %p\n",
+		       psycho->psycho_regs);
+
+		/* Now map in PCI config space for entire PSYCHO. */
+		psycho->pci_config_space =
+			sparc_alloc_io(((pr_regs[2].phys_addr & 0xffffffff)+0x01000000),
+				       NULL, 0x01000000,
+				       "PCI Config Space",
+				       (pr_regs[2].phys_addr >> 32), 0);
+		if(psycho->pci_config_space == NULL) {
+			prom_printf("PSYCHO: Error, cannot map PCI config space.\n");
+			prom_halt();
+		}
+
+		/* Finally map in I/O space for both PBM's.  This is essentially
+		 * backwards compatability for non-conformant PCI cards which
+		 * do not map themselves into the PCI memory space.
+		 */
+		psycho->pbm_B.pbm_IO = __va(pr_regs[2].phys_addr + 0x02000000UL);
+		psycho->pbm_A.pbm_IO = __va(pr_regs[2].phys_addr + 0x02010000UL);
+
+		/* Now record MEM space for both PBM's.
+		 *
+		 * XXX Eddie, these can be reversed if BOOT_BUS pin is clear, is
+		 * XXX there some way to find out what value of BOOT_BUS pin is?
+		 */
+		psycho->pbm_B.pbm_mem = __va(pr_regs[2].phys_addr + 0x180000000UL);
+		psycho->pbm_A.pbm_mem = __va(pr_regs[2].phys_addr + 0x100000000UL);
+
+		/* Report some more info. */
+		prom_printf("PSYCHO: PCI config space at %p\n",
+			    psycho->pci_config_space);
+		prom_printf("PSYCHO: PBM A I/O space at %p, PBM B I/O at %p\n",
+			    psycho->pbm_A.pbm_IO, psycho->pbm_B.pbm_IO);
+		prom_printf("PSYCHO: PBM A MEM at %p, PBM B MEM at %p\n");
+
+		printk("PSYCHO: PCI config space at %p\n", psycho->pci_config_space);
+		printk("PSYCHO: PBM A I/O space at %p, PBM B I/O at %p\n",
+		       psycho->pbm_A.pbm_IO, psycho->pbm_B.pbm_IO);
+
+		is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
+
+	other_pbm:
+		if(is_pbm_a)
+			pbm = &psycho->pbm_A;
+		else
+			pbm = &psycho->pbm_B;
+
+		pbm->parent = psycho;
+		pbm->prom_node = node;
+
+		prom_getstring(node, "name", namebuf, sizeof(namebuf));
+		strcpy(pbm->prom_name, namebuf);
+
+		/* Now the ranges. */
+		prom_pbm_ranges_init(node, pbm);
+
+		/* Finally grab the pci bus root array for this pbm after
+		 * having found the bus range existing under it.
+		 */
+		err = prom_getproperty(node, "bus-range",
+				       (char *)&busrange[0], sizeof(busrange));
+		if(err == 0 || err == -1) {
+			prom_printf("PSYCHO: Error, cannot get PCI bus range.\n");
+			prom_halt();
+		}
+		pbm->pci_first_busno = busrange[0];
+		pbm->pci_last_busno = busrange[1];
+		memset(&pbm->pci_bus, 0, sizeof(struct pci_bus));
+
+		node = prom_getsibling(node);
+		if(!node)
+			break;
+	}
+
+	/* Last minute sanity check. */
+	if(psycho_root == NULL && SBus_chain == NULL) {
+		prom_printf("Fatal error, neither SBUS nor PCI bus found.\n");
+		prom_halt();
+	}
+
+	return memory_start;
+}
+
+int pcibios_present(void)
+{
+	return psycho_root != NULL;
+}
+
+int pcibios_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;
+}
+
+int pcibios_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;
+}
+
+static void pbm_probe(struct linux_pbm_info *pbm, unsigned long *mstart)
+{
+	struct pci_bus *pbus = &pbm->pci_bus;
+
+	/* PSYCHO PBM's include child PCI bridges in bus-range property,
+	 * but we don't scan each of those ourselves, Linux generic PCI
+	 * probing code will find child bridges and link them into this
+	 * pbm's root PCI device hierarchy.
+	 */
+	pbus->number = pbm->pci_first_busno;
+	pbus->sysdata = pbm;
+	pbus->subordinate = pci_scan_bus(pbus, mstart);
+}
+
+static void fill_in_pbm_cookies(struct linux_pbm_info *pbm)
+{
+	struct pci_bus *pbtmp, *pbus = &pbm->pci_bus;
+	struct pci_dev *pdev;
+
+	for(pbtmp = pbus->children; pbtmp; pbtmp = pbtmp->children)
+		pbtmp->sysdata = pbm;
+
+	for( ; pbus; pbus = pbus->children)
+		for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
+			pdev->sysdata = pbm;
+}
+
+static void fixup_pci_dev(struct pci_dev *pdev,
+			  struct pci_bus *pbus,
+			  struct linux_pbm_info *pbm)
+{
+	struct linux_prom_pci_registers pregs[PROMREG_MAX];
+	int node;
+#if 0
+	int nregs, busno = pbus->number;
+#endif
+
+	node = prom_getchild(pbm->prom_node);
+	while(node) {
+		u32 devfn;
+		int err, nregs;
+
+		err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs));
+		if(err == 0 || err == -1) {
+			prom_printf("fixup_pci_dev: No PCI device reg property?!?!\n");
+			prom_halt();
+		}
+		nregs = (err / sizeof(struct linux_prom_pci_registers));
+
+		devfn = (pregs[0].phys_hi >> 8) & 0xff;
+		if(devfn == pdev->devfn) {
+
+			return;
+		}
+
+		node = prom_getsibling(node);
+	}
+
+	prom_printf("fixup_pci_dev: Cannot find prom node for PCI device\n");
+	prom_halt();
+}
+
+static void fixup_pci_bus(struct pci_bus *pbus, struct linux_pbm_info *pbm)
+{
+	struct pci_dev *pdev;
+
+	for(pdev = pbus->devices; pdev; pdev = pdev->sibling)
+		fixup_pci_dev(pdev, pbus, pbm);
+
+	for(pbus = pbus->children; pbus; pbus = pbus->children)
+		fixup_pci_bus(pbus, pbm);
+}
+
+static void fixup_addr_irq(struct linux_pbm_info *pbm)
+{
+	struct pci_bus *pbus = &pbm->pci_bus;
+
+	/* Work through top level devices (not bridges, those and their
+	 * devices are handled specially in the next loop).
+	 */
+	fixup_pci_bus(pbus, pbm);
+}
+
+/* Walk all PCI devices probes, fixing up base registers and IRQ registers.
+ * We use OBP for most of this work.
+ */
+static void psycho_final_fixup(struct linux_psycho *psycho)
+{
+	/* First, walk all PCI devices found.  For each device, and
+	 * PCI bridge which is not one of the PSYCHO PBM's, fill in the
+	 * sysdata with a pointer to the PBM.
+	 */
+	fill_in_pbm_cookies(&psycho->pbm_A);
+	fill_in_pbm_cookies(&psycho->pbm_B);
+
+	/* Second, fixup base address registers and IRQ lines... */
+	fixup_addr_irq(&psycho->pbm_A);
+	fixup_addr_irq(&psycho->pbm_B);
+}
+
+unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end)
+{
+	struct linux_psycho *psycho = psycho_root;
+
+	pci_probe_enable = 1;
+
+	/* XXX Really this should be per-PSYCHO, but the config space
+	 * XXX reads and writes give us no way to know which PSYCHO
+	 * XXX in which the config space reads should occur.
+	 * XXX
+	 * XXX Further thought says that we cannot change this generic
+	 * XXX interface, else we'd break xfree86 and other parts of the
+	 * XXX kernel (but whats more important is breaking userland for
+	 * XXX the ix86/Alpha/etc. people).  So we should define our own
+	 * XXX internal extension initially, we can compile our own user
+	 * XXX apps that need to get at PCI configuration space.
+	 */
+
+	/* Probe busses under PBM A. */
+	pbm_probe(&psycho->pbm_A, &memory_start);
+
+	/* Probe busses under PBM B. */
+	pbm_probe(&psycho->pbm_B, &memory_start);
+
+
+	psycho_final_fixup(psycho);
+
+	return ebus_init(memory_start, memory_end);
+}
+
+/* "PCI: The emerging standard..." 8-( */
+volatile int pci_poke_in_progress = 0;
+volatile int pci_poke_faulted = 0;
+
+/* XXX Current PCI support code is broken, it assumes one master PCI config
+ * XXX space exists, on Ultra we can have many of them, especially with
+ * XXX 'dual-pci' boards on Sunfire/Starfire/Wildfire.
+ */
+static char *pci_mkaddr(unsigned char bus, unsigned char device_fn,
+			unsigned char where)
+{
+	unsigned long ret = (unsigned long) psycho_root->pci_config_space;
+
+	ret |= (1 << 24);
+	ret |= ((bus & 0xff) << 16);
+	ret |= ((device_fn & 0xff) << 8);
+	ret |= (where & 0xfc);
+	return (unsigned char *)ret;
+}
+
+static inline int out_of_range(unsigned char bus, unsigned char device_fn)
+{
+	return ((bus == 0 && PCI_SLOT(device_fn) > 4) ||
+		(bus == 1 && PCI_SLOT(device_fn) > 6) ||
+		(pci_probe_enable == 0));
+}
+
+int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn,
+			      unsigned char where, unsigned char *value)
+{
+	unsigned char *addr = pci_mkaddr(bus, device_fn, where);
+	unsigned int word, trapped;
+
+	*value = 0xff;
+
+	if(out_of_range(bus, device_fn))
+		return PCIBIOS_SUCCESSFUL;
+
+	pci_poke_in_progress = 1;
+	pci_poke_faulted = 0;
+	__asm__ __volatile__("membar #Sync\n\t"
+			     "lduwa [%1] %2, %0\n\t"
+			     "membar #Sync"
+			     : "=r" (word)
+			     : "r" (addr), "i" (ASI_PL));
+	pci_poke_in_progress = 0;
+	trapped = pci_poke_faulted;
+	pci_poke_faulted = 0;
+	if(!trapped) {
+		switch(where & 3) {
+		case 0:
+			*value = word & 0xff;
+			break;
+		case 1:
+			*value = (word >> 8) & 0xff;
+			break;
+		case 2:
+			*value = (word >> 16) & 0xff;
+			break;
+		case 3:
+			*value = (word >> 24) & 0xff;
+			break;
+		};
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_word (unsigned char bus, unsigned char device_fn,
+			      unsigned char where, unsigned short *value)
+{
+	unsigned short *addr = (unsigned short *)pci_mkaddr(bus, device_fn, where);
+	unsigned int word, trapped;
+
+	*value = 0xffff;
+
+	if(out_of_range(bus, device_fn))
+		return PCIBIOS_SUCCESSFUL;
+
+	/* XXX Check no-probe-list conflicts here. XXX */
+
+	pci_poke_in_progress = 1;
+	pci_poke_faulted = 0;
+	__asm__ __volatile__("membar #Sync\n\t"
+			     "lduwa [%1] %2, %0\n\t"
+			     "membar #Sync"
+			     : "=r" (word)
+			     : "r" (addr), "i" (ASI_PL));
+	pci_poke_in_progress = 0;
+	trapped = pci_poke_faulted;
+	pci_poke_faulted = 0;
+	if(!trapped) {
+		switch(where & 3) {
+		case 0:
+			*value = word & 0xffff;
+			break;
+		case 2:
+			*value = (word >> 16) & 0xffff;
+			break;
+		default:
+			prom_printf("pcibios_read_config_word: misaligned "
+				    "reg [%x]\n", where);
+			prom_halt();
+		};
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
+			       unsigned char where, unsigned int *value)
+{
+	unsigned int *addr = (unsigned int *)pci_mkaddr(bus, device_fn, where);
+	unsigned int word, trapped;
+
+	*value = 0xffffffff;
+
+	if(out_of_range(bus, device_fn))
+		return PCIBIOS_SUCCESSFUL;
+
+	/* XXX Check no-probe-list conflicts here. XXX */
+
+	pci_poke_in_progress = 1;
+	pci_poke_faulted = 0;
+	__asm__ __volatile__("membar #Sync\n\t"
+			     "lduwa [%1] %2, %0\n\t"
+			     "membar #Sync"
+			     : "=r" (word)
+			     : "r" (addr), "i" (ASI_PL));
+	pci_poke_in_progress = 0;
+	trapped = pci_poke_faulted;
+	pci_poke_faulted = 0;
+	if(!trapped)
+		*value = word;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn,
+			       unsigned char where, unsigned char value)
+{
+	unsigned char *addr = pci_mkaddr(bus, device_fn, where);
+
+	if(out_of_range(bus, device_fn))
+		return PCIBIOS_SUCCESSFUL;
+
+	/* XXX Check no-probe-list conflicts here. XXX */
+
+	pci_poke_in_progress = 1;
+
+	/* Endianness doesn't matter but we have to get the memory
+	 * barriers in there so...
+	 */
+	__asm__ __volatile__("membar #Sync\n\t"
+			     "stba %0, [%1] %2\n\t"
+			     "membar #Sync\n\t"
+			     : /* no outputs */
+			     : "r" (value), "r" (addr), "i" (ASI_PL));
+	pci_poke_in_progress = 0;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_word (unsigned char bus, unsigned char device_fn,
+			       unsigned char where, unsigned short value)
+{
+	unsigned short *addr = (unsigned short *)pci_mkaddr(bus, device_fn, where);
+
+	if(out_of_range(bus, device_fn))
+		return PCIBIOS_SUCCESSFUL;
+
+	/* XXX Check no-probe-list conflicts here. XXX */
+
+	pci_poke_in_progress = 1;
+	__asm__ __volatile__("membar #Sync\n\t"
+			     "stha %0, [%1] %2\n\t"
+			     "membar #Sync\n\t"
+			     : /* no outputs */
+			     : "r" (value), "r" (addr), "i" (ASI_PL));
+	pci_poke_in_progress = 0;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
+				unsigned char where, unsigned int value)
+{
+	unsigned int *addr = (unsigned int *)pci_mkaddr(bus, device_fn, where);
+
+	if(out_of_range(bus, device_fn))
+		return PCIBIOS_SUCCESSFUL;
+
+	/* XXX Check no-probe-list conflicts here. XXX */
+
+	pci_poke_in_progress = 1;
+	__asm__ __volatile__("membar #Sync\n\t"
+			     "stwa %0, [%1] %2\n\t"
+			     "membar #Sync"
+			     : /* no outputs */
+			     : "r" (value), "r" (addr), "i" (ASI_PL));
+	pci_poke_in_progress = 0;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+asmlinkage int sys_pciconfig_read(unsigned long bus,
+				  unsigned long dfn,
+				  unsigned long off,
+				  unsigned long len,
+				  unsigned char *buf)
+{
+	unsigned char ubyte;
+	unsigned short ushort;
+	unsigned int uint;
+	int err = 0;
+
+	lock_kernel();
+	switch(len) {
+	case 1:
+		pcibios_read_config_byte(bus, dfn, off, &ubyte);
+		put_user(ubyte, buf);
+		break;
+	case 2:
+		pcibios_read_config_word(bus, dfn, off, &ushort);
+		put_user(ushort, buf);
+		break;
+	case 4:
+		pcibios_read_config_dword(bus, dfn, off, &uint);
+		put_user(uint, buf);
+		break;
+
+	default:
+		err = -EINVAL;
+		break;
+	};
+	unlock_kernel();
+
+	return err;
+}
+
+asmlinkage int sys_pciconfig_write(unsigned long bus,
+				   unsigned long dfn,
+				   unsigned long off,
+				   unsigned long len,
+				   unsigned char *buf)
+{
+	unsigned char ubyte;
+	unsigned short ushort;
+	unsigned int uint;
+	int err = 0;
+
+	lock_kernel();
+	switch(len) {
+	case 1:
+		err = get_user(ubyte, (unsigned char *)buf);
+		if(err)
+			break;
+		pcibios_write_config_byte(bus, dfn, off, ubyte);
+		break;
+
+	case 2:
+		err = get_user(ushort, (unsigned short *)buf);
+		if(err)
+			break;
+		pcibios_write_config_byte(bus, dfn, off, ushort);
+		break;
+
+	case 4:
+		err = get_user(uint, (unsigned int *)buf);
+		if(err)
+			break;
+		pcibios_write_config_byte(bus, dfn, off, uint);
+		break;
+
+	default:
+		err = -EINVAL;
+		break;
+
+	};
+	unlock_kernel();
+
+	return err;
+}
+
+#endif
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c
--- v2.1.50/linux/arch/sparc64/kernel/ptrace.c	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/kernel/ptrace.c	Sat Aug 16 09:51:09 1997
@@ -609,10 +609,6 @@
 		unsigned long tmp;
 		int res;
 
-#if 0
-		/* XXX Find out what is really going on. */
-		flush_cache_all();
-#endif
 		/* Non-word alignment _not_ allowed on Sparc. */
 		if (current->tss.flags & SPARC_FLAG_32BIT) {
 			unsigned int x;
@@ -1055,7 +1051,7 @@
 	current->exit_code = SIGTRAP;
 	current->state = TASK_STOPPED;
 	current->tss.flags ^= MAGIC_CONSTANT;
-	notify_parent(current);
+	notify_parent(current, SIGCHLD);
 	schedule();
 	/*
 	 * this isn't the same as continuing with a signal, but it will do
@@ -1067,9 +1063,9 @@
 		current->pid, current->exit_code);
 #endif
 	if (current->exit_code) {
-		/* spin_lock_irq(&current->sigmask_lock); */
+		spin_lock_irq(&current->sigmask_lock);
 		current->signal |= (1 << (current->exit_code - 1));
-		/* spin_unlock_irq(&current->sigmask_lock); */
+		spin_unlock_irq(&current->sigmask_lock);
 	}
 
 	current->exit_code = 0;
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S
--- v2.1.50/linux/arch/sparc64/kernel/rtrap.S	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/rtrap.S	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.28 1997/06/30 10:31:39 jj Exp $
+/* $Id: rtrap.S,v 1.30 1997/08/10 04:49:33 davem Exp $
  * rtrap.S: Preparing for return from trap on Sparc V9.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -21,58 +21,60 @@
 		sethi			%hi(bh_mask), %l1
 		ldx			[%l2 + %lo(bh_active)], %l4
 		ldx			[%l1 + %lo(bh_mask)], %l7
-
 		andcc			%l4, %l7, %g0
 		be,pt			%xcc, 2f
+
 		 nop
 		call			do_bottom_half
 		 nop
 2:		ldx			[%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
 		sethi			%hi(0xf << 20), %l4
 		andcc			%l1, TSTATE_PRIV, %l3
-
 		and			%l1, %l4, %l4
 		rdpr			%pstate, %l7
+
 		andn			%l1, %l4, %l1
 		be,pt			%icc, to_user
 		 andn			%l7, PSTATE_IE, %l7
 rt_continue:	ld			[%sp + PTREGS_OFF + PT_V9_FPRS], %l2
 		ld			[%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
 		ldx			[%sp + PTREGS_OFF + PT_V9_G1], %g1
-
 		brnz,pn			%l2, rt_fpu_restore
 		 ldx			[%sp + PTREGS_OFF + PT_V9_G2], %g2
+
 rt_after_fpu:	ldx			[%sp + PTREGS_OFF + PT_V9_G3], %g3
 		mov			%g6, %l6
 		ldx			[%sp + PTREGS_OFF + PT_V9_G4], %g4
 		ldx			[%sp + PTREGS_OFF + PT_V9_G5], %g5
 		ldx			[%sp + PTREGS_OFF + PT_V9_G6], %g6
 		ldx			[%sp + PTREGS_OFF + PT_V9_G7], %g7
-
 		wrpr			%l7, PSTATE_AG, %pstate
 		ldx			[%sp + PTREGS_OFF + PT_V9_I0], %i0
+
 		ldx			[%sp + PTREGS_OFF + PT_V9_I1], %i1
 		ldx			[%sp + PTREGS_OFF + PT_V9_I2], %i2
 		ldx			[%sp + PTREGS_OFF + PT_V9_I3], %i3
 		ldx			[%sp + PTREGS_OFF + PT_V9_I4], %i4
 		ldx			[%sp + PTREGS_OFF + PT_V9_I5], %i5
 		ldx			[%sp + PTREGS_OFF + PT_V9_I6], %i6
-
 		ldx			[%sp + PTREGS_OFF + PT_V9_I7], %i7
 		ld			[%sp + PTREGS_OFF + PT_V9_Y], %o3
+
 		ldx			[%sp + PTREGS_OFF + PT_V9_TPC], %l2
 		ldx			[%sp + PTREGS_OFF + PT_V9_TNPC], %o2
 		wr			%o3, %g0, %y
 		srl			%l4, 20, %l4
 		wrpr			%l4, 0x0, %pil
 		wrpr			%g0, 0x1, %tl
-
 		wrpr			%l1, %g0, %tstate
 		wrpr			%l2, %g0, %tpc
-		mov			PRIMARY_CONTEXT, %l7
+
+		wr			%g0, ASI_DMMU, %asi
 		brnz,pn			%l3, kern_rtt
 		 wrpr			%o2, %g0, %tnpc
-		stxa			%l0, [%l7] ASI_DMMU
+		stxa			%l0, [%g0 + SECONDARY_CONTEXT] %asi
+		flush			%l6
+		stxa			%l0, [%g0 + PRIMARY_CONTEXT] %asi
 		flush			%l6
 		rdpr			%wstate, %l1
 
@@ -88,47 +90,54 @@
 		retry
 kern_rtt:	restore
 		retry
-to_user:	sethi			%hi(need_resched), %l0
-		ld			[%l0 + %lo(need_resched)], %l0
+to_user:	lduw			[%g6 + AOFF_task_processor], %o0
+		mov			1, %o1
+		sethi			%hi(need_resched), %l0
+		ldx			[%l0 + %lo(need_resched)], %l0
+		sllx			%o1, %o0, %o1
+
 		wrpr			%l7, PSTATE_IE, %pstate
-		brz,pt			%l0, check_signal
+		andcc			%o1, %l0, %g0
+		be,pt			%xcc, check_signal
 		 ldx			[%g6 + AOFF_task_signal], %l0
-
 		call			schedule
 		 nop
 		ldx			[%g6 + AOFF_task_signal], %l0
 		nop
+
 check_signal:	ldx			[%g6 + AOFF_task_blocked], %o0
 		andncc			%l0, %o0, %g0
 		be,pt			%xcc, check_user_wins
 		 ldx			[%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
-
 		mov			%l5, %o2  
 		mov			%l6, %o3
 		call			do_signal
 		 add			%sp, STACK_BIAS + REGWIN_SZ, %o1
+
 		ldx			[%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
 		clr			%l6
-check_user_wins:
-		brz,pt			%o2, rt_continue
+check_user_wins:brz,pt			%o2, rt_continue
 		 nop
-
 		call			fault_in_user_windows
 		 add			%sp, STACK_BIAS + REGWIN_SZ, %o0
 		ba,a,pt			%xcc, rt_continue
 rt_fpu_restore:	wr			%g0, FPRS_FEF, %fprs
+
 		add			%sp, PTREGS_OFF + TRACEREG_SZ, %g4
 		wr			%g0, ASI_BLK_P, %asi
-
 		membar			#StoreLoad | #LoadLoad
 		ldda			[%g4 + 0x000] %asi, %f0
 		ldda			[%g4 + 0x040] %asi, %f16
 		ldda			[%g4 + 0x080] %asi, %f32
 		ldda			[%g4 + 0x0c0] %asi, %f48
 		ldx			[%g4 + 0x100], %fsr
+
 		ldx			[%g4 + 0x108], %g3
 		membar			#Sync
-
 		b,pt			%xcc, rt_after_fpu
 		 wr			%g3, 0, %gsr
+		nop
+		nop
+		nop
+		nop
 #undef PTREGS_OFF
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c
--- v2.1.50/linux/arch/sparc64/kernel/signal.c	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/kernel/signal.c	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.20 1997/07/14 03:10:28 davem Exp $
+/*  $Id: signal.c,v 1.22 1997/08/05 19:19:36 davem Exp $
  *  arch/sparc64/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -54,12 +54,12 @@
 	if(tp->w_saved						||
 	   (((unsigned long)ucp) & (sizeof(unsigned long)-1))	||
 	   (!__access_ok((unsigned long)ucp, sizeof(*ucp))))
-		do_exit(SIGSEGV);
+		goto do_sigsegv;
 	grp = &ucp->uc_mcontext.mc_gregs;
 	__get_user(pc, &((*grp)[MC_PC]));
 	__get_user(npc, &((*grp)[MC_NPC]));
 	if((pc | npc) & 3)
-		do_exit(SIGSEGV);
+		goto do_sigsegv;
 	if(regs->u_regs[UREG_I1]) {
 		__get_user(current->blocked, &ucp->uc_sigmask);
 		current->blocked &= _BLOCKABLE;
@@ -100,6 +100,10 @@
 		__get_user(fpregs[33], &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr));
 		regs->fprs = FPRS_FEF;
 	}
+	return;
+do_sigsegv:
+	lock_kernel();
+	do_exit(SIGSEGV);
 }
 
 asmlinkage void sparc64_get_context(struct pt_regs *regs)
@@ -113,7 +117,7 @@
 
 	synchronize_user_stack();
 	if(tp->w_saved || clear_user(ucp, sizeof(*ucp)))
-		do_exit(SIGSEGV);
+		goto do_sigsegv;
 	mcp = &ucp->uc_mcontext;
 	grp = &mcp->mc_gregs;
 
@@ -156,6 +160,10 @@
 		__put_user(fpregs[33], &(mcp->mc_fpregs.mcfpu_gsr));
 		__put_user(FPRS_FEF, &(mcp->mc_fpregs.mcfpu_fprs));
 	}
+	return;
+do_sigsegv:
+	lock_kernel();
+	do_exit(SIGSEGV);
 }
 
 /* 
@@ -452,7 +460,7 @@
 		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
 			current->exit_code = signr;
 			current->state = TASK_STOPPED;
-			notify_parent(current);
+			notify_parent(current, SIGCHLD);
 			schedule();
 			if (!(signr = current->exit_code))
 				continue;
@@ -498,7 +506,7 @@
 				current->exit_code = signr;
 				if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
 				     SA_NOCLDSTOP))
-					notify_parent(current);
+					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
 
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c
--- v2.1.50/linux/arch/sparc64/kernel/signal32.c	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/kernel/signal32.c	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/*  $Id: signal32.c,v 1.26 1997/07/14 03:10:31 davem Exp $
+/*  $Id: signal32.c,v 1.28 1997/08/05 19:19:40 davem Exp $
  *  arch/sparc64/kernel/signal32.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -555,6 +555,7 @@
 	synchronize_user_stack();
 	if (current->tss.w_saved){
 		printk ("Uh oh, w_saved is not zero (%ld)\n", current->tss.w_saved);
+		lock_kernel();
 		do_exit (SIGSEGV);
 	}
 	if(clear_user(uc, sizeof (*uc)))
@@ -718,7 +719,7 @@
 		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
 			current->exit_code = signr;
 			current->state = TASK_STOPPED;
-			notify_parent(current);
+			notify_parent(current, SIGCHLD);
 			schedule();
 			if (!(signr = current->exit_code))
 				continue;
@@ -764,7 +765,7 @@
 				current->exit_code = signr;
 				if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
 				     SA_NOCLDSTOP))
-					notify_parent(current);
+					notify_parent(current, SIGCHLD);
 				schedule();
 				continue;
 
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- v2.1.50/linux/arch/sparc64/kernel/smp.c	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc64/kernel/smp.c	Sat Aug 16 09:51:09 1997
@@ -10,11 +10,12 @@
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
+#include <linux/delay.h>
 
+#include <asm/head.h>
 #include <asm/ptrace.h>
 #include <asm/atomic.h>
 
-#include <asm/delay.h>
 #include <asm/irq.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -33,9 +34,9 @@
 unsigned long cpu_present_map = 0;
 int smp_num_cpus = 1;
 int smp_threads_ready = 0;
-volatile unsigned long cpu_callin_map[NR_CPUS] = {0,};
 
-struct cpuinfo_sparc cpu_data[NR_CPUS];
+struct cpuinfo_sparc cpu_data[NR_CPUS] __attribute__ ((aligned (64)));
+
 static unsigned char boot_cpu_id = 0;
 static int smp_activated = 0;
 
@@ -44,8 +45,6 @@
 
 struct klock_info klock_info = { KLOCK_CLEAR, 0 };
 
-static volatile int smp_commenced = 0;
-
 void smp_setup(char *str, int *ints)
 {
 	/* XXX implement me XXX */
@@ -68,45 +67,64 @@
 
 void smp_store_cpu_info(int id)
 {
-	cpu_data[id].udelay_val = loops_per_sec;
+	cpu_data[id].udelay_val			= loops_per_sec;
+	cpu_data[id].irq_count			= 0;
+	cpu_data[id].last_tlbversion_seen	= tlb_context_cache & CTX_VERSION_MASK;
+	cpu_data[id].pgcache_size		= 0;
+	cpu_data[id].pgd_cache			= NULL;
+	cpu_data[id].pmd_cache			= NULL;
+	cpu_data[id].pte_cache			= NULL;
 }
 
+extern void distribute_irqs(void);
+
 void smp_commence(void)
 {
-	flush_cache_all();
-	flush_tlb_all();
-	smp_commenced = 1;
-	flush_cache_all();
-	flush_tlb_all();
+	distribute_irqs();
 }
 
 static void smp_setup_percpu_timer(void);
 
 static volatile unsigned long callin_flag = 0;
 
+extern void inherit_locked_prom_mappings(int save_p);
+extern void cpu_probe(void);
+
 void smp_callin(void)
 {
 	int cpuid = hard_smp_processor_id();
 
-	flush_cache_all();
-	flush_tlb_all();
+	inherit_locked_prom_mappings(0);
+
+	__flush_cache_all();
+	__flush_tlb_all();
+
+	cpu_probe();
+
+	/* Master did this already, now is the time for us to do it. */
+	__asm__ __volatile__("
+	sethi	%%hi(0x80000000), %%g1
+	sllx	%%g1, 32, %%g1
+	rd	%%tick, %%g2
+	add	%%g2, 6, %%g2
+	andn	%%g2, %%g1, %%g2
+	wrpr	%%g2, 0, %%tick
+"	: /* no outputs */
+	: /* no inputs */
+	: "g1", "g2");
 
 	smp_setup_percpu_timer();
 
+	__sti();
+
 	calibrate_delay();
 	smp_store_cpu_info(cpuid);
 	callin_flag = 1;
 	__asm__ __volatile__("membar #Sync\n\t"
 			     "flush  %%g6" : : : "memory");
 
-	while(!task[cpuid])
-		barrier();
-	current = task[cpuid];
-
-	while(!smp_commenced)
-		barrier();
-
-	__sti();
+	while(!smp_processors_ready)
+		membar("#LoadLoad");
 }
 
 extern int cpu_idle(void *unused);
@@ -130,18 +148,22 @@
 	panic("SMP bolixed\n");
 }
 
+static void smp_tickoffset_init(void);
+
 extern struct prom_cpuinfo linux_cpus[NR_CPUS];
-extern unsigned long sparc64_cpu_startup;
+
+extern unsigned long smp_trampoline;
 
 void smp_boot_cpus(void)
 {
 	int cpucount = 0, i;
 
 	printk("Entering UltraSMPenguin Mode...\n");
+	smp_tickoffset_init();
 	__sti();
 	cpu_present_map = 0;
 	for(i = 0; i < linux_num_cpus; i++)
-		cpu_present_map |= (1 << i);
+		cpu_present_map |= (1UL << i);
 	for(i = 0; i < NR_CPUS; i++) {
 		cpu_number_map[i] = -1;
 		cpu_logical_map[i] = -1;
@@ -160,23 +182,24 @@
 		if(i == boot_cpu_id)
 			continue;
 
-		if(cpu_present_map & (1 << i)) {
+		if(cpu_present_map & (1UL << i)) {
+			unsigned long entry = (unsigned long)(&smp_trampoline);
 			struct task_struct *p;
 			int timeout;
 
+			entry -= KERNBASE;
 			kernel_thread(start_secondary, NULL, CLONE_PID);
 			p = task[++cpucount];
 			p->processor = i;
+			callin_flag = 0;
 			prom_startcpu(linux_cpus[i].prom_node,
-				      ((unsigned long)&sparc64_cpu_startup),
-				      ((unsigned long)p));
+				      entry, ((unsigned long)p));
 			for(timeout = 0; timeout < 5000000; timeout++) {
-				if(cpu_callin_map[i])
+				if(callin_flag)
 					break;
 				udelay(100);
 			}
-			if(cpu_callin_map[i]) {
-				/* XXX fix this */
+			if(callin_flag) {
 				cpu_number_map[i] = i;
 				cpu_logical_map[i] = i;
 			} else {
@@ -184,19 +207,19 @@
 				printk("Processor %d is stuck.\n", i);
 			}
 		}
-		if(!(cpu_callin_map[i])) {
-			cpu_present_map &= ~(1 << i);
+		if(!callin_flag) {
+			cpu_present_map &= ~(1UL << i);
 			cpu_number_map[i] = -1;
 		}
 	}
 	if(cpucount == 0) {
 		printk("Error: only one processor found.\n");
-		cpu_present_map = (1 << smp_processor_id());
+		cpu_present_map = (1UL << smp_processor_id());
 	} else {
 		unsigned long bogosum = 0;
 
 		for(i = 0; i < NR_CPUS; i++) {
-			if(cpu_present_map & (1 << i))
+			if(cpu_present_map & (1UL << i))
 				bogosum += cpu_data[i].udelay_val;
 		}
 		printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
@@ -207,27 +230,39 @@
 		smp_num_cpus = cpucount + 1;
 	}
 	smp_processors_ready = 1;
+	membar("#StoreStore | #StoreLoad");
 }
 
-/* XXX deprecated interface... */
+/* We don't even need to do anything, the only generic message pass done
+ * anymore is to stop all cpus during a panic().  When the user drops to
+ * the PROM prompt, the firmware will send the other cpu's it's MONDO
+ * vector anyways, so doing anything special here is pointless.
+ *
+ * This whole thing should go away anyways...
+ */
 void smp_message_pass(int target, int msg, unsigned long data, int wait)
 {
-	printk("smp_message_pass() called, this is bad, spinning.\n");
-	__sti();
-	while(1)
-		barrier();
 }
 
+/* #define XCALL_DEBUG */
+
 static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, int cpu)
 {
-	u64 result, target = (cpu_number_map[cpu] << 14) | 0x70;
+	u64 result, target = (((unsigned long)linux_cpus[cpu].mid) << 14) | 0x70;
+	int stuck;
 
+#ifdef XCALL_DEBUG
+	printk("CPU[%d]: xcall(data[%016lx:%016lx:%016lx],tgt[%016lx])\n",
+	       smp_processor_id(), data0, data1, data2, target);
+#endif
+again:
 	__asm__ __volatile__("
 	wrpr	%0, %1, %%pstate
 	wr	%%g0, %2, %%asi
 	stxa	%3, [0x40] %%asi
 	stxa	%4, [0x50] %%asi
 	stxa	%5, [0x60] %%asi
+	membar	#Sync
 	stxa	%%g0, [%6] %%asi
 	membar	#Sync"
 	: /* No outputs */
@@ -235,27 +270,46 @@
 	  "r" (data0), "r" (data1), "r" (data2), "r" (target));
 
 	/* NOTE: PSTATE_IE is still clear. */
+	stuck = 100000;
 	do {
 		__asm__ __volatile__("ldxa [%%g0] %1, %0"
 			: "=r" (result)
 			: "i" (ASI_INTR_DISPATCH_STAT));
+		if(result == 0) {
+			__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
+					     : : "r" (pstate));
+			return;
+		}
+		stuck -= 1;
+		if(stuck == 0)
+			break;
 	} while(result & 0x1);
 	__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
 			     : : "r" (pstate));
-	if(result & 0x2)
-		panic("Penguin NACK's master!");
+	if(stuck == 0) {
+#ifdef XCALL_DEBUG
+		printk("CPU[%d]: mondo stuckage result[%016lx]\n",
+		       smp_processor_id(), result);
+#endif
+	} else {
+#ifdef XCALL_DEBUG
+		printk("CPU[%d]: Penguin %d NACK's master.\n", smp_processor_id(), cpu);
+#endif
+		udelay(2);
+		goto again;
+	}
 }
 
 void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2)
 {
 	if(smp_processors_ready) {
-		unsigned long mask = (cpu_present_map & ~(1<<smp_processor_id()));
+		unsigned long mask = (cpu_present_map & ~(1UL<<smp_processor_id()));
 		u64 pstate, data0 = (((u64)ctx)<<32 | (((u64)func) & 0xffffffff));
 		int i, ncpus = smp_num_cpus;
 
 		__asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate));
 		for(i = 0; i < ncpus; i++) {
-			if(mask & (1 << i))
+			if(mask & (1UL << i))
 				xcall_deliver(data0, data1, data2, pstate, i);
 		}
 		/* NOTE: Caller runs local copy on master. */
@@ -266,7 +320,14 @@
 extern unsigned long xcall_flush_tlb_mm;
 extern unsigned long xcall_flush_tlb_range;
 extern unsigned long xcall_flush_tlb_all;
+extern unsigned long xcall_tlbcachesync;
 extern unsigned long xcall_flush_cache_all;
+extern unsigned long xcall_report_regs;
+
+void smp_report_regs(void)
+{
+	smp_cross_call(&xcall_report_regs, 0, 0, 0);
+}
 
 void smp_flush_cache_all(void)
 {
@@ -280,11 +341,33 @@
 	__flush_tlb_all();
 }
 
+static void smp_cross_call_avoidance(struct mm_struct *mm)
+{
+	spin_lock(&scheduler_lock);
+	get_new_mmu_context(mm, &tlb_context_cache);
+	mm->cpu_vm_mask = (1UL << smp_processor_id());
+	if(current->tss.current_ds) {
+		u32 ctx = mm->context & 0x1fff;
+
+		current->tss.ctx = ctx;
+		spitfire_set_secondary_context(ctx);
+		__asm__ __volatile__("flush %g6");
+	}
+	spin_unlock(&scheduler_lock);
+}
+
 void smp_flush_tlb_mm(struct mm_struct *mm)
 {
 	u32 ctx = mm->context & 0x1fff;
-	if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
-		smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
+
+	if(mm == current->mm && mm->count == 1) {
+		if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+			goto local_flush_and_out;
+		return smp_cross_call_avoidance(mm);
+	}
+	smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0);
+
+local_flush_and_out:
 	__flush_tlb_mm(ctx);
 }
 
@@ -292,22 +375,98 @@
 			 unsigned long end)
 {
 	u32 ctx = mm->context & 0x1fff;
-	if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
-		smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
+
+	if(mm == current->mm && mm->count == 1) {
+		if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+			goto local_flush_and_out;
+		return smp_cross_call_avoidance(mm);
+	}
+	smp_cross_call(&xcall_flush_tlb_range, ctx, start, end);
+
+local_flush_and_out:
 	__flush_tlb_range(ctx, start, end);
 }
 
-void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page)
 {
-	struct mm_struct *mm = vma->vm_mm;
 	u32 ctx = mm->context & 0x1fff;
 
-	if(mm->cpu_vm_mask != (1UL << smp_processor_id()))
-		smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
+	if(mm == current->mm && mm->count == 1) {
+		if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+			goto local_flush_and_out;
+		return smp_cross_call_avoidance(mm);
+	} else if(mm != current->mm && mm->count == 1) {
+		/* Try to handle two special cases to avoid cross calls
+		 * in common scenerios where we are swapping process
+		 * pages out.
+		 */
+		if((mm->context ^ tlb_context_cache) & CTX_VERSION_MASK)
+			return; /* It's dead, nothing to do. */
+		if(mm->cpu_vm_mask == (1UL << smp_processor_id()))
+			goto local_flush_and_out;
+	}
+	smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0);
+
+local_flush_and_out:
 	__flush_tlb_page(ctx, page);
 }
 
-static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED;
+/* CPU capture. */
+#define CAPTURE_DEBUG
+extern unsigned long xcall_capture;
+
+static atomic_t smp_capture_depth = ATOMIC_INIT(0);
+static atomic_t smp_capture_registry = ATOMIC_INIT(0);
+static unsigned long penguins_are_doing_time = 0;
+
+void smp_capture(void)
+{
+	int result = atomic_add_return(1, &smp_capture_depth);
+
+	membar("#StoreStore | #LoadStore");
+	if(result == 1) {
+		int ncpus = smp_num_cpus;
+
+#ifdef CAPTURE_DEBUG
+		printk("CPU[%d]: Sending penguins to jail...", smp_processor_id());
+#endif
+		penguins_are_doing_time = 1;
+		membar("#StoreStore | #LoadStore");
+		atomic_inc(&smp_capture_registry);
+		smp_cross_call(&xcall_capture, 0, 0, 0);
+		while(atomic_read(&smp_capture_registry) != ncpus)
+			membar("#LoadLoad");
+#ifdef CAPTURE_DEBUG
+		printk("done\n");
+#endif
+	}
+}
+
+void smp_release(void)
+{
+	if(atomic_dec_and_test(&smp_capture_depth)) {
+#ifdef CAPTURE_DEBUG
+		printk("CPU[%d]: Giving pardon to imprisoned penguins\n",
+		       smp_processor_id());
+#endif
+		penguins_are_doing_time = 0;
+		membar("#StoreStore | #StoreLoad");
+		atomic_dec(&smp_capture_registry);
+	}
+}
+
+/* Imprisoned penguins run with %pil == 15, but PSTATE_IE set, so they
+ * can service tlb flush xcalls...
+ */
+void smp_penguin_jailcell(void)
+{
+	flushw_user();
+	atomic_inc(&smp_capture_registry);
+	membar("#StoreLoad | #StoreStore");
+	while(penguins_are_doing_time)
+		membar("#LoadLoad");
+	atomic_dec(&smp_capture_registry);
+}
 
 static inline void sparc64_do_profile(unsigned long pc)
 {
@@ -317,59 +476,100 @@
 		pc -= (unsigned long) &_stext;
 		pc >>= prof_shift;
 
-		spin_lock(&ticker_lock);
-		if(pc < prof_len)
-			prof_buffer[pc]++;
-		else
-			prof_buffer[prof_len - 1]++;
-		spin_unlock(&ticker_lock);
+		if(pc >= prof_len)
+			pc = prof_len - 1;
+		atomic_inc((atomic_t *)&prof_buffer[pc]);
 	}
 }
 
-unsigned int prof_multiplier[NR_CPUS];
-unsigned int prof_counter[NR_CPUS];
+static unsigned long real_tick_offset, current_tick_offset;
+
+#define prof_multiplier(__cpu)		cpu_data[(__cpu)].multiplier
+#define prof_counter(__cpu)		cpu_data[(__cpu)].counter
 
 extern void update_one_process(struct task_struct *p, unsigned long ticks,
 			       unsigned long user, unsigned long system);
 
 void smp_percpu_timer_interrupt(struct pt_regs *regs)
 {
+	unsigned long compare, tick;
 	int cpu = smp_processor_id();
 	int user = user_mode(regs);
 
-	/* XXX clear_profile_irq(cpu); */
-	if(!user)
-		sparc64_do_profile(regs->tpc);
-	if(!--prof_counter[cpu]) {
-		if(current->pid) {
-			update_one_process(current, 1, user, !user);
-			if(--current->counter < 0) {
-				current->counter = 0;
-				need_resched = 1;
-			}
-
-			spin_lock(&ticker_lock);
-			if(user) {
-				if(current->priority < DEF_PRIORITY)
-					kstat.cpu_nice++;
-				else
-					kstat.cpu_user++;
-			} else {
-				kstat.cpu_system++;
+	clear_softint((1UL << 0));
+	do {
+		if(!user)
+			sparc64_do_profile(regs->tpc);
+		if(!--prof_counter(cpu)) {
+			if(current->pid) {
+				unsigned int *inc_me;
+
+				update_one_process(current, 1, user, !user);
+				if(--current->counter < 0) {
+					current->counter = 0;
+					resched_force();
+				}
+
+				if(user) {
+					if(current->priority < DEF_PRIORITY)
+						inc_me = &kstat.cpu_nice;
+					else
+						inc_me = &kstat.cpu_user;
+				} else {
+					inc_me = &kstat.cpu_system;
+				}
+				atomic_inc((atomic_t *)inc_me);
 			}
-			spin_unlock(&ticker_lock);
+			prof_counter(cpu) = prof_multiplier(cpu);
 		}
-		prof_counter[cpu] = prof_multiplier[cpu];
-	}
+		__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"
+				     "add	%0, %2, %0\n\t"
+				     "wr	%0, 0x0, %%tick_cmpr\n\t"
+				     "rd	%%tick, %1"
+				     : "=&r" (compare), "=r" (tick)
+				     : "r" (current_tick_offset));
+	} while (tick >= compare);
 }
 
 static void smp_setup_percpu_timer(void)
 {
-	/* XXX implement me */
+	int cpu = smp_processor_id();
+
+	prof_counter(cpu) = prof_multiplier(cpu) = 1;
+
+	__asm__ __volatile__("rd	%%tick, %%g1\n\t"
+			     "add	%%g1, %0, %%g1\n\t"
+			     "wr	%%g1, 0x0, %%tick_cmpr"
+			     : /* no outputs */
+			     : "r" (current_tick_offset)
+			     : "g1");
+}
+
+static void smp_tickoffset_init(void)
+{
+	int node;
+
+	node = linux_cpus[0].prom_node;
+	real_tick_offset = prom_getint(node, "clock-frequency");
+	real_tick_offset = real_tick_offset / HZ;
+	current_tick_offset = real_tick_offset;
 }
 
 int setup_profiling_timer(unsigned int multiplier)
 {
-	/* XXX implement me */
+	unsigned long flags;
+	int i;
+
+	if((!multiplier) || (real_tick_offset / multiplier) < 1000)
+		return -EINVAL;
+
+	save_and_cli(flags);
+	for(i = 0; i < NR_CPUS; i++) {
+		if(cpu_present_map & (1UL << i))
+			prof_multiplier(i) = multiplier;
+	}
+	current_tick_offset = (real_tick_offset / multiplier);
+	restore_flags(flags);
+
 	return 0;
 }
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- v2.1.50/linux/arch/sparc64/kernel/sparc64_ksyms.c	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.11 1997/07/14 23:58:20 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.17 1997/08/10 01:51:01 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -49,7 +49,8 @@
 extern void *__memscan_generic(void *, int, size_t);
 extern int __memcmp(const void *, const void *, __kernel_size_t);
 extern int __strncmp(const char *, const char *, __kernel_size_t);
-extern unsigned int __csum_partial_copy_sparc_generic (const char *, char *);
+extern unsigned int csum_partial_copy_sparc64(const char *src, char *dst,
+					      int len, unsigned int sum);
 extern char saved_command_line[];
 
 extern void bcopy (const char *, char *, int);
@@ -57,6 +58,10 @@
 
 extern void dump_thread(struct pt_regs *, struct user *);
 
+#ifdef __SMP__
+extern spinlock_t scheduler_lock;
+#endif
+
 /* One thing to note is that the way the symbols of the mul/div
  * support routines are named is a mess, they all start with
  * a '.' which makes it a bitch to export, here is the trick:
@@ -70,7 +75,17 @@
 
 /* used by various drivers */
 #ifdef __SMP__
+EXPORT_SYMBOL(scheduler_lock);
+EXPORT_SYMBOL(global_bh_lock);
 EXPORT_SYMBOL(klock_info);
+EXPORT_SYMBOL(global_irq_holder);
+EXPORT_SYMBOL(synchronize_irq);
+EXPORT_SYMBOL(cpu_data);
+EXPORT_SYMBOL_PRIVATE(global_cli);
+EXPORT_SYMBOL_PRIVATE(global_sti);
+EXPORT_SYMBOL_PRIVATE(global_restore_flags);
+#else
+EXPORT_SYMBOL(local_irq_count);
 #endif
 EXPORT_SYMBOL_PRIVATE(_lock_kernel);
 EXPORT_SYMBOL_PRIVATE(_unlock_kernel);
@@ -81,12 +96,13 @@
 EXPORT_SYMBOL(request_fast_irq);
 EXPORT_SYMBOL(sparc_alloc_io);
 EXPORT_SYMBOL(sparc_free_io);
-EXPORT_SYMBOL(local_irq_count);
 EXPORT_SYMBOL(__sparc64_bh_counter);
 EXPORT_SYMBOL(sparc_ultra_unmapioaddr);
 EXPORT_SYMBOL(mmu_get_scsi_sgl);
 EXPORT_SYMBOL(mmu_get_scsi_one);
 EXPORT_SYMBOL(sparc_dvma_malloc);
+EXPORT_SYMBOL(mmu_release_scsi_one);
+EXPORT_SYMBOL(mmu_release_scsi_sgl);
 #if CONFIG_SBUS
 EXPORT_SYMBOL(SBus_chain);
 EXPORT_SYMBOL(dma_chain);
@@ -150,7 +166,7 @@
 EXPORT_SYMBOL(__strncmp);
 EXPORT_SYMBOL(__memmove);
 
-EXPORT_SYMBOL(__csum_partial_copy_sparc_generic);
+EXPORT_SYMBOL(csum_partial_copy_sparc64);
 
 /* Moving data to/from userspace. */
 EXPORT_SYMBOL(__copy_to_user);
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/sys_sparc.c linux/arch/sparc64/kernel/sys_sparc.c
--- v2.1.50/linux/arch/sparc64/kernel/sys_sparc.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/sys_sparc.c	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc.c,v 1.2 1997/07/05 09:52:34 davem Exp $
+/* $Id: sys_sparc.c,v 1.3 1997/07/29 09:35:10 davem Exp $
  * linux/arch/sparc64/kernel/sys_sparc.c
  *
  * This file contains various random system calls that
@@ -220,46 +220,36 @@
 sparc_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction)
 {
 	struct sigaction new_sa, *p;
-	int err = -EINVAL;
 
-	lock_kernel();
 	if(signum < 0) {
 		current->tss.new_signal = 1;
 		signum = -signum;
 	}
-
 	if (signum<1 || signum>32)
-		goto out;
+		return -EINVAL;
 	p = signum - 1 + current->sig->action;
 	if (action) {
-		err = -EINVAL;
 		if (signum==SIGKILL || signum==SIGSTOP)
-			goto out;
-		err = -EFAULT;
+			return -EINVAL;
 		if(copy_from_user(&new_sa, action, sizeof(struct sigaction)))
-			goto out;	
+			return -EFAULT;
 		if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) {
-			err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
+			int err = verify_area(VERIFY_READ, new_sa.sa_handler, 1);
 			if (err)
-				goto out;
+				return err;
 		}
 	}
-
 	if (oldaction) {
-		err = -EFAULT;
 		if (copy_to_user(oldaction, p, sizeof(struct sigaction)))
-			goto out;	
+			return -EFAULT;
 	}
-
 	if (action) {
+		spin_lock_irq(&current->sig->siglock);
 		*p = new_sa;
 		check_pending(signum);
+		spin_unlock_irq(&current->sig->siglock);
 	}
-
-	err = 0;
-out:
-	unlock_kernel();
-	return err;
+	return 0;
 }
 
 /* only AP+ systems have sys_aplib */
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.1.50/linux/arch/sparc64/kernel/sys_sparc32.c	Sun Jul 27 12:11:00 1997
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Sat Aug 16 10:00:20 1997
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.44 1997/07/20 09:18:47 davem Exp $
+/* $Id: sys_sparc32.c,v 1.43 1997/07/17 02:20:45 davem Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -87,10 +87,11 @@
 
 void putname32(char * name)
 {
-	if (name_page_cache32 == 0)
-		name_page_cache32 = (unsigned long) name;
-	else
-		free_page((unsigned long) name);
+	unsigned long page;
+
+	page = xchg(&name_page_cache32, ((unsigned long)name));
+	if(page)
+		free_page(page);
 }
 
 int getname32(u32 filename, char **result)
@@ -98,8 +99,7 @@
 	unsigned long page;
 	int retval;
 
-	page = name_page_cache32;
-	name_page_cache32 = 0;
+	page = xchg(&name_page_cache32, NULL);
 	if (!page) {
 		page = __get_free_page(GFP_KERNEL);
 		if (!page)
@@ -1010,7 +1010,7 @@
 	lock_kernel ();
 	p = (char *)__get_free_page (GFP_KERNEL);
 	if (!p)
-		goto out;
+		goto out_nofree;
 
 	q = (u32 *)p;
 	Inp = (u32 *)A(inp);
@@ -1079,6 +1079,7 @@
 	}
 out:
 	free_page ((unsigned long)p);
+out_nofree:
 	unlock_kernel();
 	return ret;
 }
@@ -2110,54 +2111,45 @@
 {
 	struct sigaction32 new_sa, old_sa;
 	struct sigaction *p;
-	int err = -EINVAL;
 
-	lock_kernel();
 	if(signum < 0) {
 		current->tss.new_signal = 1;
 		signum = -signum;
 	}
-
 	if (signum<1 || signum>32)
-		goto out;
+		return -EINVAL;
 	p = signum - 1 + current->sig->action;
 	if (action) {
-		err = -EINVAL;
 		if (signum==SIGKILL || signum==SIGSTOP)
-			goto out;
-		err = -EFAULT;
+			return -EINVAL;
 		if(copy_from_user(&new_sa, A(action), sizeof(struct sigaction32)))
-			goto out;
+			return -EFAULT;
 		if (((__sighandler_t)A(new_sa.sa_handler)) != SIG_DFL && 
 		    ((__sighandler_t)A(new_sa.sa_handler)) != SIG_IGN) {
-			err = verify_area(VERIFY_READ, (__sighandler_t)A(new_sa.sa_handler), 1);
+			int err = verify_area(VERIFY_READ,
+					      (__sighandler_t)A(new_sa.sa_handler), 1);
 			if (err)
-				goto out;
+				return err;
 		}
 	}
-
 	if (oldaction) {
-		err = -EFAULT;
 		old_sa.sa_handler = (unsigned)(u64)(p->sa_handler);
 		old_sa.sa_mask = (sigset_t32)(p->sa_mask);
 		old_sa.sa_flags = (unsigned)(p->sa_flags);
 		old_sa.sa_restorer = (unsigned)(u64)(p->sa_restorer);
 		if (copy_to_user(A(oldaction), &old_sa, sizeof(struct sigaction32)))
-			goto out;	
+			return -EFAULT;
 	}
-
 	if (action) {
+		spin_lock_irq(&current->sig->siglock);
 		p->sa_handler = (__sighandler_t)A(new_sa.sa_handler);
 		p->sa_mask = (sigset_t)(new_sa.sa_mask);
 		p->sa_flags = new_sa.sa_flags;
 		p->sa_restorer = (void (*)(void))A(new_sa.sa_restorer);
 		check_pending(signum);
+		spin_unlock_irq(&current->sig->siglock);
 	}
-
-	err = 0;
-out:
-	unlock_kernel();
-	return err;
+	return 0;
 }
 
 /*
@@ -2298,7 +2290,7 @@
                 base = 1;
 
 	lock_kernel();
-        filename = getname((char *)(unsigned long)(u32)regs->u_regs[base + UREG_I0]);
+        filename = getname((char *)A((u32)regs->u_regs[base + UREG_I0]));
 	error = PTR_ERR(filename);
         if(IS_ERR(filename))
                 goto out;
@@ -2720,9 +2712,7 @@
 	return 0;
 }
 
-extern asmlinkage int sys_nfsservctl(int cmd,
-				     struct nfsctl_arg *arg,
-				     union nfsctl_res *resp);
+extern asmlinkage int sys_nfsservctl(int cmd, void *arg, void *resp);
 
 int asmlinkage sys32_nfsservctl(int cmd, u32 u_argp, u32 u_resp)
 {
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S
--- v2.1.50/linux/arch/sparc64/kernel/systbls.S	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/systbls.S	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.21 1997/07/05 07:09:17 davem Exp $
+/* $Id: systbls.S,v 1.23 1997/08/09 18:33:17 jj Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -10,213 +10,214 @@
  * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
  */
 
-	.data
-	.align	8
+	.text
+	.align	1024
 
 	/* First, the 32-bit Linux native syscall table. */
 
 	.globl sys_call_table32
 sys_call_table32:
-/*0*/	.xword sys_setup, sys_exit, sys_fork, sys32_read, sys32_write
-/*5*/	.xword sys32_open, sys_close, sys32_wait4, sys32_creat, sys32_link
-/*10*/  .xword sys32_unlink, sunos_execv, sys32_chdir, sys_nis_syscall, sys32_mknod
-/*15*/	.xword sys32_chmod, sys32_chown, sparc32_brk, sys_nis_syscall, sys32_lseek
-/*20*/	.xword sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
-/*25*/	.xword sys32_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
-/*30*/	.xword sys32_utime, sys_stty, sys_gtty, sys32_access, sys_nice
-	.xword sys_ftime, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall
-/*40*/	.xword sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_profil
-	.xword sys_nis_syscall, sys_setgid, sys_getgid, sys32_signal, sys_geteuid
-/*50*/	.xword sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl
-	.xword sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys32_execve
-/*60*/	.xword sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize
-	.xword sys32_msync, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*70*/	.xword sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect
-	.xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups
-/*80*/	.xword sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall
-	.xword sys32_swapon, sys32_getitimer, sys_nis_syscall, sys32_sethostname, sys_nis_syscall
-/*90*/	.xword sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall
-	.xword sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*100*/	.xword sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*110*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-	.xword sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall
-/*120*/	.xword sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod
-	.xword sys_nis_syscall, sys32_setreuid, sys_setregid, sys32_rename, sys32_truncate
-/*130*/	.xword sys32_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-	.xword sys_nis_syscall, sys32_mkdir, sys32_rmdir, sys_nis_syscall, sys_nis_syscall
-/*140*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
-	.xword sys32_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*150*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-	.xword sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys32_umount
-/*160*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_setdomainname, sys_nis_syscall
-	.xword sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall
-/*170*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
-	.xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
-	.xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname
-/*190*/	.xword sys32_init_module, sys32_personality, sys_prof, sys_break, sys_lock
-	.xword sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask
-/*200*/	.xword sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir
-	.xword sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall
-/*210*/	.xword sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo
-	.xword sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
-/*220*/	.xword sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid
-	.xword sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
-/*230*/	.xword sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall
-	.xword sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall
-/*240*/	.xword sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall
-	.xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
-/*250*/	.xword sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
-	.xword sys_aplib, sys_nis_syscall
+/*0*/	.word sys_setup, sys_exit, sys_fork, sys32_read, sys32_write
+/*5*/	.word sys32_open, sys_close, sys32_wait4, sys32_creat, sys32_link
+/*10*/  .word sys32_unlink, sunos_execv, sys32_chdir, sys_nis_syscall, sys32_mknod
+/*15*/	.word sys32_chmod, sys32_chown, sparc32_brk, sys_nis_syscall, sys32_lseek
+/*20*/	.word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
+/*25*/	.word sys32_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
+/*30*/	.word sys32_utime, sys_stty, sys_gtty, sys32_access, sys_nice
+	.word sys_ftime, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall
+/*40*/	.word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_profil
+	.word sys_nis_syscall, sys_setgid, sys_getgid, sys32_signal, sys_geteuid
+/*50*/	.word sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl
+	.word sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys32_execve
+/*60*/	.word sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize
+	.word sys32_msync, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*70*/	.word sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect
+	.word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups
+/*80*/	.word sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall
+	.word sys32_swapon, sys32_getitimer, sys_nis_syscall, sys32_sethostname, sys_nis_syscall
+/*90*/	.word sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall
+	.word sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*100*/	.word sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*110*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+	.word sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall
+/*120*/	.word sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod
+	.word sys_nis_syscall, sys32_setreuid, sys_setregid, sys32_rename, sys32_truncate
+/*130*/	.word sys32_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+	.word sys_nis_syscall, sys32_mkdir, sys32_rmdir, sys_nis_syscall, sys_nis_syscall
+/*140*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
+	.word sys32_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*150*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+	.word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys32_umount
+/*160*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_setdomainname, sys_nis_syscall
+	.word sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall
+/*170*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
+	.word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*180*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module
+	.word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname
+/*190*/	.word sys32_init_module, sys32_personality, sys_prof, sys_break, sys_lock
+	.word sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask
+/*200*/	.word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir
+	.word sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall
+/*210*/	.word sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo
+	.word sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
+/*220*/	.word sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid
+	.word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
+/*230*/	.word sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall
+	.word sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall
+/*240*/	.word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall
+	.word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
+/*250*/	.word sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
+	.word sys_aplib
 
 	/* Now the 64-bit native Linux syscall table. */
 
+	.align	1024
 	.globl sys_call_table64, sys_call_table
 sys_call_table64:
 sys_call_table:
-/*0*/	.xword sys_setup, sys_exit, sys_fork, sys_read, sys_write
-/*5*/	.xword sys_open, sys_close, sys_wait4, sys_creat, sys_link
-/*10*/  .xword sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
-/*15*/	.xword sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek
-/*20*/	.xword sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
-/*25*/	.xword sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
-/*30*/	.xword sys_utime, sys_stty, sys_gtty, sys_access, sys_nice
-	.xword sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall
-/*40*/	.xword sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil
-	.xword sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
-/*50*/	.xword sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
-	.xword sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
-/*60*/	.xword sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
-	.xword sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*70*/	.xword sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
-	.xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups
-/*80*/	.xword sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall
-	.xword sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
-/*90*/	.xword sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
-	.xword sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
-/*100*/	.xword sys_getpriority, sys_send, sys_recv, sys_nis_syscall, sys_bind
-	.xword sys_setsockopt, sys_listen, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*110*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg
-	.xword sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_nis_syscall
-/*120*/	.xword sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
-	.xword sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
-/*130*/	.xword sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown
-	.xword sys_socketpair, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall
-/*140*/	.xword sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
-	.xword sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*150*/	.xword sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-	.xword sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount
-/*160*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall
-	.xword sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
-/*170*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
-	.xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
-	.xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
-/*190*/	.xword sys_init_module, sys_personality, sys_prof, sys_break, sys_lock
-	.xword sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask
-/*200*/	.xword sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall
-	.xword sys_nis_syscall, sys_nis_syscall, sys_syslog, sys_nis_syscall, sys_nis_syscall
-/*210*/	.xword sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
-	.xword sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
-/*220*/	.xword sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
-	.xword sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
-/*230*/	.xword sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
-	.xword sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
-/*240*/	.xword sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall
-	.xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
-/*250*/	.xword sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
-	.xword sys_aplib, sys_nis_syscall
+/*0*/	.word sys_setup, sys_exit, sys_fork, sys_read, sys_write
+/*5*/	.word sys_open, sys_close, sys_wait4, sys_creat, sys_link
+/*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod
+/*15*/	.word sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek
+/*20*/	.word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid
+/*25*/	.word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause
+/*30*/	.word sys_utime, sys_stty, sys_gtty, sys_access, sys_nice
+	.word sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall
+/*40*/	.word sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil
+	.word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid
+/*50*/	.word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
+	.word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve
+/*60*/	.word sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize
+	.word sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*70*/	.word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
+	.word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups
+/*80*/	.word sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall
+	.word sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
+/*90*/	.word sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
+	.word sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
+/*100*/	.word sys_getpriority, sys_send, sys_recv, sys_nis_syscall, sys_bind
+	.word sys_setsockopt, sys_listen, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*110*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg
+	.word sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_nis_syscall
+/*120*/	.word sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
+	.word sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate
+/*130*/	.word sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown
+	.word sys_socketpair, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall
+/*140*/	.word sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
+	.word sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*150*/	.word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+	.word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount
+/*160*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall
+	.word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
+/*170*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
+	.word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*180*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
+	.word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
+/*190*/	.word sys_init_module, sys_personality, sys_prof, sys_break, sys_lock
+	.word sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask
+/*200*/	.word sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall
+	.word sys_nis_syscall, sys_nis_syscall, sys_syslog, sys_nis_syscall, sys_nis_syscall
+/*210*/	.word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
+	.word sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
+/*220*/	.word sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
+	.word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
+/*230*/	.word sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
+	.word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
+/*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall
+	.word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
+/*250*/	.word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
+	.word sys_aplib
 
 	/* Now the 32-bit SunOS syscall table. */
 
-	.align 8
+	.align 1024
 	.globl sunos_sys_table
 sunos_sys_table:
-/*0*/	.xword sunos_indir, sys_exit, sys_fork
-	.xword sunos_read, sunos_write, sunos_open
-	.xword sys_close, sunos_wait4, sys32_creat
-	.xword sys32_link, sys32_unlink, sunos_execv
-	.xword sys32_chdir, sunos_nosys, sys32_mknod
-	.xword sys32_chmod, sys32_chown, sunos_brk
-	.xword sunos_nosys, sys32_lseek, sunos_getpid
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_getuid, sunos_nosys, sys_ptrace
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sys32_access, sunos_nosys, sunos_nosys
-	.xword sys_sync, sys_kill, sys32_newstat
-	.xword sunos_nosys, sys32_newlstat, sys_dup
-	.xword sys_pipe, sunos_nosys, sys_profil
-	.xword sunos_nosys, sunos_nosys, sunos_getgid
-	.xword sunos_nosys, sunos_nosys
-/*50*/	.xword sunos_nosys, sys32_acct, sunos_nosys
-	.xword sunos_mctl, sunos_ioctl, sys32_reboot
-	.xword sunos_nosys, sys32_symlink, sys32_readlink
-	.xword sys32_execve, sys_umask, sys32_chroot
-	.xword sys32_newfstat, sunos_nosys, sys_getpagesize
-	.xword sys32_msync, sys_vfork, sunos_nosys
-	.xword sunos_nosys, sunos_sbrk, sunos_sstk
-	.xword sunos_mmap, sunos_vadvise, sys32_munmap
-	.xword sys32_mprotect, sunos_madvise, sys_vhangup
-	.xword sunos_nosys, sunos_mincore, sys32_getgroups
-	.xword sys32_setgroups, sys_getpgrp, sunos_setpgrp
-	.xword sys32_setitimer, sunos_nosys, sys32_swapon
-	.xword sys32_getitimer, sys32_gethostname, sys32_sethostname
-	.xword sunos_getdtablesize, sys_dup2, sunos_nop
-	.xword sys32_fcntl, sunos_select, sunos_nop
-	.xword sys_fsync, sys_setpriority, sys_socket
-	.xword sys32_connect, sunos_accept
-/*100*/	.xword sys_getpriority, sunos_send, sunos_recv
-	.xword sunos_nosys, sys32_bind, sunos_setsockopt
-	.xword sys_listen, sunos_nosys, sunos_sigaction
-	.xword sunos_sigblock, sunos_sigsetmask, sys_sigpause
-	.xword sys32_sigstack, sys32_recvmsg, sys32_sendmsg
-	.xword sunos_nosys, sys_gettimeofday, sys32_getrusage
-	.xword sunos_getsockopt, sunos_nosys, sunos_readv
-	.xword sunos_writev, sys_settimeofday, sys_fchown
-	.xword sys_fchmod, sys32_recvfrom, sys32_setreuid
-	.xword sys_setregid, sys32_rename, sys32_truncate
-	.xword sys32_ftruncate, sys_flock, sunos_nosys
-	.xword sys32_sendto, sys_shutdown, sys_socketpair
-	.xword sys32_mkdir, sys32_rmdir, sys32_utimes
-	.xword sys_sigreturn, sunos_nosys, sys32_getpeername
-	.xword sunos_gethostid, sunos_nosys, sys32_getrlimit
-	.xword sys32_setrlimit, sunos_killpg, sunos_nosys
-	.xword sunos_nosys, sunos_nosys
-/*150*/	.xword sys32_getsockname, sunos_nosys, sunos_nosys
-	.xword sys32_poll, sunos_nosys, sunos_nosys
-	.xword sunos_getdirentries, sys32_statfs, sys32_fstatfs
-	.xword sys32_umount, sunos_nosys, sunos_nosys
-	.xword sunos_getdomainname, sys32_setdomainname
-	.xword sunos_nosys, sys32_quotactl, sunos_nosys
-	.xword sunos_mount, sys32_ustat, sunos_semsys
-	.xword sunos_nosys, sunos_shmsys, sunos_audit
-	.xword sunos_nosys, sunos_getdents, sys_setsid
-	.xword sys_fchdir, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sys32_sigpending, sunos_nosys
-	.xword sys_setpgid, sunos_pathconf, sunos_fpathconf
-	.xword sunos_sysconf, sunos_uname, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-/*200*/	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys
-/*250*/	.xword sunos_nosys, sunos_nosys, sunos_nosys
-	.xword sunos_nosys, sunos_nosys, sys_aplib
+/*0*/	.word sunos_indir, sys_exit, sys_fork
+	.word sunos_read, sunos_write, sunos_open
+	.word sys_close, sunos_wait4, sys32_creat
+	.word sys32_link, sys32_unlink, sunos_execv
+	.word sys32_chdir, sunos_nosys, sys32_mknod
+	.word sys32_chmod, sys32_chown, sunos_brk
+	.word sunos_nosys, sys32_lseek, sunos_getpid
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_getuid, sunos_nosys, sys_ptrace
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sys32_access, sunos_nosys, sunos_nosys
+	.word sys_sync, sys_kill, sys32_newstat
+	.word sunos_nosys, sys32_newlstat, sys_dup
+	.word sys_pipe, sunos_nosys, sys_profil
+	.word sunos_nosys, sunos_nosys, sunos_getgid
+	.word sunos_nosys, sunos_nosys
+/*50*/	.word sunos_nosys, sys32_acct, sunos_nosys
+	.word sunos_mctl, sunos_ioctl, sys32_reboot
+	.word sunos_nosys, sys32_symlink, sys32_readlink
+	.word sys32_execve, sys_umask, sys32_chroot
+	.word sys32_newfstat, sunos_nosys, sys_getpagesize
+	.word sys32_msync, sys_vfork, sunos_nosys
+	.word sunos_nosys, sunos_sbrk, sunos_sstk
+	.word sunos_mmap, sunos_vadvise, sys32_munmap
+	.word sys32_mprotect, sunos_madvise, sys_vhangup
+	.word sunos_nosys, sunos_mincore, sys32_getgroups
+	.word sys32_setgroups, sys_getpgrp, sunos_setpgrp
+	.word sys32_setitimer, sunos_nosys, sys32_swapon
+	.word sys32_getitimer, sys32_gethostname, sys32_sethostname
+	.word sunos_getdtablesize, sys_dup2, sunos_nop
+	.word sys32_fcntl, sunos_select, sunos_nop
+	.word sys_fsync, sys_setpriority, sys_socket
+	.word sys32_connect, sunos_accept
+/*100*/	.word sys_getpriority, sunos_send, sunos_recv
+	.word sunos_nosys, sys32_bind, sunos_setsockopt
+	.word sys_listen, sunos_nosys, sunos_sigaction
+	.word sunos_sigblock, sunos_sigsetmask, sys_sigpause
+	.word sys32_sigstack, sys32_recvmsg, sys32_sendmsg
+	.word sunos_nosys, sys_gettimeofday, sys32_getrusage
+	.word sunos_getsockopt, sunos_nosys, sunos_readv
+	.word sunos_writev, sys_settimeofday, sys_fchown
+	.word sys_fchmod, sys32_recvfrom, sys32_setreuid
+	.word sys_setregid, sys32_rename, sys32_truncate
+	.word sys32_ftruncate, sys_flock, sunos_nosys
+	.word sys32_sendto, sys_shutdown, sys_socketpair
+	.word sys32_mkdir, sys32_rmdir, sys32_utimes
+	.word sys_sigreturn, sunos_nosys, sys32_getpeername
+	.word sunos_gethostid, sunos_nosys, sys32_getrlimit
+	.word sys32_setrlimit, sunos_killpg, sunos_nosys
+	.word sunos_nosys, sunos_nosys
+/*150*/	.word sys32_getsockname, sunos_nosys, sunos_nosys
+	.word sys32_poll, sunos_nosys, sunos_nosys
+	.word sunos_getdirentries, sys32_statfs, sys32_fstatfs
+	.word sys32_umount, sunos_nosys, sunos_nosys
+	.word sunos_getdomainname, sys32_setdomainname
+	.word sunos_nosys, sys32_quotactl, sunos_nosys
+	.word sunos_mount, sys32_ustat, sunos_semsys
+	.word sunos_nosys, sunos_shmsys, sunos_audit
+	.word sunos_nosys, sunos_getdents, sys_setsid
+	.word sys_fchdir, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sys32_sigpending, sunos_nosys
+	.word sys_setpgid, sunos_pathconf, sunos_fpathconf
+	.word sunos_sysconf, sunos_uname, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+/*200*/	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys
+/*250*/	.word sunos_nosys, sunos_nosys, sunos_nosys
+	.word sunos_nosys, sunos_nosys, sys_aplib
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/time.c linux/arch/sparc64/kernel/time.c
--- v2.1.50/linux/arch/sparc64/kernel/time.c	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc64/kernel/time.c	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.5 1997/07/23 11:32:06 davem Exp $
+/* $Id: time.c,v 1.9 1997/08/12 04:12:40 ecd Exp $
  * time.c: UltraSparc timer and TOD clock support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -8,6 +8,7 @@
  * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -23,6 +24,10 @@
 #include <asm/timer.h>
 #include <asm/irq.h>
 #include <asm/io.h>
+#include <asm/sbus.h>
+#include <asm/fhc.h>
+#include <asm/pbm.h>
+#include <asm/ebus.h>
 
 struct mostek48t02 *mstk48t02_regs = 0;
 struct mostek48t08 *mstk48t08_regs = 0;
@@ -155,33 +160,55 @@
 
 
 /* Probe for the real time clock chip. */
-__initfunc(static void clock_probe(void))
+__initfunc(static void set_system_time(void))
 {
-	struct linux_prom_registers clk_reg[2];
-	char model[128];
-	int node, sbusnd, err;
+	unsigned int year, mon, day, hour, min, sec;
+	struct mostek48t02 *mregs;
 
-	/* XXX HACK HACK HACK, delete me soon */
-	struct linux_prom_ranges XXX_sbus_ranges[PROMREG_MAX];
-	int XXX_sbus_nranges;
-
-	node = prom_getchild(prom_root_node);
-	sbusnd = prom_searchsiblings(node, "sbus");
-	node = prom_getchild(sbusnd);
+	do_get_fast_time = do_gettimeofday;
 
-	if(node == 0 || node == -1) {
-		prom_printf("clock_probe: Serious problem can't find sbus PROM node.\n");
+	mregs = mstk48t02_regs;
+	if(!mregs) {
+		prom_printf("Something wrong, clock regs not mapped yet.\n");
 		prom_halt();
+	}		
+
+	mregs->creg |= MSTK_CREG_READ;
+	sec = MSTK_REG_SEC(mregs);
+	min = MSTK_REG_MIN(mregs);
+	hour = MSTK_REG_HOUR(mregs);
+	day = MSTK_REG_DOM(mregs);
+	mon = MSTK_REG_MONTH(mregs);
+	year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
+	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
+	xtime.tv_usec = 0;
+	mregs->creg &= ~MSTK_CREG_READ;
+}
+
+__initfunc(void clock_probe(void))
+{
+	struct linux_prom_registers clk_reg[2];
+	char model[128];
+	int node, busnd = -1, err;
+
+	if(central_bus != NULL) {
+		busnd = central_bus->child->prom_node;
+	}
+#ifdef CONFIG_PCI
+	else if (ebus_chain != NULL) {
+		busnd = ebus_chain->prom_node;
+	}
+#endif
+	else {
+		busnd = SBus_chain->prom_node;
 	}
 
-	/* XXX FIX ME */
-	err = prom_getproperty(sbusnd, "ranges", (char *) XXX_sbus_ranges,
-			       sizeof(XXX_sbus_ranges));
-	if(err == -1) {
-		prom_printf("clock_probe: Cannot get XXX sbus ranges\n");
+	if(busnd == -1) {
+		prom_printf("clock_probe: problem, cannot find bus to search.\n");
 		prom_halt();
 	}
-	XXX_sbus_nranges = (err / sizeof(struct linux_prom_ranges));
+
+	node = prom_getchild(busnd);
 
 	while(1) {
 		prom_getstring(node, "model", model, sizeof(model));
@@ -199,12 +226,34 @@
 		err = prom_getproperty(node, "reg", (char *)clk_reg,
 				       sizeof(clk_reg));
 		if(err == -1) {
-			prom_printf("clock_probe: Cannot make Mostek\n");
+			prom_printf("clock_probe: Cannot get Mostek reg property\n");
 			prom_halt();
 		}
 
-		/* XXX fix me badly */
-		prom_adjust_regs(clk_reg, 1, XXX_sbus_ranges, XXX_sbus_nranges);
+		if(central_bus) {
+			prom_apply_fhc_ranges(central_bus->child, clk_reg, 1);
+			prom_apply_central_ranges(central_bus, clk_reg, 1);
+		}
+#ifdef CONFIG_PCI
+		else if (ebus_chain) {
+			struct linux_ebus_device *edev;
+
+			for_each_ebusdev(edev, ebus_chain)
+				if (edev->prom_node == node)
+					break;
+			if (!edev) {
+				prom_printf("%s: Mostek not probed by EBUS\n");
+				prom_halt();
+			}
+
+			clk_reg[0] = edev->regs[0];
+		}
+#endif
+		else {
+			prom_adjust_regs(clk_reg, 1,
+					 SBus_chain->sbus_ranges,
+					 SBus_chain->num_sbus_ranges);
+		}
 
 		if(model[5] == '0' && model[6] == '2') {
 			mstk48t02_regs = (struct mostek48t02 *)
@@ -234,6 +283,8 @@
 	/* Kick start the clock if it is completely stopped. */
 	if (mstk48t02_regs->sec & MSTK_STOP)
 		kick_start_clock();
+
+	set_system_time();
 }
 
 #ifndef BCD_TO_BIN
@@ -246,29 +297,10 @@
 
 __initfunc(void time_init(void))
 {
-	unsigned int year, mon, day, hour, min, sec;
-	struct mostek48t02 *mregs;
-
-	do_get_fast_time = do_gettimeofday;
-
-	clock_probe();
-
-	mregs = mstk48t02_regs;
-	if(!mregs) {
-		prom_printf("Something wrong, clock regs not mapped yet.\n");
-		prom_halt();
-	}		
-
-	mregs->creg |= MSTK_CREG_READ;
-	sec = MSTK_REG_SEC(mregs);
-	min = MSTK_REG_MIN(mregs);
-	hour = MSTK_REG_HOUR(mregs);
-	day = MSTK_REG_DOM(mregs);
-	mon = MSTK_REG_MONTH(mregs);
-	year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
-	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-	xtime.tv_usec = 0;
-	mregs->creg &= ~MSTK_CREG_READ;
+	/* clock_probe() is now done at end of sbus_init on sparc64
+	 * so that both sbus and fhc bus information is probed and
+	 * available.
+	 */
 }
 
 extern void init_timers(void (*func)(int, void *, struct pt_regs *));
@@ -307,8 +339,11 @@
 	sethi	%hi(xtime), %g2
 	ldx	[%o1 + %lo(linux_timers)], %g3
 1:	ldd	[%g2 + %lo(xtime)], %o4
+	membar	#LoadLoad | #MemIssue
 	ldx	[%g3], %o1
+	membar	#LoadLoad | #MemIssue
 	ldd	[%g2 + %lo(xtime)], %o2
+	membar	#LoadLoad
 	xor	%o4, %o2, %o2
 	xor	%o5, %o3, %o3
 	orcc	%o2, %o3, %g0
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/trampoline.S linux/arch/sparc64/kernel/trampoline.S
--- v2.1.50/linux/arch/sparc64/kernel/trampoline.S	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc64/kernel/trampoline.S	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/* $Id: trampoline.S,v 1.1 1997/07/24 14:47:53 davem Exp $
+/* $Id: trampoline.S,v 1.2 1997/07/28 02:57:32 davem Exp $
  * trampoline.S: Jump start slave processors on sparc64.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -13,16 +13,28 @@
 #include <asm/spitfire.h>
 #include <asm/asm_offsets.h>
 
+	.data
+	.align		8
+	.globl		smp_trampoline
+smp_trampoline:		.skip	0x300
+
 	.text
-	.globl		sparc64_cpu_startup
+	.align		8
+	.globl		sparc64_cpu_startup, sparc64_cpu_startup_end
 sparc64_cpu_startup:
 	flushw
 	mov	(LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1
 	stxa	%g1, [%g0] ASI_LSU_CONTROL
+	membar	#Sync
 	wrpr	%g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate
 	wrpr	%g0, 15, %pil
 
-	mov	%o0, %g6
+	sethi	%uhi(PAGE_OFFSET), %g4
+	sllx	%g4, 32, %g4
+
+	/* XXX Buggy PROM... */
+	srl	%o0, 0, %g6
+	add	%g6, %g4, %g6
 
 	sethi	%uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5
 	sllx	%g5, 32, %g5
@@ -33,9 +45,8 @@
 	sllx	%g3, 32, %g3
 	sethi	%hi(_PAGE_PADDR), %g7
 	or	%g7, %lo(_PAGE_PADDR), %g7
-	or	%g3, %g7, %g7
+	or	%g3, %g7, %g3
 
-	/* Find TLB entry we are executing out of. */
 	clr	%l0
 	set	0x1fff, %l2
 	rd	%pc, %l3
@@ -69,7 +80,7 @@
 	andn	%g1, %l2, %g1
 	cmp	%g1, %g3
 	blu,pn	%xcc, 2f
-	cmp	%g1, %g7
+	 cmp	%g1, %g7
 	bgeu,pn	%xcc, 2f
 	 nop
 	stxa	%g0, [%l7] ASI_IMMU
@@ -109,7 +120,7 @@
 	stxa	%g3, [%l7] ASI_IMMU
 	stxa	%g5, [%g7] ASI_ITLB_DATA_ACCESS
 	membar	#Sync
-	flush	%g6
+	flush	%g3
 	membar	#Sync
 	b,pt	%xcc, 1f
 	 nop
@@ -125,9 +136,6 @@
 	stxa	%g0, [%g7] ASI_DMMU
 	membar	#Sync
 
-	sethi	%uhi(PAGE_OFFSET), %g4
-	sllx	%g4, 32, %g4
-
 	mov	TLB_TAG_ACCESS, %g2
 	stxa	%g3, [%g2] ASI_IMMU
 	stxa	%g3, [%g2] ASI_DMMU
@@ -143,7 +151,7 @@
 	stxa	%g1, [%g7] ASI_DTLB_DATA_ACCESS
 	membar	#Sync
 
-	flush	%g6
+	flush	%g3
 	membar	#Sync
 
 	mov	1, %g5
@@ -184,7 +192,6 @@
 	stxa	%o5, [%o4] ASI_IMMU
 	membar	#Sync
 
-	wrpr	%g0, 0, %pil
 	or	%o1, PSTATE_IE, %o1
 	wrpr	%o1, 0, %pstate
 
@@ -195,3 +202,6 @@
 	call	cpu_panic
 	 nop
 1:	b,a,pt	%xcc, 1b
+
+	.align		8
+sparc64_cpu_startup_end:
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c
--- v2.1.50/linux/arch/sparc64/kernel/traps.c	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/traps.c	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.29 1997/07/05 09:52:38 davem Exp $
+/* $Id: traps.c,v 1.31 1997/08/11 14:35:33 davem Exp $
  * arch/sparc64/kernel/traps.c
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -25,6 +25,7 @@
 #include <asm/unistd.h>
 #include <asm/uaccess.h>
 #include <asm/fpumacro.h>
+#include <asm/lsu.h>
 
 /* #define SYSCALL_TRACING */
 /* #define VERBOSE_SYSCALL_TRACING */
@@ -194,8 +195,55 @@
 	send_sig(SIGSEGV, current, 1);
 }
 
+#ifdef CONFIG_PCI
+/* This is really pathetic... */
+/* #define DEBUG_PCI_POKES */
+extern volatile int pci_poke_in_progress;
+extern volatile int pci_poke_faulted;
+#endif
+
 void do_dae(struct pt_regs *regs)
 {
+#ifdef CONFIG_PCI
+#ifdef DEBUG_PCI_POKES
+	prom_printf(" (POKE ");
+#endif
+	if(pci_poke_in_progress) {
+		unsigned long va;
+#ifdef DEBUG_PCI_POKES
+		prom_printf("tpc[%016lx] tnpc[%016lx] ",
+			    regs->tpc, regs->tnpc);
+#endif
+		pci_poke_faulted = 1;
+		regs->tnpc = regs->tpc + 4;
+
+
+#ifdef DEBUG_PCI_POKES
+		prom_printf("PCI) ");
+		/* prom_halt(); */
+#endif
+		/* Re-enable I/D caches, Ultra turned them off. */
+		for(va =  0; va < (PAGE_SIZE << 1); va += 32) {
+			spitfire_put_icache_tag(va, 0x0);
+			spitfire_put_dcache_tag(va, 0x0);
+		}
+		__asm__ __volatile__("flush %%g6\n\t"
+				     "membar #Sync\n\t"
+				     "stxa %0, [%%g0] %1\n\t"
+				     "membar #Sync"
+				     : /* no outputs */
+				     : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC |
+					    LSU_CONTROL_IM | LSU_CONTROL_DM),
+				       "i" (ASI_LSU_CONTROL)
+				     : "memory");
+		return;
+	}
+#ifdef DEBUG_PCI_POKES
+	prom_printf("USER) ");
+	prom_printf("tpc[%016lx] tnpc[%016lx]\n");
+	prom_halt();
+#endif
+#endif
 	send_sig(SIGSEGV, current, 1);
 }
 
@@ -215,11 +263,9 @@
 		regs->tpc = regs->tnpc;
 		regs->tnpc += 4;
 	} else {
-		lock_kernel();
 		current->tss.sig_address = regs->tpc;
 		current->tss.sig_desc = SUBSIG_FPERROR;
 		send_sig(SIGFPE, current, 1);
-		unlock_kernel();
 	}
 }
 
@@ -288,6 +334,7 @@
 	}
 	printk("Instruction DUMP:");
 	instruction_dump ((unsigned int *) regs->tpc);
+	lock_kernel(); /* Or else! */
 	if(regs->tstate & TSTATE_PRIV)
 		do_exit(SIGKILL);
 	do_exit(SIGSEGV);
@@ -298,13 +345,11 @@
 	unsigned long pc = regs->tpc;
 	unsigned long tstate = regs->tstate;
 
-	lock_kernel();
 	if(tstate & TSTATE_PRIV)
 		die_if_kernel("Kernel illegal instruction", regs);
 	current->tss.sig_address = pc;
 	current->tss.sig_desc = SUBSIG_ILLINST;
 	send_sig(SIGILL, current, 1);
-	unlock_kernel();
 }
 
 void mem_address_unaligned(struct pt_regs *regs)
@@ -333,19 +378,16 @@
 	current->tss.sig_address = regs->tpc;
 	current->tss.sig_desc = SUBSIG_PRIVINST;
 	send_sig(SIGILL, current, 1);
-	unlock_kernel();
 }
 
 void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 			 unsigned long tstate)
 {
-	lock_kernel();
 	if(tstate & TSTATE_PRIV)
 		die_if_kernel("Penguin instruction from Penguin mode??!?!", regs);
 	current->tss.sig_address = pc;
 	current->tss.sig_desc = SUBSIG_PRIVINST;
 	send_sig(SIGILL, current, 1);
-	unlock_kernel();
 }
 
 /* XXX User may want to be allowed to do this. XXX */
@@ -353,7 +395,6 @@
 void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 			    unsigned long tstate)
 {
-	lock_kernel();
 	if(regs->tstate & TSTATE_PRIV) {
 		printk("KERNEL MNA at pc %016lx npc %016lx called by %016lx\n", pc, npc,
 		       regs->u_regs[UREG_RETPC]);
@@ -363,15 +404,12 @@
 	current->tss.sig_address = pc;
 	current->tss.sig_desc = SUBSIG_PRIVINST;
 	send_sig(SIGBUS, current, 1);
-	unlock_kernel();
 }
 
 void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
 		       unsigned long psr)
 {
-	lock_kernel();
 	send_sig(SIGILL, current, 1);
-	unlock_kernel();
 }
 
 /* Trap level 1 stuff or other traps we should never see... */
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/ttable.S linux/arch/sparc64/kernel/ttable.S
--- v2.1.50/linux/arch/sparc64/kernel/ttable.S	Mon Jul  7 08:18:54 1997
+++ linux/arch/sparc64/kernel/ttable.S	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.18 1997/07/05 09:52:41 davem Exp $
+/* $Id: ttable.S,v 1.19 1997/07/26 18:38:56 davem Exp $
  * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -44,7 +44,8 @@
 tl0_irq7:	TRAP_IRQ(handler_irq, 7)  TRAP_IRQ(handler_irq, 8)
 tl0_irq9:	TRAP_IRQ(handler_irq, 9)  TRAP_IRQ(handler_irq, 10)
 tl0_irq11:	TRAP_IRQ(handler_irq, 11) TRAP_IRQ(handler_irq, 12)
-tl0_irq13:	TRAP_IRQ(handler_irq, 13) TRAP_IRQ(handler_irq, 14)
+tl0_irq13:	TRAP_IRQ(handler_irq, 13)
+tl0_itick:	TRAP_TICK
 tl0_irq15:	TRAP_IRQ(handler_irq, 15)
 tl0_resv050:	BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55)
 tl0_resv056:	BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b)
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/kernel/winfixup.S linux/arch/sparc64/kernel/winfixup.S
--- v2.1.50/linux/arch/sparc64/kernel/winfixup.S	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/kernel/winfixup.S	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/* $Id: winfixup.S,v 1.16 1997/07/13 20:02:42 davem Exp $
+/* $Id: winfixup.S,v 1.19 1997/08/08 08:33:37 jj Exp $
  *
  * winfixup.S: Handle cases where user stack pointer is found to be bogus.
  *
@@ -143,8 +143,9 @@
 	retry
 window_scheisse_from_user_common:
 	wrpr		%g1, %cwp
+	sethi		%hi(109f), %g7
 	ba,pt		%xcc, etrap
-	 rd		%pc, %g7
+109:	 or		%g7, %lo(109b), %g7
 window_scheisse_merge:
 	srlx		%l5, PAGE_SHIFT, %o1
 
@@ -244,8 +245,9 @@
 	retry
 window_mna_from_user_common:
 	wrpr		%g1, %cwp
+	sethi		%hi(109f), %g7
 	ba,pt		%xcc, etrap
-	 rd		%pc, %g7
+109:	 or		%g7, %lo(109b), %g7
 window_mna_merge:
 	call		mem_address_unaligned
 	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/lib/Makefile linux/arch/sparc64/lib/Makefile
--- v2.1.50/linux/arch/sparc64/lib/Makefile	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/lib/Makefile	Sat Aug 16 10:00:22 1997
@@ -6,7 +6,7 @@
 
 OBJS  = blockops.o locks.o strlen.o strncmp.o \
 	memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \
-	VIScopy.o VISbzero.o VISmemset.o VIScsum.o
+	VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o
 
 lib.a: $(OBJS)
 	$(AR) rcs lib.a $(OBJS)
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/lib/VISbzero.S linux/arch/sparc64/lib/VISbzero.S
--- v2.1.50/linux/arch/sparc64/lib/VISbzero.S	Mon Jul  7 08:18:55 1997
+++ linux/arch/sparc64/lib/VISbzero.S	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/* $Id: VISbzero.S,v 1.4 1997/06/28 17:21:21 jj Exp $
+/* $Id: VISbzero.S,v 1.6 1997/08/08 08:34:00 jj Exp $
  * VISbzero.S: High speed clear operations utilizing the UltraSparc
  *        Visual Instruction Set.
  *
@@ -147,7 +147,7 @@
 #else
 	 wr		%g0, ASI_BLK_P, %asi
 #endif
-	membar		#StoreStore | #LoadStore
+	membar		#StoreLoad | #StoreStore | #LoadStore
 	fzero		%f0
 	andcc		%o3, 0xc0, %o2
 	and		%o1, 0x3f, %o1
@@ -181,15 +181,23 @@
 	wr		%g0, 0, %fprs
 	wr		%g7, 0x0, %asi
 #endif
-	membar		#Sync
+	membar		#StoreLoad | #StoreStore
 9:	andcc		%o1, 0xf8, %o2
 	be,pn		%xcc, 13f
 	 andcc		%o1, 7, %o1
+#ifdef __KERNEL__
+14:	sethi		%hi(13f), %o4
+	srl		%o2, 1, %o3
+	sub		%o4, %o3, %o4
+	jmpl		%o4 + %lo(13f), %g0
+	 add		%o0, %o2, %o0
+#else
 14:	rd		%pc, %o4
 	srl		%o2, 1, %o3
 	sub		%o4, %o3, %o4
 	jmpl		%o4 + (13f - 14b), %g0
 	 add		%o0, %o2, %o0
+#endif
 12:	ZERO_BLOCKS(%o0, 0xc8, %g0)
 	ZERO_BLOCKS(%o0, 0x88, %g0)
 	ZERO_BLOCKS(%o0, 0x48, %g0)
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/lib/VIScopy.S linux/arch/sparc64/lib/VIScopy.S
--- v2.1.50/linux/arch/sparc64/lib/VIScopy.S	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/lib/VIScopy.S	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/* $Id: VIScopy.S,v 1.9 1997/07/13 18:23:39 davem Exp $
+/* $Id: VIScopy.S,v 1.11 1997/08/08 08:34:02 jj Exp $
  * VIScopy.S: High speed copy operations utilizing the UltraSparc
  *            Visual Instruction Set.
  *
@@ -303,7 +303,7 @@
 		sethi		%hi(8192), %o2			! IEU0	Group
 		mov		ASI_BLK_P, asi_src		! IEU1
 		b,pt		%xcc, dest_is_64byte_aligned	! CTI
-		 mov		ASI_BLK_COMMIT_P, asi_dest	! IEU0	Group
+		 mov		ASI_BLK_P, asi_dest		! IEU0	Group
 
 		.align			32
 		.globl			__copy_from_user
@@ -446,6 +446,13 @@
 	EXVIS1(LDBLK		[%o1 + 0x40] ASIBLK, %f16)	! LSU	Group
 	sub			%g7, 0x80, %g7			! IEU0
 	EXVIS(LDBLK		[%o1 + 0x80] ASIBLK, %f32)	! LSU	Group
+#ifdef __KERNEL__
+vispc:	sll			%g2, 9, %g2			! IEU0	Group
+	sethi			%hi(vis00), %g5			! IEU1
+	or			%g5, %lo(vis00), %g5		! IEU0	Group
+	jmpl			%g5 + %g2, %g0			! CTI	Group brk forced
+	 addcc			%o1, 0xc0, %o1			! IEU1	Group
+#else
 								! Clk1	Group 8-(
 								! Clk2	Group 8-(
 								! Clk3	Group 8-(
@@ -455,6 +462,7 @@
 	sll			%g2, 9, %g2			! IEU0
 	jmpl			%g5 + %g2, %g0			! CTI	Group brk forced
 	 addcc			%o1, 0xc0, %o1			! IEU1	Group
+#endif
 	.align			512		/* OK, here comes the fun part... */
 vis00:FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) LOOP_CHUNK1(o1, o0, g7, vis01)
       FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) LOOP_CHUNK2(o1, o0, g7, vis02)
@@ -721,20 +729,21 @@
 3:	andcc		%o2, 0x70, %g7				! IEU1	Group
 41:	be,pn		%xcc, 80f				! CTI
 	 andcc		%o2, 8, %g0				! IEU1	Group
-								! Clk1 8-(
-								! Clk2 8-(
-								! Clk3 8-(
-								! Clk4 8-(
-79:	rd		%pc, %o5				! PDU	Group
 #ifdef __KERNEL__
+79:	sethi		%hi(80f), %o5				! IEU0
 	sll		%g7, 1, %g5				! IEU0	Group
 	add		%o1, %g7, %o1				! IEU1
 	srl		%g7, 1, %g2				! IEU0  Group
 	sub		%o5, %g5, %o5				! IEU1
 	sub		%o5, %g2, %o5				! IEU0  Group
-	jmpl		%o5 + %lo(80f - 79b), %g0		! CTI	Group brk forced
+	jmpl		%o5 + %lo(80f), %g0			! CTI	Group brk forced
 	 add		%o0, %g7, %o0				! IEU0	Group
 #else
+								! Clk1 8-(
+								! Clk2 8-(
+								! Clk3 8-(
+								! Clk4 8-(
+79:	rd		%pc, %o5				! PDU	Group
 	sll		%g7, 1, %g5				! IEU0	Group
 	add		%o1, %g7, %o1				! IEU1
 	sub		%o5, %g5, %o5				! IEU0  Group
@@ -814,19 +823,20 @@
 	andcc		%o2, 0x70, %g7				! IEU1
 	be,pn		%xcc, 84f				! CTI
 	 andcc		%o2, 8, %g0				! IEU1	Group
+#ifdef __KERNEL__
+83:	srl		%g7, 1, %g5				! IEU0
+	sethi		%hi(84f), %o5				! IEU0	Group
+	add		%g7, %g5, %g5				! IEU1
+	add		%o1, %g7, %o1				! IEU0	Group
+	sub		%o5, %g5, %o5				! IEU1
+	jmpl		%o5 + %lo(84f), %g0			! CTI	Group brk forced
+	 add		%o0, %g7, %o0				! IEU0	Group
+#else
 								! Clk1 8-(
 								! Clk2 8-(
 								! Clk3 8-(
 								! Clk4 8-(
 83:	rd		%pc, %o5				! PDU	Group
-#ifdef __KERNEL__
-	srl		%g7, 1, %g5				! IEU0	Group
-	add		%g7, %g5, %g5				! IEU0	Group
-	add		%o1, %g7, %o1				! IEU1
-	sub		%o5, %g5, %o5				! IEU0	Group
-	jmpl		%o5 + %lo(84f - 83b), %g0		! CTI	Group brk forced
-	 add		%o0, %g7, %o0				! IEU0	Group
-#else
 	add		%o1, %g7, %o1				! IEU0	Group
 	sub		%o5, %g7, %o5				! IEU1
 	jmpl		%o5 + %lo(84f - 83b), %g0		! CTI	Group brk forced
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/lib/VIScsum.S linux/arch/sparc64/lib/VIScsum.S
--- v2.1.50/linux/arch/sparc64/lib/VIScsum.S	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/lib/VIScsum.S	Sat Aug 16 10:00:22 1997
@@ -434,3 +434,447 @@
 	 add		%o2, 1, %o2		/*  IEU0				*/
 1:	ba,pt		%xcc, 25b		/*  CTI		Group			*/
 	 sllx		%o2, 32, %g1		/*  IEU0				*/
+/* $Id: VIScsum.S,v 1.2 1997/08/08 08:34:05 jj Exp $
+ * VIScsum.S: High bandwidth IP checksumming utilizing the UltraSparc
+ *            Visual Instruction Set.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * Based on older sparc32/sparc64 checksum.S, which is:
+ *
+ *      Copyright(C) 1995 Linus Torvalds
+ *      Copyright(C) 1995 Miguel de Icaza
+ *      Copyright(C) 1996,1997 David S. Miller
+ *    derived from:
+ *	  Linux/Alpha checksum c-code
+ *        Linux/ix86 inline checksum assembly
+ *        RFC1071 Computing the Internet Checksum (esp. Jacobsons m68k code)
+ *	  David Mosberger-Tang for optimized reference c-code
+ *	  BSD4.4 portable checksum routine
+ */
+
+#ifdef __sparc_v9__
+#define STACKOFF	2175
+#else
+#define STACKOFF	64
+#endif
+
+#ifdef __KERNEL__
+#include <asm/head.h>
+#include <asm/asi.h>
+#else
+#define ASI_BLK_P	0xf0
+#define FRPS_FEF	0x04
+#endif
+
+/* Dobrou noc, SunSoft engineers. Spete sladce.
+ * This has a couple of tricks in and those
+ * tricks are UltraLinux trade secrets :))
+ */
+
+#define START_THE_TRICK(fz,f0,f2,f4,f6,f8,f10)							\
+	fcmpgt32	%fz, %f0, %g1		/*  FPM		Group			*/;	\
+	fcmpgt32	%fz, %f2, %g2		/*  FPM		Group			*/;	\
+	fcmpgt32	%fz, %f4, %g3		/*  FPM		Group			*/;	\
+	fcmpgt32	%fz, %f6, %g5		/*  FPM		Group			*/;	\
+	inc		%g1			/*  IEU0				*/;	\
+	fcmpgt32	%fz, %f8, %g7		/*  FPM		Group			*/;	\
+	srl		%g1, 1, %g1		/*  IEU0				*/;	\
+	inc		%g2			/*  IEU1				*/;	\
+	fcmpgt32	%fz, %f10, %o3		/*  FPM		Group			*/;	\
+	srl		%g2, 1, %g2		/*  IEU0				*/;	\
+	add		%o2, %g1, %o2		/*  IEU1				*/;	\
+	add		%g3, 1, %g3		/*  IEU0	Group			*/;	\
+	srl		%g3, 1, %g3		/*  IEU0	Group			*/;	\
+	add		%o2, %g2, %o2		/*  IEU1				*/;	\
+	inc		%g5			/*  IEU0	Group			*/;	\
+	add		%o2, %g3, %o2		/*  IEU1				*/;
+
+#define DO_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14)		\
+	fcmpgt32	%O12, %f12, %o4		/*  FPM		Group			*/;	\
+	srl		%g5, 1, %g5		/*  IEU0				*/;	\
+	inc		%g7			/*  IEU1				*/;	\
+	fpadd32		%F0, %f0, %F0		/*  FPA					*/;	\
+	fcmpgt32	%O14, %f14, %o5		/*  FPM		Group			*/;	\
+	srl		%g7, 1, %g7		/*  IEU0				*/;	\
+	add		%o2, %g5, %o2		/*  IEU1				*/;	\
+	fpadd32		%F2, %f2, %F2		/*  FPA					*/;	\
+	inc		%o3			/*  IEU0	Group			*/;	\
+	add		%o2, %g7, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%f0, %F0, %g1		/*  FPM		Group			*/;	\
+	srl		%o3, 1, %o3		/*  IEU0				*/;	\
+	inc		%o4			/*  IEU1				*/;	\
+	fpadd32		%F4, %f4, %F4		/*  FPA					*/;	\
+	fcmpgt32	%f2, %F2, %g2		/*  FPM		Group			*/;	\
+	srl		%o4, 1, %o4		/*  IEU0				*/;	\
+	add		%o2, %o3, %o2		/*  IEU1				*/;	\
+	fpadd32		%F6, %f6, %F6		/*  FPA					*/;	\
+	inc		%o5			/*  IEU0	Group			*/;	\
+	add		%o2, %o4, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%f4, %F4, %g3		/*  FPM		Group			*/;	\
+	srl		%o5, 1, %o5		/*  IEU0				*/;	\
+	inc		%g1			/*  IEU1				*/;	\
+	fpadd32		%F8, %f8, %F8		/*  FPA					*/;	\
+	fcmpgt32	%f6, %F6, %g5		/*  FPM		Group			*/;	\
+	srl		%g1, 1, %g1		/*  IEU0				*/;	\
+	add		%o2, %o5, %o2		/*  IEU1				*/;	\
+	fpadd32		%F10, %f10, %F10	/*  FPA					*/;	\
+	inc		%g2			/*  IEU0	Group			*/;	\
+	add		%o2, %g1, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%f8, %F8, %g7		/*  FPM		Group			*/;	\
+	srl		%g2, 1, %g2		/*  IEU0				*/;	\
+	inc		%g3			/*  IEU1				*/;	\
+	fpadd32		%F12, %f12, %F12	/*  FPA					*/;	\
+	fcmpgt32	%f10, %F10, %o3		/*  FPM		Group			*/;	\
+	srl		%g3, 1, %g3		/*  IEU0				*/;	\
+	add		%o2, %g2, %o2		/*  IEU1				*/;	\
+	fpadd32		%F14, %f14, %F14	/*  FPA					*/;	\
+	inc		%g5			/*  IEU0	Group			*/;	\
+	add		%o2, %g3, %o2		/*  IEU1				*/;
+
+#define END_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,S0,S1,S2,S3,T0,T1,U0,fz)		\
+	fcmpgt32	%O12, %f12, %o4		/*  FPM		Group			*/;	\
+	srl		%g5, 1, %g5		/*  IEU0				*/;	\
+	inc		%g7			/*  IEU1				*/;	\
+	fpadd32		%f2, %f0, %S0		/*  FPA					*/;	\
+	fcmpgt32	%O14, %f14, %o5		/*  FPM		Group			*/;	\
+	srl		%g7, 1, %g7		/*  IEU0				*/;	\
+	add		%o2, %g5, %o2		/*  IEU1				*/;	\
+	fpadd32		%f6, %f4, %S1		/*  FPA					*/;	\
+	inc		%o3			/*  IEU0	Group			*/;	\
+	add		%o2, %g7, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%f0, %S0, %g1		/*  FPM		Group			*/;	\
+	srl		%o3, 1, %o3		/*  IEU0				*/;	\
+	inc		%o4			/*  IEU1				*/;	\
+	fpadd32		%f10, %f8, %S2		/*  FPA					*/;	\
+	fcmpgt32	%f4, %S1, %g2		/*  FPM		Group			*/;	\
+	srl		%o4, 1, %o4		/*  IEU0				*/;	\
+	add		%o2, %o3, %o2		/*  IEU1				*/;	\
+	fpadd32		%f14, %f12, %S3		/*  FPA					*/;	\
+	inc		%o5			/*  IEU0	Group			*/;	\
+	add		%o2, %o4, %o2		/*  IEU1				*/;	\
+	fzero		%fz			/*  FPA					*/;	\
+	fcmpgt32	%f8, %S2, %g3		/*  FPM		Group			*/;	\
+	srl		%o5, 1, %o5		/*  IEU0				*/;	\
+	inc		%g1			/*  IEU1				*/;	\
+	fpadd32		%S0, %S1, %T0		/*  FPA					*/;	\
+	fcmpgt32	%f12, %S3, %g5		/*  FPM		Group			*/;	\
+	srl		%g1, 1, %g1		/*  IEU0				*/;	\
+	add		%o2, %o5, %o2		/*  IEU1				*/;	\
+	fpadd32		%S2, %S3, %T1		/*  FPA					*/;	\
+	inc		%g2			/*  IEU0	Group			*/;	\
+	add		%o2, %g1, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%S0, %T0, %g7		/*  FPM		Group			*/;	\
+	srl		%g2, 1, %g2		/*  IEU0				*/;	\
+	inc		%g3			/*  IEU1				*/;	\
+	fcmpgt32	%S2, %T1, %o3		/*  FPM		Group			*/;	\
+	srl		%g3, 1, %g3		/*  IEU0				*/;	\
+	add		%o2, %g2, %o2		/*  IEU1				*/;	\
+	inc		%g5			/*  IEU0	Group			*/;	\
+	add		%o2, %g3, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%fz, %f2, %o4		/*  FPM		Group			*/;	\
+	srl		%g5, 1, %g5		/*  IEU0				*/;	\
+	inc		%g7			/*  IEU1				*/;	\
+	fpadd32		%T0, %T1, %U0		/*  FPA					*/;	\
+	fcmpgt32	%fz, %f6, %o5		/*  FPM		Group			*/;	\
+	srl		%g7, 1, %g7		/*  IEU0				*/;	\
+	add		%o2, %g5, %o2		/*  IEU1				*/;	\
+	inc		%o3			/*  IEU0	Group			*/;	\
+	add		%o2, %g7, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%fz, %f10, %g1		/*  FPM		Group			*/;	\
+	srl		%o3, 1, %o3		/*  IEU0				*/;	\
+	inc		%o4			/*  IEU1				*/;	\
+	fcmpgt32	%fz, %f14, %g2		/*  FPM		Group			*/;	\
+	srl		%o4, 1, %o4		/*  IEU0				*/;	\
+	add		%o2, %o3, %o2		/*  IEU1				*/;	\
+	std		%U0, [%sp + STACKOFF]	/*  Store	Group			*/;	\
+	inc		%o5			/*  IEU0				*/;	\
+	sub		%o2, %o4, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%fz, %S1, %g3		/*  FPM		Group			*/;	\
+	srl		%o5, 1, %o5		/*  IEU0				*/;	\
+	inc		%g1			/*  IEU1				*/;	\
+	fcmpgt32	%fz, %S3, %g5		/*  FPM		Group			*/;	\
+	srl		%g1, 1, %g1		/*  IEU0				*/;	\
+	sub		%o2, %o5, %o2		/*  IEU1				*/;	\
+	ldx		[%sp + STACKOFF], %o5	/*  Load	Group			*/;	\
+	inc		%g2			/*  IEU0				*/;	\
+	sub		%o2, %g1, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%fz, %T1, %g7		/*  FPM		Group			*/;	\
+	srl		%g2, 1, %g2		/*  IEU0				*/;	\
+	inc		%g3			/*  IEU1				*/;	\
+	fcmpgt32	%T0, %U0, %o3		/*  FPM		Group			*/;	\
+	srl		%g3, 1, %g3		/*  IEU0				*/;	\
+	sub		%o2, %g2, %o2		/*  IEU1				*/;	\
+	inc		%g5			/*  IEU0	Group			*/;	\
+	sub		%o2, %g3, %o2		/*  IEU1				*/;	\
+	fcmpgt32	%fz, %U0, %o4		/*  FPM		Group			*/;	\
+	srl		%g5, 1, %g5		/*  IEU0				*/;	\
+	inc		%g7			/*  IEU1				*/;	\
+	srl		%g7, 1, %g7		/*  IEU0	Group			*/;	\
+	sub		%o2, %g5, %o2		/*  IEU1				*/;	\
+	inc		%o3			/*  IEU0	Group			*/;	\
+	sub		%o2, %g7, %o2		/*  IEU1				*/;	\
+	srl		%o3, 1, %o3		/*  IEU0	Group			*/;	\
+	inc		%o4			/*  IEU1				*/;	\
+	srl		%o4, 1, %o4		/*  IEU0	Group			*/;	\
+	add		%o2, %o3, %o2		/*  IEU1				*/;	\
+	sub		%o2, %o4, %o2		/*  IEU0	Group			*/;	\
+	addcc		%o2, %o5, %o2		/*  IEU1	Group			*/;	\
+	bcs,a,pn	%xcc, 33f		/*  CTI					*/;	\
+	 add		%o2, 1, %o2		/*  IEU0				*/;	\
+33:						/*  That's it				*/;
+
+#define CSUM_LASTCHUNK(offset)									\
+        ldx             [%o0 - offset - 0x10], %g2;						\
+        ldx             [%o0 - offset - 0x08], %g3;						\
+        addcc           %g2, %o2, %o2;								\
+        bcs,a,pn        %xcc, 31f;								\
+         add            %o2, 1, %o2;								\
+31:     addcc           %g3, %o2, %o2;								\
+        bcs,a,pn        %xcc, 32f;								\
+         add            %o2, 1, %o2;								\
+32:
+
+	.text
+	.globl		csum_partial
+	.align		32
+csum_partial:
+	andcc		%o0, 7, %g0		/*  IEU1	Group			*/
+	be,pt		%icc, 4f		/*  CTI					*/
+	 andcc		%o0, 0x38, %g3		/*  IEU1				*/
+	mov		1, %g5			/*  IEU0	Group			*/
+	cmp		%o1, 6			/*  IEU1				*/
+	bl,pn		%icc, 21f		/*  CTI					*/
+	 andcc		%o0, 2, %g0		/*  IEU1	Group			*/
+	be,pt		%icc, 1f		/*  CTI					*/
+	 and		%o0, 4, %g7		/*  IEU0				*/
+	lduh		[%o0], %g2		/*  Load				*/
+	sub		%o1, 2, %o1		/*  IEU0	Group			*/
+	add		%o0, 2, %o0		/*  IEU1				*/
+	andcc		%o0, 4, %g7		/*  IEU1	Group			*/
+	sll		%g5, 16, %g5		/*  IEU0				*/
+	sll		%g2, 16, %g2		/*  IEU0	Group 			*/
+	addcc		%g2, %o2, %o2		/*  IEU1	Group (regdep)		*/
+	bcs,a,pn	%icc, 1f		/*  CTI					*/
+	 add		%o2, %g5, %o2		/*  IEU0				*/
+1:	ld		[%o0], %g2		/*  Load				*/
+	brz,a,pn	%g7, 4f			/*  CTI+IEU1	Group			*/
+	 and		%o0, 0x38, %g3		/*  IEU0				*/
+	add		%o0, 4, %o0		/*  IEU0	Group			*/
+	sub		%o1, 4, %o1		/*  IEU1				*/
+	addcc		%g2, %o2, %o2		/*  IEU1	Group			*/
+	bcs,a,pn	%icc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+1:	and		%o0, 0x38, %g3		/*  IEU1	Group			*/
+4:	srl		%o2, 0, %o2		/*  IEU0	Group			*/
+	mov		0x40, %g1		/*  IEU1				*/
+	brz,pn		%g3, 3f			/*  CTI+IEU1	Group			*/
+	 sub		%g1, %g3, %g1		/*  IEU0				*/
+	cmp		%o1, 56			/*  IEU1	Group			*/
+	blu,pn		%icc, 20f		/*  CTI					*/
+	 andcc		%o0, 8, %g0		/*  IEU1	Group			*/
+	be,pn		%icc, 1f		/*  CTI					*/
+	 ldx		[%o0], %g2		/*  Load				*/
+	add		%o0, 8, %o0		/*  IEU0	Group			*/
+	sub		%o1, 8, %o1		/*  IEU1				*/
+	addcc		%g2, %o2, %o2		/*  IEU1	Group			*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+1:	andcc		%g1, 0x10, %g0		/*  IEU1	Group			*/
+	be,pn		%icc, 2f		/*  CTI					*/
+	 and		%g1, 0x20, %g1		/*  IEU0				*/
+	ldx		[%o0], %g2		/*  Load				*/
+	ldx		[%o0+8], %g3		/*  Load	Group			*/
+	add		%o0, 16, %o0		/*  IEU0				*/
+	sub		%o1, 16, %o1		/*  IEU1				*/
+	addcc		%g2, %o2, %o2		/*  IEU1	Group			*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+1:	addcc		%g3, %o2, %o2		/*  IEU1	Group			*/
+	bcs,a,pn	%xcc, 2f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+2:	brz,pn		%g1, 3f			/*  CTI+IEU1	Group			*/
+	 ldx		[%o0], %g2		/*  Load				*/
+	ldx		[%o0+8], %g3		/*  Load	Group			*/
+	ldx		[%o0+16], %g5		/*  Load	Group			*/
+	ldx		[%o0+24], %g7		/*  Load	Group			*/
+	add		%o0, 32, %o0		/*  IEU0				*/
+	sub		%o1, 32, %o1		/*  IEU1				*/
+	addcc		%g2, %o2, %o2		/*  IEU1	Group			*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+1:	addcc		%g3, %o2, %o2		/*  IEU1	Group			*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+1:	addcc		%g5, %o2, %o2		/*  IEU1	Group			*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+1:	addcc		%g7, %o2, %o2		/*  IEU1	Group			*/
+	bcs,a,pn	%xcc, 3f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+3:	cmp		%o1, 0xc0		/*  IEU1	Group			*/
+	blu,pn		%icc, 20f		/*  CTI					*/
+	 sllx		%o2, 32, %g1		/*  IEU0				*/
+	addcc		%o2, %g1, %o2		/*  IEU1	Group			*/
+	sub		%o1, 0xc0, %o1		/*  IEU0				*/
+	wr		%g0, ASI_BLK_P, %asi	/*  LSU		Group			*/
+#ifdef __KERNEL__
+	wr		%g0, FPRS_FEF, %fprs	/*  LSU		Group			*/
+#endif
+	membar		#StoreLoad		/*  LSU		Group			*/
+	srlx		%o2, 32, %o2		/*  IEU0	Group			*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU1				*/
+1:	andcc		%o1, 0x80, %g0		/*  IEU1	Group			*/
+	bne,pn		%icc, 7f		/*  CTI					*/
+	 andcc		%o1, 0x40, %g0		/*  IEU1	Group			*/
+	be,pn		%icc, 6f		/*  CTI					*/
+	 fzero		%f12			/*  FPA					*/
+	fzero		%f14			/*  FPA		Group			*/
+	ldda		[%o0 + 0x000] %asi, %f16
+	ldda		[%o0 + 0x040] %asi, %f32
+	ldda		[%o0 + 0x080] %asi, %f48
+	START_THE_TRICK(f12,f16,f18,f20,f22,f24,f26)
+	ba,a,pt		%xcc, 3f
+6:	sub		%o0, 0x40, %o0		/*  IEU0	Group			*/
+	fzero		%f28			/*  FPA					*/
+	fzero		%f30			/*  FPA		Group			*/
+	ldda		[%o0 + 0x040] %asi, %f32
+	ldda		[%o0 + 0x080] %asi, %f48
+	ldda		[%o0 + 0x0c0] %asi, %f0
+	START_THE_TRICK(f28,f32,f34,f36,f38,f40,f42)
+	ba,a,pt		%xcc, 4f
+7:	bne,pt		%icc, 8f		/*  CTI					*/
+	 fzero		%f44			/*  FPA					*/
+	add		%o0, 0x40, %o0		/*  IEU0	Group			*/
+	fzero		%f60			/*  FPA					*/
+	fzero		%f62			/*  FPA		Group			*/
+	ldda		[%o0 - 0x040] %asi, %f0
+	ldda		[%o0 + 0x000] %asi, %f16
+	ldda		[%o0 + 0x040] %asi, %f32
+	START_THE_TRICK(f60,f0,f2,f4,f6,f8,f10)
+	ba,a,pt		%xcc, 2f
+8:	add		%o0, 0x80, %o0		/*  IEU0	Group			*/
+	fzero		%f46			/*  FPA					*/
+	ldda		[%o0 - 0x080] %asi, %f48
+	ldda		[%o0 - 0x040] %asi, %f0
+	ldda		[%o0 + 0x000] %asi, %f16
+	START_THE_TRICK(f44,f48,f50,f52,f54,f56,f58)
+1:	DO_THE_TRICK(f44,f46,f48,f50,f52,f54,f56,f58,f60,f62,f0,f2,f4,f6,f8,f10,f12,f14)
+	ldda		[%o0 + 0x040] %asi, %f32
+2:	DO_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30)
+	ldda		[%o0 + 0x080] %asi, %f48
+3:	DO_THE_TRICK(f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46)
+	ldda		[%o0 + 0x0c0] %asi, %f0
+4:	DO_THE_TRICK(f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,f48,f50,f52,f54,f56,f58,f60,f62)
+	add		%o0, 0x100, %o0		/*  IEU0	Group			*/
+	subcc		%o1, 0x100, %o1		/*  IEU1				*/
+	bgeu,a,pt	%icc, 1b		/*  CTI					*/
+	 ldda		[%o0 + 0x000] %asi, %f16
+	membar		#Sync			/*  LSU		Group			*/
+	DO_THE_TRICK(f44,f46,f48,f50,f52,f54,f56,f58,f60,f62,f0,f2,f4,f6,f8,f10,f12,f14)
+	END_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30)
+	and		%o1, 0x3f, %o1		/*  IEU0	Group			*/
+#ifdef __KERNEL__
+	wr		%g0, 0, %fprs		/*  LSU		Group			*/
+#endif
+20:	andcc		%o1, 0xf0, %g1		/*  IEU1	Group			*/
+	be,pn		%icc, 23f		/*  CTI					*/
+	 and		%o1, 0xf, %o3		/*  IEU0				*/
+#ifdef __KERNEL__
+22:	sll		%g1, 1, %o4		/*  IEU0	Group			*/
+	sethi		%hi(23f), %g7		/*  IEU1				*/
+	sub		%g7, %o4, %g7		/*  IEU0	Group			*/
+	jmpl		%g7 + %lo(23f), %g0	/*  CTI		Group brk forced	*/
+	 add		%o0, %g1, %o0		/*  IEU0				*/
+#else
+22:	rd		%pc, %g7		/*  LSU		Group+4bubbles		*/
+	sll		%g1, 1, %o4		/*  IEU0	Group			*/
+	sub		%g7, %o4, %g7		/*  IEU0	Group (regdep)		*/
+	jmpl		%g7 + (23f - 22b), %g0	/*  CTI		Group brk forced	*/
+	 add		%o0, %g1, %o0		/*  IEU0				*/
+#endif
+	CSUM_LASTCHUNK(0xe0)
+	CSUM_LASTCHUNK(0xd0)
+	CSUM_LASTCHUNK(0xc0)
+	CSUM_LASTCHUNK(0xb0)
+	CSUM_LASTCHUNK(0xa0)
+	CSUM_LASTCHUNK(0x90)
+	CSUM_LASTCHUNK(0x80)
+	CSUM_LASTCHUNK(0x70)
+	CSUM_LASTCHUNK(0x60)
+	CSUM_LASTCHUNK(0x50)
+	CSUM_LASTCHUNK(0x40)
+	CSUM_LASTCHUNK(0x30)
+	CSUM_LASTCHUNK(0x20)
+	CSUM_LASTCHUNK(0x10)
+	CSUM_LASTCHUNK(0x00)
+23:	brnz,pn		%o3, 26f		/*  CTI+IEU1	Group			*/
+24:	 sllx		%o2, 32, %g1		/*  IEU0				*/
+25:	addcc		%o2, %g1, %o0		/*  IEU1	Group			*/
+	srlx		%o0, 32, %o0		/*  IEU0	Group (regdep)		*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o0, 1, %o0		/*  IEU1				*/
+1:	retl					/*  CTI		Group brk forced	*/
+	 srl		%o0, 0, %o0		/*  IEU0				*/
+26:	andcc		%o1, 8, %g0		/*  IEU1	Group			*/
+	be,pn		%icc, 1f		/*  CTI					*/
+	 ldx		[%o0], %g3		/*  Load				*/
+	add		%o0, 8, %o0		/*  IEU0	Group			*/
+	addcc		%g3, %o2, %o2		/*  IEU1	Group			*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+1:	andcc		%o1, 4, %g0		/*  IEU1	Group			*/
+	be,a,pn		%icc, 1f		/*  CTI					*/
+	 clr		%g2			/*  IEU0				*/
+	ld		[%o0], %g2		/*  Load				*/
+	add		%o0, 4, %o0		/*  IEU0	Group			*/
+	sllx		%g2, 32, %g2		/*  IEU0	Group			*/
+1:	andcc		%o1, 2, %g0		/*  IEU1				*/
+	be,a,pn		%icc, 1f		/*  CTI					*/
+	 clr		%o4			/*  IEU0	Group			*/
+	lduh		[%o0], %o4		/*  Load				*/
+	add		%o0, 2, %o0		/*  IEU1				*/
+	sll		%o4, 16, %o4		/*  IEU0	Group			*/
+1:	andcc		%o1, 1, %g0		/*  IEU1				*/
+	be,a,pn		%icc, 1f		/*  CTI					*/
+	 clr		%o5			/*  IEU0	Group			*/
+	ldub		[%o0], %o5		/*  Load				*/
+	sll		%o5, 8, %o5		/*  IEU0	Group			*/
+1:	or		%g2, %o4, %o4		/*  IEU1				*/
+	or		%o5, %o4, %o4		/*  IEU0	Group (regdep)		*/
+	addcc		%o4, %o2, %o2		/*  IEU1	Group (regdep)		*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+1:	ba,pt		%xcc, 25b		/*  CTI		Group			*/
+	 sllx		%o2, 32, %g1		/*  IEU0				*/
+21:	srl		%o2, 0, %o2		/*  IEU0	Group			*/
+	cmp		%o1, 0			/*  IEU1				*/
+	be,pn		%icc, 24b		/*  CTI					*/
+	 andcc		%o1, 4, %g0		/*  IEU1	Group			*/
+	be,a,pn		%icc, 1f		/*  CTI					*/
+	 clr		%g2			/*  IEU0				*/
+	lduh		[%o0], %g3		/*  Load				*/
+	lduh		[%o0+2], %g2		/*  Load	Group			*/
+	add		%o0, 4, %o0		/*  IEU0	Group			*/
+	sllx		%g3, 48, %g3		/*  IEU0	Group			*/
+	sllx		%g2, 32, %g2		/*  IEU0	Group			*/
+	or		%g3, %g2, %g2		/*  IEU0	Group			*/
+1:	andcc		%o1, 2, %g0		/*  IEU1				*/
+	be,a,pn		%icc, 1f		/*  CTI					*/
+	 clr		%o4			/*  IEU0	Group			*/
+	lduh		[%o0], %o4		/*  Load				*/
+	add		%o0, 2, %o0		/*  IEU1				*/
+	sll		%o4, 16, %o4		/*  IEU0	Group			*/
+1:	andcc		%o1, 1, %g0		/*  IEU1				*/
+	be,a,pn		%icc, 1f		/*  CTI					*/
+	 clr		%o5			/*  IEU0	Group			*/
+	ldub		[%o0], %o5		/*  Load				*/
+	sll		%o5, 8, %o5		/*  IEU0	Group			*/
+1:	or		%g2, %o4, %o4		/*  IEU1				*/
+	or		%o5, %o4, %o4		/*  IEU0	Group (regdep)		*/
+	addcc		%o4, %o2, %o2		/*  IEU1	Group (regdep)		*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%o2, 1, %o2		/*  IEU0				*/
+1:	ba,pt		%xcc, 25b		/*  CTI		Group			*/
+	 sllx		%o2, 32, %g1		/*  IEU0				*/
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/lib/VIScsumcopy.S linux/arch/sparc64/lib/VIScsumcopy.S
--- v2.1.50/linux/arch/sparc64/lib/VIScsumcopy.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/sparc64/lib/VIScsumcopy.S	Sat Aug 16 09:51:09 1997
@@ -0,0 +1,880 @@
+/* $Id: VIScsumcopy.S,v 1.1 1997/08/09 18:14:29 jj Exp $
+ * VIScsumcopy.S: High bandwidth IP checksumming with simultaneous
+ *            copying utilizing the UltraSparc Visual Instruction Set.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * Based on older sparc32/sparc64 checksum.S, which is:
+ *
+ *      Copyright(C) 1995 Linus Torvalds
+ *      Copyright(C) 1995 Miguel de Icaza
+ *      Copyright(C) 1996,1997 David S. Miller
+ *    derived from:
+ *	  Linux/Alpha checksum c-code
+ *        Linux/ix86 inline checksum assembly
+ *        RFC1071 Computing the Internet Checksum (esp. Jacobsons m68k code)
+ *	  David Mosberger-Tang for optimized reference c-code
+ *	  BSD4.4 portable checksum routine
+ */
+
+#ifdef __sparc_v9__
+#define STACKOFF	0x7ff+128
+#else
+#define STACKOFF	64
+#endif
+
+#ifdef __KERNEL__
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/page.h>
+#else
+#define ASI_P		0x80
+#define ASI_BLK_P	0xf0
+#define FRPS_FEF	0x04
+#define FPRS_DU		0x02
+#define FPRS_DL		0x01
+#endif
+#define ASI_BLK_XOR	(ASI_BLK_P ^ ASI_P)
+
+#define src		o0
+#define dst		o1
+#define	len		o2
+#define sum		o3
+#define x1		g1
+#define x2		g2
+#define x3		g3
+#define x4		g4
+#define x5		g5
+#define x6		g7
+#define x7		o4
+#define x8		o5
+
+/* Dobrou noc, SunSoft engineers. Spete sladce.
+ * This has a couple of tricks in and those
+ * tricks are UltraLinux trade secrets :))
+ * Once AGAIN, the SunSoft engineers are caught
+ * asleep at the keyboard :)).
+ * The main loop does about 20 superscalar cycles
+ * per 64bytes checksummed/copied.
+ */
+
+#define LDBLK(O0)										\
+	ldda		[%src] %asi, %O0 	/*  Load	Group			*/
+
+#define STBLK											\
+	stda		%f48, [%dst] ASI_BLK_P	/*  Store				*/
+
+#define ST(fx,off)										\
+	std		%fx, [%dst + off]	/*  Store				*/
+
+#define SYNC											\
+	membar		#Sync
+
+
+#define DO_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14,DUMMY1,A0,A2,A4,A6,A8,A10,A12,A14,B14,DYMMY2,LOAD,STORE1,STORE2,STORE3,STORE4,STORE5,STORE6,STORE7,STORE8,DUMMY3,BRANCH...)	\
+	LOAD					/*  Load	Group			*/;	\
+	faligndata	%A14, %F0, %A14		/*  FPA		Group			*/;	\
+	inc		%x5			/*  IEU0				*/;	\
+	STORE1					/*  Store (optional)			*/;	\
+	faligndata	%F0, %F2, %A0		/*  FPA		Group			*/;	\
+	srl		%x5, 1, %x5		/*  IEU0				*/;	\
+	add		%sum, %x4, %sum		/*  IEU1				*/;	\
+	fpadd32		%F0, %f0, %F0		/*  FPA		Group			*/;	\
+	inc		%x6			/*  IEU0				*/;	\
+	STORE2					/*  Store (optional)			*/;	\
+	faligndata	%F2, %F4, %A2		/*  FPA		Group			*/;	\
+	srl		%x6, 1, %x6		/*  IEU0				*/;	\
+	add		%sum, %x5, %sum		/*  IEU1				*/;	\
+	fpadd32		%F2, %f2, %F2		/*  FPA		Group			*/;	\
+	add		%src, 64, %src		/*  IEU0				*/;	\
+	add		%dst, 64, %dst		/*  IEU1				*/;	\
+	fcmpgt32	%f0, %F0, %x1		/*  FPM		Group			*/;	\
+	inc		%x7			/*  IEU0				*/;	\
+	STORE3					/*  Store (optional)			*/;	\
+	faligndata	%F4, %F6, %A4		/*  FPA					*/;	\
+	srl		%x7, 1, %x7		/*  IEU0	Group			*/;	\
+	add		%sum, %x6, %sum		/*  IEU1				*/;	\
+	fpadd32		%F4, %f4, %F4		/*  FPA					*/;	\
+	fcmpgt32	%f2, %F2, %x2		/*  FPM		Group			*/;	\
+	inc		%x8			/*  IEU0				*/;	\
+	STORE4					/*  Store (optional)			*/;	\
+	faligndata	%F6, %F8, %A6		/*  FPA					*/;	\
+	srl		%x8, 1, %x8		/*  IEU0	Group			*/;	\
+	add		%sum, %x7, %sum		/*  IEU1				*/;	\
+	fpadd32		%F6, %f6, %F6		/*  FPA					*/;	\
+	fcmpgt32	%f4, %F4, %x3		/*  FPM		Group			*/;	\
+	inc		%x1			/*  IEU0				*/;	\
+	STORE5					/*  Store (optional)			*/;	\
+	faligndata	%F8, %F10, %A8		/*  FPA					*/;	\
+	srl		%x1, 1, %x1		/*  IEU0	Group			*/;	\
+	add		%sum, %x8, %sum		/*  IEU1				*/;	\
+	fpadd32		%F8, %f8, %F8		/*  FPA					*/;	\
+	fcmpgt32	%f6, %F6, %x4		/*  FPM		Group			*/;	\
+	inc		%x2			/*  IEU0				*/;	\
+	STORE6					/*  Store (optional)			*/;	\
+	faligndata	%F10, %F12, %A10	/*  FPA					*/;	\
+	srl		%x2, 1, %x2		/*  IEU0	Group			*/;	\
+	add		%sum, %x1, %sum		/*  IEU1				*/;	\
+	fpadd32		%F10, %f10, %F10	/*  FPA					*/;	\
+	fcmpgt32	%f8, %F8, %x5		/*  FPM		Group			*/;	\
+	inc		%x3			/*  IEU0				*/;	\
+	STORE7					/*  Store (optional)			*/;	\
+	faligndata	%F12, %F14, %A12	/*  FPA					*/;	\
+	srl		%x3, 1, %x3		/*  IEU0	Group			*/;	\
+	add		%sum, %x2, %sum		/*  IEU1				*/;	\
+	fpadd32		%F12, %f12, %F12	/*  FPA					*/;	\
+	fcmpgt32	%f10, %F10, %x6		/*  FPM		Group			*/;	\
+	inc		%x4			/*  IEU0				*/;	\
+	STORE8					/*  Store (optional)			*/;	\
+	fmovd		%F14, %B14		/*  FPA					*/;	\
+	srl		%x4, 1, %x4		/*  IEU0	Group			*/;	\
+	add		%sum, %x3, %sum		/*  IEU1				*/;	\
+	fpadd32		%F14, %f14, %F14	/*  FPA					*/;	\
+	fcmpgt32	%f12, %F12, %x7		/*  FPM		Group			*/;	\
+	subcc		%len, 64, %len		/*  IEU1				*/;	\
+	BRANCH					/*  CTI					*/;	\
+	fcmpgt32	%f14, %F14, %x8		/*  FPM		Group			*/;	\
+
+#define END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,S0,S1,S2,S3,T0,T1,U0,fz) \
+	inc		%x5			/*  IEU0	Group			*/;	\
+	fpadd32		%f2, %f0, %S0		/*  FPA					*/;	\
+	srl		%x5, 1, %x5		/*  IEU0	Group			*/;	\
+	add		%sum, %x4, %sum		/*  IEU1				*/;	\
+	fpadd32		%f6, %f4, %S1		/*  FPA					*/;	\
+	inc		%x6			/*  IEU0	Group			*/;	\
+	add		%sum, %x5, %sum		/*  IEU1				*/;	\
+	fcmpgt32	%f0, %S0, %x1		/*  FPM		Group			*/;	\
+	srl		%x6, 1, %x6		/*  IEU0				*/;	\
+	inc		%x7			/*  IEU1				*/;	\
+	fpadd32		%f10, %f8, %S2		/*  FPA					*/;	\
+	fcmpgt32	%f4, %S1, %x2		/*  FPM		Group			*/;	\
+	srl		%x7, 1, %x7		/*  IEU0				*/;	\
+	add		%sum, %x6, %sum		/*  IEU1				*/;	\
+	fpadd32		%f14, %f12, %S3		/*  FPA					*/;	\
+	inc		%x8			/*  IEU0	Group			*/;	\
+	add		%sum, %x7, %sum		/*  IEU1				*/;	\
+	fzero		%fz			/*  FPA					*/;	\
+	fcmpgt32	%f8, %S2, %x3		/*  FPM		Group			*/;	\
+	srl		%x8, 1, %x8		/*  IEU0				*/;	\
+	inc		%x1			/*  IEU1				*/;	\
+	fpadd32		%S0, %S1, %T0		/*  FPA					*/;	\
+	fcmpgt32	%f12, %S3, %x4		/*  FPM		Group			*/;	\
+	srl		%x1, 1, %x1		/*  IEU0				*/;	\
+	add		%sum, %x8, %sum		/*  IEU1				*/;	\
+	fpadd32		%S2, %S3, %T1		/*  FPA					*/;	\
+	inc		%x2			/*  IEU0	Group			*/;	\
+	add		%sum, %x1, %sum		/*  IEU1				*/;	\
+	fcmpgt32	%S0, %T0, %x5		/*  FPM		Group			*/;	\
+	srl		%x2, 1, %x2		/*  IEU0				*/;	\
+	inc		%x3			/*  IEU1				*/;	\
+	fcmpgt32	%S2, %T1, %x6		/*  FPM		Group			*/;	\
+	srl		%x3, 1, %x3		/*  IEU0				*/;	\
+	add		%sum, %x2, %sum		/*  IEU1				*/;	\
+	inc		%x4			/*  IEU0	Group			*/;	\
+	add		%sum, %x3, %sum		/*  IEU1				*/;	\
+	fcmpgt32	%fz, %f2, %x7		/*  FPM		Group			*/;	\
+	srl		%x4, 1, %x4		/*  IEU0				*/;	\
+	inc		%x5			/*  IEU1				*/;	\
+	fpadd32		%T0, %T1, %U0		/*  FPA					*/;	\
+	fcmpgt32	%fz, %f6, %x8		/*  FPM		Group			*/;	\
+	srl		%x5, 1, %x5		/*  IEU0				*/;	\
+	add		%sum, %x4, %sum		/*  IEU1				*/;	\
+	inc		%x6			/*  IEU0	Group			*/;	\
+	add		%sum, %x5, %sum		/*  IEU1				*/;	\
+	fcmpgt32	%fz, %f10, %x1		/*  FPM		Group			*/;	\
+	srl		%x6, 1, %x6		/*  IEU0				*/;	\
+	inc		%x7			/*  IEU1				*/;	\
+	fcmpgt32	%fz, %f14, %x2		/*  FPM		Group			*/;	\
+	ba,pt		%xcc, ett		/*  CTI					*/;	\
+	 fmovd		%FA, %FB		/*  FPA					*/;	\
+
+#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB) 					\
+	END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,f48,f50,f52,f54,f56,f58,f60,f62)
+
+#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz) 						\
+	fpadd32		%U0, %U1, %V0		/*  FPA		Group			*/;	\
+	srl		%x7, 1, %x7		/*  IEU0				*/;	\
+	add		%sum, %x6, %sum		/*  IEU1				*/;	\
+	std		%V0, [%sp + STACKOFF]	/*  Store	Group			*/;	\
+	inc		%x8			/*  IEU0				*/;	\
+	sub		%sum, %x7, %sum		/*  IEU1				*/;	\
+	fcmpgt32	%fz, %S1, %x3		/*  FPM		Group			*/;	\
+	srl		%x8, 1, %x8		/*  IEU0				*/;	\
+	inc		%x1			/*  IEU1				*/;	\
+	fcmpgt32	%fz, %S3, %x4		/*  FPM		Group			*/;	\
+	srl		%x1, 1, %x1		/*  IEU0				*/;	\
+	sub		%sum, %x8, %sum		/*  IEU1				*/;	\
+	ldx		[%sp + STACKOFF], %x8	/*  Load	Group			*/;	\
+	inc		%x2			/*  IEU0				*/;	\
+	sub		%sum, %x1, %sum		/*  IEU1				*/;	\
+	fcmpgt32	%fz, %T1, %x5		/*  FPM		Group			*/;	\
+	srl		%x2, 1, %x2		/*  IEU0				*/;	\
+	inc		%x3			/*  IEU1				*/;	\
+	fcmpgt32	%T0, %U0, %x6		/*  FPM		Group			*/;	\
+	srl		%x3, 1, %x3		/*  IEU0				*/;	\
+	sub		%sum, %x2, %sum		/*  IEU1				*/;	\
+	inc		%x4			/*  IEU0	Group			*/;	\
+	sub		%sum, %x3, %sum		/*  IEU1				*/;	\
+	fcmpgt32	%fz, %U1, %x7		/*  FPM		Group			*/;	\
+	srl		%x4, 1, %x4		/*  IEU0				*/;	\
+	inc		%x5			/*  IEU1				*/;	\
+	fcmpgt32	%U0, %V0, %x1		/*  FPM		Group			*/;	\
+	srl		%x5, 1, %x5		/*  IEU0				*/;	\
+	sub		%sum, %x4, %sum		/*  IEU1				*/;	\
+	fcmpgt32	%fz, %V0, %x2		/*  FPM		Group			*/;	\
+	inc		%x6			/*  IEU0				*/;	\
+	sub		%sum, %x5, %sum		/*  IEU1				*/;	\
+	srl		%x6, 1, %x6		/*  IEU0	Group			*/;	\
+	inc		%x7			/*  IEU1				*/;	\
+	srl		%x7, 1, %x7		/*  IEU0	Group			*/;	\
+	add		%sum, %x6, %sum		/*  IEU1				*/;	\
+	inc		%x1			/*  IEU0	Group			*/;	\
+	sub		%sum, %x7, %sum		/*  IEU1				*/;	\
+	srl		%x1, 1, %x1		/*  IEU0	Group			*/;	\
+	inc		%x2			/*  IEU1				*/;	\
+	srl		%x2, 1, %x2		/*  IEU0	Group			*/;	\
+	add		%sum, %x1, %sum		/*  IEU1				*/;	\
+	sub		%sum, %x2, %sum		/*  IEU0	Group			*/;	\
+	addcc		%sum, %x8, %sum		/*  IEU		Group			*/;	\
+	bcs,a,pn	%xcc, 33f		/*  CTI					*/;	\
+	 add		%sum, 1, %sum		/*  IEU0				*/;	\
+33:						/*  That's it				*/;
+
+	.text
+	.globl		csum_partial_copy_vis
+	.align		32
+/* %asi should be either ASI_P or ASI_S for csum_partial_copy resp. csum_partial_copy_from_user */
+/* This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256 */
+csum_partial_copy_vis:
+	andcc		%dst, 7, %g0		/*  IEU1	Group			*/
+	be,pt		%icc, 4f		/*  CTI					*/
+	 and		%dst, 0x38, %g3		/*  IEU0				*/
+	mov		1, %g5			/*  IEU0	Group			*/
+	andcc		%dst, 2, %g0		/*  IEU1				*/
+	be,pt		%icc, 1f		/*  CTI					*/
+	 and		%dst, 4, %g7		/*  IEU0	Group			*/
+	lduha		[%src] %asi, %g2	/*  Load				*/
+	sub		%len, 2, %len		/*  IEU0	Group			*/
+	add		%dst, 2, %dst		/*  IEU1				*/
+	andcc		%dst, 4, %g7		/*  IEU1	Group			*/
+	sll		%g5, 16, %g5		/*  IEU0				*/
+	sth		%g2, [%dst - 2]		/*  Store	Group			*/
+	sll		%g2, 16, %g2		/*  IEU0	 			*/
+	add		%src, 2, %src		/*  IEU1				*/
+	addcc		%g2, %sum, %sum		/*  IEU1	Group			*/
+	bcs,a,pn	%icc, 1f		/*  CTI					*/
+	 add		%sum, %g5, %sum		/*  IEU0				*/
+1:	lduwa		[%src] %asi, %g2	/*  Load				*/
+	brz,a,pn	%g7, 4f			/*  CTI+IEU1	Group			*/
+	 and		%dst, 0x38, %g3		/*  IEU0				*/
+	add		%dst, 4, %dst		/*  IEU0	Group			*/
+	sub		%len, 4, %len		/*  IEU1				*/
+	addcc		%g2, %sum, %sum		/*  IEU1	Group			*/
+	bcs,a,pn	%icc, 1f		/*  CTI					*/
+	 add		%sum, 1, %sum		/*  IEU0				*/
+1:	and		%dst, 0x38, %g3		/*  IEU0	Group			*/
+	stw		%g2, [%dst - 4]		/*  Store				*/
+	add		%src, 4, %src		/*  IEU1				*/
+4:
+#ifdef __KERNEL__
+	wr		%g0, FPRS_FEF, %fprs	/*  LSU		Group			*/
+#endif
+	mov		%src, %g7		/*  IEU1	Group			*/
+	fzero		%f48			/*  FPA					*/
+	alignaddr	%src, %g0, %src		/*  Single	Group			*/
+	subcc		%g7, %src, %g7		/*  IEU1	Group			*/
+	be,pt		%xcc, 1f		/*  CTI					*/
+	 mov		0x40, %g1		/*  IEU0				*/
+	lduwa		[%src] %asi, %g2	/*  Load	Group			*/
+	subcc		%sum, %g2, %sum		/*  IEU1	Group+load stall	*/
+	bcs,a,pn	%icc, 1f		/*  CTI					*/
+	 sub		%sum, 1, %sum		/*  IEU0				*/
+1:	srl		%sum, 0, %sum		/*  IEU0	Group			*/
+	clr		%g5			/*  IEU1				*/
+	brz,pn		%g3, 3f			/*  CTI+IEU1	Group			*/
+	 sub		%g1, %g3, %g1		/*  IEU0				*/
+	ldda		[%src] %asi, %f0	/*  Load				*/
+	clr		%g3			/*  IEU0	Group			*/
+	andcc		%dst, 8, %g0		/*  IEU1				*/
+	be,pn		%icc, 1f		/*  CTI					*/
+	 ldda		[%src + 8] %asi, %f2	/*  Load	Group			*/
+	add		%src, 8, %src		/*  IEU0				*/
+	sub		%len, 8, %len		/*  IEU1				*/
+	fpadd32		%f0, %f48, %f50		/*  FPA					*/
+	addcc		%dst, 8, %dst		/*  IEU1	Group			*/
+	faligndata	%f0, %f2, %f16		/*  FPA					*/
+	fcmpgt32	%f48, %f50, %g3		/*  FPM		Group			*/
+	fmovd		%f2, %f0		/*  FPA		Group			*/
+	ldda		[%src + 8] %asi, %f2	/*  Load				*/
+	std		%f16, [%dst - 8]	/*  Store				*/
+	fmovd		%f50, %f48		/*  FPA					*/
+1:	andcc		%g1, 0x10, %g0		/*  IEU1	Group			*/
+	be,pn		%icc, 1f		/*  CTI					*/
+	 and		%g1, 0x20, %g1		/*  IEU0				*/
+	fpadd32		%f0, %f48, %f50		/*  FPA					*/
+	ldda		[%src + 16] %asi, %f4	/*  Load	Group			*/
+	add		%src, 16, %src		/*  IEU0				*/
+	add		%dst, 16, %dst		/*  IEU1				*/
+	faligndata	%f0, %f2, %f16		/*  FPA					*/
+	fcmpgt32	%f48, %f50, %g5		/*  FPM		Group			*/
+	sub		%len, 16, %len		/*  IEU0				*/
+	inc		%g3			/*  IEU1				*/
+	std		%f16, [%dst - 16]	/*  Store	Group			*/
+	fpadd32		%f2, %f50, %f48		/*  FPA					*/
+	srl		%g3, 1, %o5		/*  IEU0				*/
+	faligndata	%f2, %f4, %f18		/*  FPA		Group			*/
+	std		%f18, [%dst - 8]	/*  Store				*/
+	fcmpgt32	%f50, %f48, %g3		/*  FPM		Group			*/
+	add		%o5, %sum, %sum		/*  IEU0				*/
+	ldda		[%src + 8] %asi, %f2	/*  Load				*/
+	fmovd		%f4, %f0		/*  FPA					*/
+1:	brz,a,pn	%g1, 4f			/*  CTI+IEU1	Group			*/
+	 rd		%asi, %g2		/*  LSU		Group + 4 bubbles	*/
+	inc		%g5			/*  IEU0				*/
+	fpadd32		%f0, %f48, %f50		/*  FPA					*/
+	ldda		[%src + 16] %asi, %f4	/*  Load	Group			*/
+	srl		%g5, 1, %g5		/*  IEU0				*/
+	add		%dst, 32, %dst		/*  IEU1				*/
+	faligndata	%f0, %f2, %f16		/*  FPA					*/
+	fcmpgt32	%f48, %f50, %o5		/*  FPM		Group			*/
+	inc		%g3			/*  IEU0				*/
+	ldda		[%src + 24] %asi, %f6	/*  Load				*/
+	srl		%g3, 1, %g3		/*  IEU0	Group			*/
+	add		%g5, %sum, %sum		/*  IEU1				*/
+	ldda		[%src + 32] %asi, %f8	/*  Load				*/
+	fpadd32		%f2, %f50, %f48		/*  FPA					*/
+	faligndata	%f2, %f4, %f18		/*  FPA		Group			*/
+	sub		%len, 32, %len		/*  IEU0				*/
+	std		%f16, [%dst - 32]	/*  Store				*/
+	fcmpgt32	%f50, %f48, %o4		/*  FPM		Group			*/
+	inc		%o5			/*  IEU0				*/
+	add		%g3, %sum, %sum		/*  IEU1				*/
+	fpadd32		%f4, %f48, %f50		/*  FPA					*/
+	faligndata	%f4, %f6, %f20		/*  FPA		Group			*/
+	srl		%o5, 1, %o5		/*  IEU0				*/
+	fcmpgt32	%f48, %f50, %g5		/*  FPM		Group			*/
+	add		%o5, %sum, %sum		/*  IEU0				*/
+	std		%f18, [%dst - 24]	/*  Store				*/
+	fpadd32		%f6, %f50, %f48		/*  FPA					*/
+	inc		%o4			/*  IEU0	Group			*/
+	std		%f20, [%dst - 16]	/*  Store				*/
+	add		%src, 32, %src		/*  IEU1				*/
+	faligndata	%f6, %f8, %f22		/*  FPA					*/
+	fcmpgt32	%f50, %f48, %g3		/*  FPM		Group			*/
+	srl		%o4, 1, %o4		/*  IEU0				*/
+	std		%f22, [%dst - 8]	/*  Store				*/	
+	add		%o4, %sum, %sum		/*  IEU0	Group			*/
+3:	rd		%asi, %g2		/*  LSU		Group + 4 bubbles	*/
+#ifdef __KERNEL__
+4:	sethi		%hi(vis0s), %g7		/*  IEU0	Group			*/
+#else
+4:	rd		%pc, %g7		/*  LSU		Group + 4 bubbles	*/
+#endif
+	inc		%g5			/*  IEU0	Group			*/
+	and		%src, 0x38, %o4		/*  IEU1				*/	
+	membar		#StoreLoad		/*  LSU		Group			*/
+	srl		%g5, 1, %g5		/*  IEU0				*/
+	inc		%g3			/*  IEU1				*/
+	sll		%o4, 8, %o4		/*  IEU0	Group			*/
+	sub		%len, 0xc0, %len	/*  IEU1				*/
+	addcc		%g5, %sum, %sum		/*  IEU1	Group			*/
+	srl		%g3, 1, %g3		/*  IEU0				*/
+	add		%g7, %o4, %g7		/*  IEU0	Group			*/
+	add		%g3, %sum, %sum		/*  IEU1				*/
+#ifdef __KERNEL__
+	jmpl		%g7 + %lo(vis0s), %g0	/*  CTI+IEU1	Group			*/
+#else
+	jmpl		%g7 + (vis0s - 4b), %g0	/*  CTI+IEU1	Group			*/
+#endif
+	 fzero		%f32			/*  FPA					*/
+
+	.align		2048
+vis0s:	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group			*/
+	add		%src, 128, %src		/*  IEU0	Group			*/
+	ldda		[%src-128] %asi, %f0	/*  Load	Group			*/
+	ldda		[%src-64] %asi, %f16	/*  Load	Group			*/
+	fmovd		%f48, %f62		/*  FPA		Group			*/
+	faligndata	%f0, %f2, %f48		/*  FPA		Group			*/
+	fcmpgt32	%f32, %f2, %x1		/*  FPM		Group			*/
+	fpadd32		%f0, %f62, %f0		/*  FPA					*/
+	fcmpgt32	%f32, %f4, %x2		/*  FPM		Group			*/
+	faligndata	%f2, %f4, %f50		/*  FPA					*/
+	fcmpgt32	%f62, %f0, %x3		/*  FPM		Group			*/
+	faligndata	%f4, %f6, %f52		/*  FPA					*/
+	fcmpgt32	%f32, %f6, %x4		/*  FPM		Group			*/
+	inc		%x1			/*  IEU0				*/
+	faligndata	%f6, %f8, %f54		/*  FPA					*/
+	fcmpgt32	%f32, %f8, %x5		/*  FPM		Group			*/
+	srl		%x1, 1, %x1		/*  IEU0				*/
+	inc		%x2			/*  IEU1				*/
+	faligndata	%f8, %f10, %f56		/*  FPA					*/
+	fcmpgt32	%f32, %f10, %x6		/*  FPM		Group			*/
+	srl		%x2, 1, %x2		/*  IEU0				*/
+	add		%sum, %x1, %sum		/*  IEU1				*/
+	faligndata	%f10, %f12, %f58	/*  FPA					*/
+	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group			*/
+	inc		%x3			/*  IEU0				*/
+	add		%sum, %x2, %sum		/*  IEU1				*/
+	faligndata	%f12, %f14, %f60	/*  FPA					*/
+	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group			*/
+	srl		%x3, 1, %x3		/*  IEU0				*/
+	inc		%x4			/*  IEU1				*/
+	fmovd		%f14, %f62		/*  FPA					*/
+	srl		%x4, 1, %x4		/*  IEU0	Group			*/
+	add		%sum, %x3, %sum		/*  IEU1				*/
+vis0:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,
+			,f48,f50,f52,f54,f56,f58,f60,f62,f62,								
+			,LDBLK(f32),	STBLK,,,,,,,,									
+			,bcs,pn %icc, vis0e1)
+	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+			,f48,f50,f52,f54,f56,f58,f60,f62,f62,								
+			,LDBLK(f0),	STBLK,,,,,,,,									
+			,bcs,pn %icc, vis0e2)
+	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
+			,f48,f50,f52,f54,f56,f58,f60,f62,f62,
+			,LDBLK(f16),	STBLK,,,,,,,,
+			,bcc,pt %icc, vis0)
+vis0e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
+			,f48,f50,f52,f54,f56,f58,f60,f62,f32,
+			,SYNC,		STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
+			,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e2)
+vis0e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+			,f48,f50,f52,f54,f56,f58,f60,f62,f0,
+			,SYNC,		STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
+			,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e3)
+vis0e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
+			,f48,f50,f52,f54,f56,f58,f60,f62,f16,
+			,SYNC,		STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48),
+			,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e1)
+	.align		2048
+vis1s:	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group			*/
+	add		%src, 128 - 8, %src	/*  IEU0	Group			*/
+	ldda		[%src-128] %asi, %f0	/*  Load	Group			*/
+	ldda		[%src-64] %asi, %f16	/*  Load	Group			*/
+	fmovd		%f48, %f0		/*  FPA		Group			*/
+	fcmpgt32	%f32, %f2, %x2		/*  FPM		Group			*/
+	faligndata	%f2, %f4, %f48		/*  FPA					*/
+	fcmpgt32	%f32, %f4, %x3		/*  FPM		Group			*/
+	faligndata	%f4, %f6, %f50		/*  FPA					*/
+	fcmpgt32	%f32, %f6, %x4		/*  FPM		Group			*/
+	faligndata	%f6, %f8, %f52		/*  FPA					*/
+	fcmpgt32	%f32, %f8, %x5		/*  FPM		Group			*/
+	inc		%x2			/*  IEU1				*/
+	faligndata	%f8, %f10, %f54		/*  FPA					*/
+	fcmpgt32	%f32, %f10, %x6		/*  FPM		Group			*/
+	srl		%x2, 1, %x2		/*  IEU0				*/
+	faligndata	%f10, %f12, %f56	/*  FPA					*/
+	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group			*/
+	inc		%x3			/*  IEU0				*/
+	add		%sum, %x2, %sum		/*  IEU1				*/
+	faligndata	%f12, %f14, %f58	/*  FPA					*/
+	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group			*/
+	srl		%x3, 1, %x3		/*  IEU0				*/
+	inc		%x4			/*  IEU1				*/
+	fmovd		%f14, %f60		/*  FPA					*/
+	srl		%x4, 1, %x4		/*  IEU0	Group			*/
+	add		%sum, %x3, %sum		/*  IEU1				*/
+vis1:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
+			,f62,f48,f50,f52,f54,f56,f58,f60,f60,
+			,LDBLK(f32),	,STBLK,,,,,,,
+			,bcs,pn %icc, vis1e1)
+	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+			,f62,f48,f50,f52,f54,f56,f58,f60,f60,
+			,LDBLK(f0),	,STBLK,,,,,,,
+			,bcs,pn %icc, vis1e2)
+	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
+			,f62,f48,f50,f52,f54,f56,f58,f60,f60,
+			,LDBLK(f16),	,STBLK,,,,,,,
+			,bcc,pt %icc, vis1)
+vis1e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
+			,f62,f48,f50,f52,f54,f56,f58,f60,f32,
+			,SYNC,		,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
+			,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e2)
+vis1e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+			,f62,f48,f50,f52,f54,f56,f58,f60,f0,
+			,SYNC,		,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
+			,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e3)
+vis1e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
+			,f62,f48,f50,f52,f54,f56,f58,f60,f16,
+			,SYNC,		,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),
+			,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e1)
+	.align		2048
+vis2s:	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group			*/
+	add		%src, 128 - 16, %src	/*  IEU0	Group			*/
+	ldda		[%src-128] %asi, %f0	/*  Load	Group			*/
+	ldda		[%src-64] %asi, %f16	/*  Load	Group			*/
+	fmovd		%f48, %f0		/*  FPA		Group			*/	
+	sub		%dst, 64, %dst		/*  IEU0				*/
+	fzero		%f2			/*  FPA		Group			*/
+	fcmpgt32	%f32, %f4, %x3		/*  FPM		Group			*/
+	faligndata	%f4, %f6, %f48		/*  FPA					*/
+	fcmpgt32	%f32, %f6, %x4		/*  FPM		Group			*/
+	faligndata	%f6, %f8, %f50		/*  FPA					*/
+	fcmpgt32	%f32, %f8, %x5		/*  FPM		Group			*/
+	faligndata	%f8, %f10, %f52		/*  FPA					*/
+	fcmpgt32	%f32, %f10, %x6		/*  FPM		Group			*/
+	faligndata	%f10, %f12, %f54	/*  FPA					*/
+	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group			*/
+	inc		%x3			/*  IEU0				*/
+	faligndata	%f12, %f14, %f56	/*  FPA					*/
+	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group			*/
+	srl		%x3, 1, %x3		/*  IEU0				*/
+	inc		%x4			/*  IEU1				*/
+	fmovd		%f14, %f58		/*  FPA					*/
+	srl		%x4, 1, %x4		/*  IEU0	Group			*/
+	add		%sum, %x3, %sum		/*  IEU1				*/
+vis2:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
+			,f60,f62,f48,f50,f52,f54,f56,f58,f58,
+			,LDBLK(f32),	,,STBLK,,,,,,
+			,bcs,pn %icc, vis2e1)
+	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+			,f60,f62,f48,f50,f52,f54,f56,f58,f58,
+			,LDBLK(f0),	,,STBLK,,,,,,
+			,bcs,pn %icc, vis2e2)
+	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
+			,f60,f62,f48,f50,f52,f54,f56,f58,f58,
+			,LDBLK(f16),	,,STBLK,,,,,,
+			,bcc,pt %icc, vis2)
+vis2e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
+			,f60,f62,f48,f50,f52,f54,f56,f58,f32,
+			,SYNC,		,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
+			,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e2)
+vis2e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+			,f60,f62,f48,f50,f52,f54,f56,f58,f0,
+			,SYNC,		,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
+			,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e3)
+vis2e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
+			,f60,f62,f48,f50,f52,f54,f56,f58,f16,
+			,SYNC,		,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96),
+			,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e1)
+	.align		2048
+vis3s:	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group			*/
+	add		%src, 128 - 24, %src	/*  IEU0	Group			*/
+	ldda		[%src-128] %asi, %f0	/*  Load	Group			*/
+	ldda		[%src-64] %asi, %f16	/*  Load	Group			*/
+	fmovd		%f48, %f0		/*  FPA		Group			*/
+	sub		%dst, 64, %dst		/*  IEU0				*/
+	fzero		%f2			/*  FPA		Group			*/
+	fzero		%f4			/*  FPA		Group			*/
+	fcmpgt32	%f32, %f6, %x4		/*  FPM		Group			*/
+	faligndata	%f6, %f8, %f48		/*  FPA					*/
+	fcmpgt32	%f32, %f8, %x5		/*  FPM		Group			*/
+	faligndata	%f8, %f10, %f50		/*  FPA					*/
+	fcmpgt32	%f32, %f10, %x6		/*  FPM		Group			*/
+	faligndata	%f10, %f12, %f52	/*  FPA					*/
+	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group			*/
+	faligndata	%f12, %f14, %f54	/*  FPA					*/
+	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group			*/
+	fmovd		%f14, %f56		/*  FPA					*/
+	inc		%x4			/*  IEU0				*/
+	srl		%x4, 1, %x4		/*  IEU0	Group			*/
+vis3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
+			,f58,f60,f62,f48,f50,f52,f54,f56,f56,
+			,LDBLK(f32),	,,,STBLK,,,,,
+			,bcs,pn %icc, vis3e1)
+	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+			,f58,f60,f62,f48,f50,f52,f54,f56,f56,
+			,LDBLK(f0),	,,,STBLK,,,,,
+			,bcs,pn %icc, vis3e2)
+	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
+			,f58,f60,f62,f48,f50,f52,f54,f56,f56,
+			,LDBLK(f16),	,,,STBLK,,,,,
+			,bcc,pt %icc, vis3)
+vis3e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
+			,f58,f60,f62,f48,f50,f52,f54,f56,f32,
+			,SYNC,		,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
+			,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e2)
+vis3e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+			,f58,f60,f62,f48,f50,f52,f54,f56,f0,
+			,SYNC,		,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
+			,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e3)
+vis3e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
+			,f58,f60,f62,f48,f50,f52,f54,f56,f16,
+			,SYNC,		,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),
+			,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e1)
+	.align		2048
+vis4s:	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group			*/
+	add		%src, 128 - 32, %src	/*  IEU0	Group			*/
+	ldda		[%src-128] %asi, %f0	/*  Load	Group			*/
+	ldda		[%src-64] %asi, %f16	/*  Load	Group			*/
+	fmovd		%f48, %f0		/*  FPA		Group			*/
+	sub		%dst, 64, %dst		/*  IEU0				*/
+	fzero		%f2			/*  FPA		Group			*/
+	fzero		%f4			/*  FPA		Group			*/
+	fzero		%f6			/*  FPA		Group			*/
+	clr		%x4			/*  IEU0				*/
+	fcmpgt32	%f32, %f8, %x5		/*  FPM		Group			*/
+	faligndata	%f8, %f10, %f48		/*  FPA					*/
+	fcmpgt32	%f32, %f10, %x6		/*  FPM		Group			*/
+	faligndata	%f10, %f12, %f50	/*  FPA					*/
+	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group			*/
+	faligndata	%f12, %f14, %f52	/*  FPA					*/
+	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group			*/
+	fmovd		%f14, %f54		/*  FPA					*/
+vis4:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
+			,f56,f58,f60,f62,f48,f50,f52,f54,f54,
+			,LDBLK(f32),	,,,,STBLK,,,,
+			,bcs,pn %icc, vis4e1)
+	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+			,f56,f58,f60,f62,f48,f50,f52,f54,f54,
+			,LDBLK(f0),	,,,,STBLK,,,,
+			,bcs,pn %icc, vis4e2)
+	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
+			,f56,f58,f60,f62,f48,f50,f52,f54,f54,
+			,LDBLK(f16),	,,,,STBLK,,,,
+			,bcc,pt %icc, vis4)
+vis4e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
+			,f56,f58,f60,f62,f48,f50,f52,f54,f32,
+			,SYNC,		,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),
+			,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e2)
+vis4e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+			,f56,f58,f60,f62,f48,f50,f52,f54,f0,
+			,SYNC,		,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),
+			,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e3)
+vis4e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
+			,f56,f58,f60,f62,f48,f50,f52,f54,f16,
+			,SYNC,		,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),
+			,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e1)
+	.align		2048
+vis5s:	add		%src, 128 - 40, %src	/*  IEU0	Group			*/
+	ldda		[%src-88] %asi, %f10	/*  Load	Group			*/
+	ldda		[%src-80] %asi, %f12	/*  Load	Group			*/
+	ldda		[%src-72] %asi, %f14	/*  Load	Group			*/
+	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group			*/
+	ldda		[%src-64] %asi, %f16	/*  Load	Group			*/
+	fmovd		%f48, %f0		/*  FPA		Group			*/
+	fmuld		%f32, %f32, %f2		/*  FPM					*/
+	clr		%x4			/*  IEU0				*/
+	faddd		%f32, %f32, %f4		/*  FPA		Group			*/
+	fmuld		%f32, %f32, %f6		/*  FPM					*/
+	clr		%x5			/*  IEU0				*/
+	faddd		%f32, %f32, %f8		/*  FPA		Group			*/
+	fcmpgt32	%f32, %f10, %x6		/*  FPM		Group			*/
+	sub		%dst, 64, %dst		/*  IEU0				*/
+	faligndata	%f10, %f12, %f48	/*  FPA					*/
+	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group			*/
+	faligndata	%f12, %f14, %f50	/*  FPA					*/
+	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group			*/
+	fmovd		%f14, %f52		/*  FPA					*/
+vis5:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
+			,f54,f56,f58,f60,f62,f48,f50,f52,f52,
+			,LDBLK(f32),	,,,,,STBLK,,,
+			,bcs,pn %icc, vis5e1)
+	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+			,f54,f56,f58,f60,f62,f48,f50,f52,f52,
+			,LDBLK(f0),	,,,,,STBLK,,,
+			,bcs,pn %icc, vis5e2)
+	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
+			,f54,f56,f58,f60,f62,f48,f50,f52,f52,
+			,LDBLK(f16),	,,,,,STBLK,,,
+			,bcc,pt %icc, vis5)
+vis5e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
+			,f54,f56,f58,f60,f62,f48,f50,f52,f32,
+			,SYNC,		,,,,,STBLK,ST(f48,64),ST(f50,72),
+			,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e2)
+vis5e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+			,f54,f56,f58,f60,f62,f48,f50,f52,f0,
+			,SYNC,		,,,,,STBLK,ST(f48,64),ST(f50,72),
+			,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e3)
+vis5e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
+			,f54,f56,f58,f60,f62,f48,f50,f52,f16,
+			,SYNC,		,,,,,STBLK,ST(f48,64),ST(f50,72),
+			,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e1)
+	.align		2048
+vis6s:	add		%src, 128 - 48, %src	/*  IEU0	Group			*/
+	ldda		[%src-80] %asi, %f12	/*  Load	Group			*/
+	ldda		[%src-72] %asi, %f14	/*  Load	Group			*/
+	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group			*/
+	ldda		[%src-64] %asi, %f16	/*  Load	Group			*/
+	fmovd		%f48, %f0		/*  FPA		Group			*/
+	fmuld		%f32, %f32, %f2		/*  FPM					*/
+	clr		%x4			/*  IEU0				*/
+	faddd		%f32, %f32, %f4		/*  FPA		Group			*/
+	fmuld		%f32, %f32, %f6		/*  FPM					*/
+	clr		%x5			/*  IEU0				*/
+	faddd		%f32, %f32, %f8		/*  FPA		Group			*/
+	fmuld		%f32, %f32, %f10	/*  FPM					*/
+	clr		%x6			/*  IEU0				*/
+	fcmpgt32	%f32, %f12, %x7		/*  FPM		Group			*/
+	sub		%dst, 64, %dst		/*  IEU0				*/
+	faligndata	%f12, %f14, %f48	/*  FPA					*/
+	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group			*/
+	fmovd		%f14, %f50		/*  FPA					*/
+vis6:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
+			,f52,f54,f56,f58,f60,f62,f48,f50,f50,
+			,LDBLK(f32),	,,,,,,STBLK,,
+			,bcs,pn %icc, vis6e1)
+	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+			,f52,f54,f56,f58,f60,f62,f48,f50,f50,
+			,LDBLK(f0),	,,,,,,STBLK,,
+			,bcs,pn %icc, vis6e2)
+	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
+			,f52,f54,f56,f58,f60,f62,f48,f50,f50,
+			,LDBLK(f16),	,,,,,,STBLK,,
+			,bcc,pt %icc, vis6)
+vis6e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
+			,f52,f54,f56,f58,f60,f62,f48,f50,f32,
+			,SYNC,		,,,,,,STBLK,ST(f48,64),
+			,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e2)
+vis6e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+			,f52,f54,f56,f58,f60,f62,f48,f50,f0,
+			,SYNC,		,,,,,,STBLK,ST(f48,64),
+			,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e3)
+vis6e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
+			,f52,f54,f56,f58,f60,f62,f48,f50,f16,
+			,SYNC,		,,,,,,STBLK,ST(f48,64),
+			,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e1)
+	.align		2048
+vis7s:	add		%src, 128 - 56, %src	/*  IEU0	Group			*/
+	ldda		[%src-72] %asi, %f14	/*  Load	Group			*/
+	wr		%g2, ASI_BLK_XOR, %asi	/*  LSU		Group			*/
+	ldda		[%src-64] %asi, %f16	/*  Load	Group			*/
+	fmovd		%f48, %f0		/*  FPA		Group			*/
+	fmuld		%f32, %f32, %f2		/*  FPM					*/
+	clr		%x4			/*  IEU0				*/
+	faddd		%f32, %f32, %f4		/*  FPA		Group			*/
+	fmuld		%f32, %f32, %f6		/*  FPM					*/
+	clr		%x5			/*  IEU0				*/
+	faddd		%f32, %f32, %f8		/*  FPA		Group			*/
+	fmuld		%f32, %f32, %f10	/*  FPM					*/
+	clr		%x6			/*  IEU0				*/
+	faddd		%f32, %f32, %f12	/*  FPA		Group			*/
+	clr		%x7			/*  IEU0				*/
+	fcmpgt32	%f32, %f14, %x8		/*  FPM		Group			*/
+	sub		%dst, 64, %dst		/*  IEU0				*/
+	fmovd		%f14, %f48		/*  FPA					*/
+vis7:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
+			,f50,f52,f54,f56,f58,f60,f62,f48,f48,
+			,LDBLK(f32),	,,,,,,,STBLK,
+			,bcs,pn %icc, vis7e1)
+	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+			,f50,f52,f54,f56,f58,f60,f62,f48,f48,
+			,LDBLK(f0),	,,,,,,,STBLK,
+			,bcs,pn %icc, vis7e2)
+	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
+			,f50,f52,f54,f56,f58,f60,f62,f48,f48,
+			,LDBLK(f16),	,,,,,,,STBLK,
+			,bcc,pt %icc, vis7)
+vis7e3:	DO_THE_TRICK(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,	
+			,f50,f52,f54,f56,f58,f60,f62,f48,f32,
+			,SYNC,		,,,,,,,STBLK,
+			,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e2)
+vis7e1:	DO_THE_TRICK(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,
+			,f50,f52,f54,f56,f58,f60,f62,f48,f0,
+			,SYNC,		,,,,,,,STBLK,
+			,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e3)
+vis7e2:	DO_THE_TRICK(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14,	
+			,f50,f52,f54,f56,f58,f60,f62,f48,f16,
+			,SYNC,		,,,,,,,STBLK,
+			,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e1)
+e1:	END_THE_TRICK1(	f0,f2,f4,f6,f8,f10,f12,f14,f16,f6)
+e2:	END_THE_TRICK1(	f16,f18,f20,f22,f24,f26,f28,f30,f32,f6)
+e3:	END_THE_TRICK1(	f32,f34,f36,f38,f40,f42,f44,f46,f0,f6)
+ett:	rd		%gsr, %x3		/*  LSU		Group+4bubbles		*/
+	andcc		%x3, 7, %x3		/*  IEU1	Group			*/
+	add		%dst, 8, %dst		/*  IEU0	Group			*/
+	bne,pn		%icc, 1f		/*  CTI					*/
+	 fzero		%f10			/*  FPA					*/
+	brz,a,pn	%len, 2f		/*  CTI+IEU1	Group			*/
+	 std		%f6, [%dst - 8]		/*  Store				*/
+1:	rd		%asi, %x4		/*  LSU		Group+4bubbles		*/
+	sub		%src, 64, %src		/*  IEU0	Group			*/
+	cmp		%len, 8			/*  IEU1				*/
+	blu,pn		%icc, 3f		/*  CTI					*/
+	 wr		%x4, ASI_BLK_XOR, %asi	/*  LSU		Group+4bubbles		*/
+1:	ldda		[%src] %asi, %f2	/*  Load	Group			*/
+	fpadd32		%f10, %f2, %f12		/*  FPA		Group+load stall	*/
+	add		%src, 8, %src		/*  IEU0				*/
+	add		%dst, 8, %dst		/*  IEU1				*/
+	faligndata	%f6, %f2, %f14		/*  FPA		Group			*/
+	fcmpgt32	%f10, %f12, %x5		/*  FPM		Group			*/
+	std		%f14, [%dst - 16]	/*  Store				*/
+	fmovd		%f2, %f6		/*  FPA					*/
+	fmovd		%f12, %f10		/*  FPA		Group			*/
+	sub		%len, 8, %len		/*  IEU1				*/
+	fzero		%f16			/*  FPA		Group - FPU nop		*/
+	fzero		%f18			/*  FPA		Group - FPU nop		*/
+	inc		%x5			/*  IEU0				*/
+	srl		%x5, 1, %x5		/*  IEU0	Group (regdep)		*/
+	cmp		%len, 8			/*  IEU1				*/
+	bgeu,pt		%icc, 1b		/*  CTI					*/
+	 add		%x5, %sum, %sum		/*  IEU0	Group			*/
+3:	brz,a,pt	%x3, 2f			/*  CTI+IEU1				*/
+	 std		%f6, [%dst - 8]		/*  Store	Group			*/
+	st		%f7, [%dst - 8]		/*  Store	Group			*/
+	sub		%dst, 4, %dst		/*  IEU0				*/
+	add		%len, 4, %len		/*  IEU1				*/
+2:
+#ifdef __KERNEL__
+	sub		%sp, 8, %sp		/*  IEU0	Group			*/
+#endif
+	END_THE_TRICK2(	f48,f50,f52,f54,f56,f58,f60,f10,f12,f62)
+	membar		#Sync			/*  LSU		Group			*/
+#ifdef __KERNEL__
+	wr		%g0, 0, %fprs		/*  LSU		Group			*/
+	add		%sp, 8, %sp		/*  IEU0	Group			*/
+#endif
+23:	brnz,pn		%len, 26f		/*  CTI+IEU1	Group			*/
+24:	 sllx		%sum, 32, %g1		/*  IEU0				*/
+25:	addcc		%sum, %g1, %src		/*  IEU1	Group			*/
+	srlx		%src, 32, %src		/*  IEU0	Group (regdep)		*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%src, 1, %src		/*  IEU1				*/
+#ifndef __KERNEL__
+1:	retl					/*  CTI		Group brk forced	*/
+	 srl		%src, 0, %src		/*  IEU0				*/
+#else
+1:	sethi		%uhi(PAGE_OFFSET), %g4	/*  IEU0	Group			*/
+	retl					/*  CTI		Group brk forced	*/
+	 sllx		%g4, 32, %g4		/*  IEU0				*/
+#endif
+26:	andcc		%len, 8, %g0		/*  IEU1	Group			*/
+	be,pn		%icc, 1f		/*  CTI					*/
+	 lduwa		[%src] %asi, %g3	/*  Load				*/
+	lduwa		[%src+4] %asi, %g2	/*  Load	Group			*/
+	add		%src, 8, %src		/*  IEU0				*/
+	add		%dst, 8, %dst		/*  IEU1				*/
+	sllx		%g3, 32, %g5		/*  IEU0	Group			*/
+	stw		%g3, [%dst - 8]		/*  Store				*/
+	or		%g5, %g2, %g5		/*  IEU0	Group			*/
+	stw		%g2, [%dst - 4]		/*  Store				*/
+	addcc		%g5, %sum, %sum		/*  IEU1	Group			*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%sum, 1, %sum		/*  IEU0				*/
+1:	andcc		%len, 4, %g0		/*  IEU1	Group			*/
+	be,a,pn		%icc, 1f		/*  CTI					*/
+	 clr		%g2			/*  IEU0				*/
+	lduwa		[%src] %asi, %g7	/*  Load				*/
+	add		%src, 4, %src		/*  IEU0	Group			*/
+	add		%dst, 4, %dst		/*  IEU1				*/
+	sllx		%g7, 32, %g2		/*  IEU0	Group			*/
+	stw		%g7, [%dst - 4]		/*  Store				*/
+1:	andcc		%len, 2, %g0		/*  IEU1				*/
+	be,a,pn		%icc, 1f		/*  CTI					*/
+	 clr		%o4			/*  IEU0	Group			*/
+	lduha		[%src] %asi, %g7	/*  Load				*/
+	add		%src, 2, %src		/*  IEU1				*/
+	add		%dst, 2, %dst		/*  IEU0	Group			*/
+	sll		%g7, 16, %o4		/*  IEU0	Group			*/
+	sth		%g7, [%dst - 2]		/*  Store				*/
+1:	andcc		%len, 1, %g0		/*  IEU1				*/
+	be,a,pn		%icc, 1f		/*  CTI					*/
+	 clr		%o5			/*  IEU0	Group			*/
+	lduba		[%src] %asi, %g7	/*  Load				*/
+	sll		%g7, 8, %o5		/*  IEU0	Group			*/
+	stb		%g7, [%dst]		/*  Store				*/
+1:	or		%g2, %o4, %o4		/*  IEU1				*/
+	or		%o5, %o4, %o4		/*  IEU0	Group (regdep)		*/
+	addcc		%o4, %sum, %sum		/*  IEU1	Group (regdep)		*/
+	bcs,a,pn	%xcc, 1f		/*  CTI					*/
+	 add		%sum, 1, %sum		/*  IEU0				*/
+1:	ba,pt		%xcc, 25b		/*  CTI		Group			*/
+	 sllx		%sum, 32, %g1		/*  IEU0				*/
+
+#ifdef __KERNEL__
+end:
+
+	.section	__ex_table
+	.align		8
+	.xword		csum_partial_copy_vis, 0, end, cpc_handler
+#endif
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/lib/VISmemset.S linux/arch/sparc64/lib/VISmemset.S
--- v2.1.50/linux/arch/sparc64/lib/VISmemset.S	Mon Jul  7 08:18:55 1997
+++ linux/arch/sparc64/lib/VISmemset.S	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/* $Id: VISmemset.S,v 1.4 1997/07/02 19:00:39 jj Exp $
+/* $Id: VISmemset.S,v 1.6 1997/08/08 08:34:13 jj Exp $
  * VISmemset.S: High speed memset operations utilizing the UltraSparc
  *        Visual Instruction Set.
  *
@@ -172,10 +172,17 @@
 #ifdef __KERNEL__
 	wr		%g0, 0, %fprs
 #endif
-	membar		#Sync
+	membar		#StoreLoad | #StoreStore
 9:	andcc		%o2, 0x78, %g5
 	be,pn		%xcc, 13f
 	 andcc		%o2, 7, %o2
+#ifdef __KERNEL__
+14:	srl		%g5, 1, %o3
+	sethi		%hi(13f), %o4
+	sub		%o4, %o3, %o4
+	jmpl		%o4 + %lo(13f), %g0
+	 add		%o0, %g5, %o0
+#else
 14:	rd		%pc, %o4
 #ifdef REGS_64BIT
 	srl		%g5, 1, %o3
@@ -185,6 +192,7 @@
 #endif
 	jmpl		%o4 + (13f - 14b), %g0
 	 add		%o0, %g5, %o0
+#endif
 12:	SET_BLOCKS(%o0, 0x68, %o1)
 	SET_BLOCKS(%o0, 0x48, %o1)
 	SET_BLOCKS(%o0, 0x28, %o1)
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/lib/blockops.S linux/arch/sparc64/lib/blockops.S
--- v2.1.50/linux/arch/sparc64/lib/blockops.S	Mon Jul  7 08:18:55 1997
+++ linux/arch/sparc64/lib/blockops.S	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/* $Id: blockops.S,v 1.10 1997/06/24 17:29:10 jj Exp $
+/* $Id: blockops.S,v 1.11 1997/07/29 09:35:36 davem Exp $
  * arch/sparc64/lib/blockops.S: UltraSparc block zero optimized routines.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -15,7 +15,7 @@
 	wr		%g0, FPRS_FEF, %fprs		! FPU	Group
 	ldd		[%o1], %f48			! Load	Group
 	wr		%g0, ASI_BLK_P, %asi		! LSU	Group
-	membar		#StoreStore | #LoadStore	! LSU	Group
+	membar		#StoreLoad | #StoreStore | #LoadStore	! LSU	Group
 	mov		32, %g2				! IEU0	Group
 
 	/* Cannot perform real arithmatic on the pattern, that can
@@ -36,7 +36,7 @@
 	subcc		%g2, 1, %g2			! IEU1	Group
 	bne,pt		%icc, 1b			! CTI
 	 add		%o0, 0x100, %o0			! IEU0
-	membar		#Sync				! LSU	Group
+	membar		#StoreLoad | #StoreStore	! LSU	Group
 
 	jmpl		%o7 + 0x8, %g0			! CTI	Group brk forced
 	 wr		%g0, 0, %fprs			! FPU	Group
@@ -56,7 +56,7 @@
 	faddd		%f0, %f2, %f12			! FPA	Group
 	fmuld		%f0, %f2, %f14			! FPM
 	wr		%g0, ASI_BLK_P, %asi		! LSU	Group
-	membar		#StoreStore | #LoadStore	! LSU	Group
+	membar		#StoreLoad | #StoreStore | #LoadStore	! LSU	Group
 1:	stda		%f0, [%o0 + 0x00] %asi		! Store	Group
 	stda		%f0, [%o0 + 0x40] %asi		! Store	Group
 	stda		%f0, [%o0 + 0x80] %asi		! Store	Group
@@ -65,6 +65,6 @@
 	subcc		%g1, 1, %g1			! IEU1
 	bne,pt		%icc, 1b			! CTI
 	 add		%o0, 0x100, %o0			! IEU0	Group
-	membar		#Sync				! LSU	Group
+	membar		#StoreLoad | #StoreStore	! LSU	Group
 	jmpl		%o7 + 0x8, %g0			! CTI	Group brk forced
 	 wr		%g0, 0, %fprs			! FPU	Group
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/lib/checksum.S linux/arch/sparc64/lib/checksum.S
--- v2.1.50/linux/arch/sparc64/lib/checksum.S	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/lib/checksum.S	Sat Aug 16 10:00:22 1997
@@ -23,456 +23,456 @@
 	 * are two fold.  Firstly, they cannot pair with jack shit,
 	 * and also they only add in the 32-bit carry condition bit
 	 * into the accumulated sum.  The following is much better.
-	 *
-	 * This should run at max bandwidth for ecache hits, a better
-	 * technique is to use VIS and fpu operations. This is already
-	 * done for csum_partial, needs to be written for the copy stuff
-	 * still.
+	 * For larger chunks we use VIS code, which is faster ;)
 	 */
 
-	.text
-	.globl __csum_partial_copy_start, __csum_partial_copy_end
-__csum_partial_copy_start:
+#define src o0
+#define dst o1
+#define len o2
+#define sum o3
 
+	.text
 	/* I think I have an erection...  Once _AGAIN_ the SunSoft
 	 * engineers are caught asleep at the keyboard, tsk tsk...
 	 */
-#define CSUMCOPY_ECACHE_LOAD(src, off, t0, t1, t2, t3, t4, t5, t6, t7)			\
-	ldxa		[src + off + 0x00] %asi, t0;					\
-	ldxa		[src + off + 0x08] %asi, t1;					\
-	ldxa		[src + off + 0x10] %asi, t2;					\
-	ldxa		[src + off + 0x18] %asi, t3;					\
-	ldxa		[src + off + 0x20] %asi, t4;					\
-	ldxa		[src + off + 0x28] %asi, t5;					\
-	ldxa		[src + off + 0x30] %asi, t6;					\
-	ldxa		[src + off + 0x38] %asi, t7;					\
+#define CSUMCOPY_ECACHE_LOAD(off, t0, t1, t2, t3, t4, t5, t6, t7)			\
+	ldxa		[%src + off + 0x00] %asi, t0;					\
+	ldxa		[%src + off + 0x08] %asi, t1;					\
+	ldxa		[%src + off + 0x10] %asi, t2;					\
+	ldxa		[%src + off + 0x18] %asi, t3;					\
+	ldxa		[%src + off + 0x20] %asi, t4;					\
+	ldxa		[%src + off + 0x28] %asi, t5;					\
+	ldxa		[%src + off + 0x30] %asi, t6;					\
+	ldxa		[%src + off + 0x38] %asi, t7;					\
 	nop; nop; /* DO NOT TOUCH THIS!!!!! */
 
-#define CSUMCOPY_EC_STALIGNED_LDNXT(src, dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7)\
-	stx		t0, [dest + off - 0x40];					\
-	addcc		sum, t0, sum;							\
+#define CSUMCOPY_EC_STALIGNED_LDNXT(off, t0, t1, t2, t3, t4, t5, t6, t7)		\
+	stx		t0, [%dst + off - 0x40];					\
+	addcc		%sum, t0, %sum;							\
 	bcc,pt		%xcc, 11f;							\
-	 ldxa		[src + off + 0x00] %asi, t0;					\
-	add		sum, 1, sum;							\
-11:	stx		t1, [dest + off - 0x38];					\
-	addcc		sum, t1, sum;							\
+	 ldxa		[%src + off + 0x00] %asi, t0;					\
+	add		%sum, 1, %sum;							\
+11:	stx		t1, [%dst + off - 0x38];					\
+	addcc		%sum, t1, %sum;							\
 	bcc,pt		%xcc, 12f;							\
-	 ldxa		[src + off + 0x08] %asi, t1;					\
-	add		sum, 1, sum;							\
-12:	stx		t2, [dest + off - 0x30];					\
-	addcc		sum, t2, sum;							\
+	 ldxa		[%src + off + 0x08] %asi, t1;					\
+	add		%sum, 1, %sum;							\
+12:	stx		t2, [%dst + off - 0x30];					\
+	addcc		%sum, t2, %sum;							\
 	bcc,pt		%xcc, 13f;							\
-	 ldxa		[src + off + 0x10] %asi, t2;					\
-	add		sum, 1, sum;							\
-13:	stx		t3, [dest + off - 0x28];					\
-	addcc		sum, t3, sum;							\
+	 ldxa		[%src + off + 0x10] %asi, t2;					\
+	add		%sum, 1, %sum;							\
+13:	stx		t3, [%dst + off - 0x28];					\
+	addcc		%sum, t3, %sum;							\
 	bcc,pt		%xcc, 14f;							\
-	 ldxa		[src + off + 0x18] %asi, t3;					\
-	add		sum, 1, sum;							\
-14:	stx		t4, [dest + off - 0x20];					\
-	addcc		sum, t4, sum;							\
+	 ldxa		[%src + off + 0x18] %asi, t3;					\
+	add		%sum, 1, %sum;							\
+14:	stx		t4, [%dst + off - 0x20];					\
+	addcc		%sum, t4, %sum;							\
 	bcc,pt		%xcc, 15f;							\
-	 ldxa		[src + off + 0x20] %asi, t4;					\
-	add		sum, 1, sum;							\
-15:	stx		t5, [dest + off - 0x18];					\
-	addcc		sum, t5, sum;							\
+	 ldxa		[%src + off + 0x20] %asi, t4;					\
+	add		%sum, 1, %sum;							\
+15:	stx		t5, [%dst + off - 0x18];					\
+	addcc		%sum, t5, %sum;							\
 	bcc,pt		%xcc, 16f;							\
-	 ldxa		[src + off + 0x28] %asi, t5;					\
-	add		sum, 1, sum;							\
-16:	stx		t6, [dest + off - 0x10];					\
-	addcc		sum, t6, sum;							\
+	 ldxa		[%src + off + 0x28] %asi, t5;					\
+	add		%sum, 1, %sum;							\
+16:	stx		t6, [%dst + off - 0x10];					\
+	addcc		%sum, t6, %sum;							\
 	bcc,pt		%xcc, 17f;							\
-	 ldxa		[src + off + 0x30] %asi, t6;					\
-	add		sum, 1, sum;							\
-17:	stx		t7, [dest + off - 0x08];					\
-	addcc		sum, t7, sum;							\
+	 ldxa		[%src + off + 0x30] %asi, t6;					\
+	add		%sum, 1, %sum;							\
+17:	stx		t7, [%dst + off - 0x08];					\
+	addcc		%sum, t7, %sum;							\
 	bcc,pt		%xcc, 18f;							\
-	 ldxa		[src + off + 0x38] %asi, t7;					\
-	add		sum, 1, sum;							\
+	 ldxa		[%src + off + 0x38] %asi, t7;					\
+	add		%sum, 1, %sum;							\
 18:
 
-#define CSUMCOPY_EC_STUNALIGN_LDNXT(src, dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7)\
-	stw		t0, [dest + off - 0x3c];					\
-	addcc		sum, t0, sum;							\
+#define CSUMCOPY_EC_STUNALIGN_LDNXT(off, t0, t1, t2, t3, t4, t5, t6, t7)		\
+	stw		t0, [%dst + off - 0x3c];					\
+	addcc		%sum, t0, %sum;							\
 	srlx		t0, 32, t0;							\
-	stw		t0, [dest + off - 0x40];					\
+	stw		t0, [%dst + off - 0x40];					\
 	bcc,pt		%xcc, 21f;							\
-	 ldxa		[src + off + 0x00] %asi, t0;					\
-	add		sum, 1, sum;							\
-21:	stw		t1, [dest + off - 0x34];					\
-	addcc		sum, t1, sum;							\
+	 ldxa		[%src + off + 0x00] %asi, t0;					\
+	add		%sum, 1, %sum;							\
+21:	stw		t1, [%dst + off - 0x34];					\
+	addcc		%sum, t1, %sum;							\
 	srlx		t1, 32, t1;							\
-	stw		t1, [dest + off - 0x38];					\
+	stw		t1, [%dst + off - 0x38];					\
 	bcc,pt		%xcc, 22f;							\
-	 ldxa		[src + off + 0x08] %asi, t1;					\
-	add		sum, 1, sum;							\
-22:	stw		t2, [dest + off - 0x2c];					\
-	addcc		sum, t2, sum;							\
+	 ldxa		[%src + off + 0x08] %asi, t1;					\
+	add		%sum, 1, %sum;							\
+22:	stw		t2, [%dst + off - 0x2c];					\
+	addcc		%sum, t2, %sum;							\
 	srlx		t2, 32, t2;							\
-	stw		t2, [dest + off - 0x30];					\
+	stw		t2, [%dst + off - 0x30];					\
 	bcc,pt		%xcc, 23f;							\
-	 ldxa		[src + off + 0x10] %asi, t2;					\
-	add		sum, 1, sum;							\
-23:	stw		t3, [dest + off - 0x24];					\
-	addcc		sum, t3, sum;							\
+	 ldxa		[%src + off + 0x10] %asi, t2;					\
+	add		%sum, 1, %sum;							\
+23:	stw		t3, [%dst + off - 0x24];					\
+	addcc		%sum, t3, %sum;							\
 	srlx		t3, 32, t3;							\
-	stw		t3, [dest + off - 0x28];					\
+	stw		t3, [%dst + off - 0x28];					\
 	bcc,pt		%xcc, 24f;							\
-	 ldxa		[src + off + 0x18] %asi, t3;					\
-	add		sum, 1, sum;							\
-24:	stw		t4, [dest + off - 0x1c];					\
-	addcc		sum, t4, sum;							\
+	 ldxa		[%src + off + 0x18] %asi, t3;					\
+	add		%sum, 1, %sum;							\
+24:	stw		t4, [%dst + off - 0x1c];					\
+	addcc		%sum, t4, %sum;							\
 	srlx		t4, 32, t4;							\
-	stw		t4, [dest + off - 0x20];					\
+	stw		t4, [%dst + off - 0x20];					\
 	bcc,pt		%xcc, 25f;							\
-	 ldxa		[src + off + 0x20] %asi, t4;					\
-	add		sum, 1, sum;							\
-25:	stw		t5, [dest + off - 0x14];					\
-	addcc		sum, t5, sum;							\
+	 ldxa		[%src + off + 0x20] %asi, t4;					\
+	add		%sum, 1, %sum;							\
+25:	stw		t5, [%dst + off - 0x14];					\
+	addcc		%sum, t5, %sum;							\
 	srlx		t5, 32, t5;							\
-	stw		t5, [dest + off - 0x18];					\
+	stw		t5, [%dst + off - 0x18];					\
 	bcc,pt		%xcc, 26f;							\
-	 ldxa		[src + off + 0x28] %asi, t5;					\
-	add		sum, 1, sum;							\
-26:	stw		t6, [dest + off - 0x0c];					\
-	addcc		sum, t6, sum;							\
+	 ldxa		[%src + off + 0x28] %asi, t5;					\
+	add		%sum, 1, %sum;							\
+26:	stw		t6, [%dst + off - 0x0c];					\
+	addcc		%sum, t6, %sum;							\
 	srlx		t6, 32, t6;							\
-	stw		t6, [dest + off - 0x10];					\
+	stw		t6, [%dst + off - 0x10];					\
 	bcc,pt		%xcc, 27f;							\
-	 ldxa		[src + off + 0x30] %asi, t6;					\
-	add		sum, 1, sum;							\
-27:	stw		t7, [dest + off - 0x04];					\
-	addcc		sum, t7, sum;							\
+	 ldxa		[%src + off + 0x30] %asi, t6;					\
+	add		%sum, 1, %sum;							\
+27:	stw		t7, [%dst + off - 0x04];					\
+	addcc		%sum, t7, %sum;							\
 	srlx		t7, 32, t7;							\
-	stw		t7, [dest + off - 0x08];					\
+	stw		t7, [%dst + off - 0x08];					\
 	bcc,pt		%xcc, 28f;							\
-	 ldxa		[src + off + 0x38] %asi, t7;					\
-	add		sum, 1, sum;							\
+	 ldxa		[%src + off + 0x38] %asi, t7;					\
+	add		%sum, 1, %sum;							\
 28:
 
-#define CSUMCOPY_EC_STALIGNED(dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7)		\
-	addcc		sum, t0, sum;							\
+#define CSUMCOPY_EC_STALIGNED(off, t0, t1, t2, t3, t4, t5, t6, t7)			\
+	addcc		%sum, t0, %sum;							\
 	bcc,pt		%xcc, 31f;							\
-	 stx		t0, [dest + off + 0x00];					\
-	add		sum, 1, sum;							\
-31:	addcc		sum, t1, sum;							\
+	 stx		t0, [%dst + off + 0x00];					\
+	add		%sum, 1, %sum;							\
+31:	addcc		%sum, t1, %sum;							\
 	bcc,pt		%xcc, 32f;							\
-	 stx		t1, [dest + off + 0x08];					\
-	add		sum, 1, sum;							\
-32:	addcc		sum, t2, sum;							\
+	 stx		t1, [%dst + off + 0x08];					\
+	add		%sum, 1, %sum;							\
+32:	addcc		%sum, t2, %sum;							\
 	bcc,pt		%xcc, 33f;							\
-	 stx		t2, [dest + off + 0x10];					\
-	add		sum, 1, sum;							\
-33:	addcc		sum, t3, sum;							\
+	 stx		t2, [%dst + off + 0x10];					\
+	add		%sum, 1, %sum;							\
+33:	addcc		%sum, t3, %sum;							\
 	bcc,pt		%xcc, 34f;							\
-	 stx		t3, [dest + off + 0x18];					\
-	add		sum, 1, sum;							\
-34:	addcc		sum, t4, sum;							\
+	 stx		t3, [%dst + off + 0x18];					\
+	add		%sum, 1, %sum;							\
+34:	addcc		%sum, t4, %sum;							\
 	bcc,pt		%xcc, 35f;							\
-	 stx		t4, [dest + off + 0x20];					\
-	add		sum, 1, sum;							\
-35:	addcc		sum, t5, sum;							\
+	 stx		t4, [%dst + off + 0x20];					\
+	add		%sum, 1, %sum;							\
+35:	addcc		%sum, t5, %sum;							\
 	bcc,pt		%xcc, 36f;							\
-	 stx		t5, [dest + off + 0x28];					\
-	add		sum, 1, sum;							\
-36:	addcc		sum, t6, sum;							\
+	 stx		t5, [%dst + off + 0x28];					\
+	add		%sum, 1, %sum;							\
+36:	addcc		%sum, t6, %sum;							\
 	bcc,pt		%xcc, 37f;							\
-	 stx		t6, [dest + off + 0x30];					\
-	add		sum, 1, sum;							\
-37:	addcc		sum, t7, sum;							\
+	 stx		t6, [%dst + off + 0x30];					\
+	add		%sum, 1, %sum;							\
+37:	addcc		%sum, t7, %sum;							\
 	bcc,pt		%xcc, 38f;							\
-	 stx		t7, [dest + off + 0x38];					\
-	add		sum, 1, sum;							\
+	 stx		t7, [%dst + off + 0x38];					\
+	add		%sum, 1, %sum;							\
 38:
 
-#define CSUMCOPY_EC_STUNALIGN(dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7)		\
-	stw		t0, [dest + off + 0x04];					\
-	addcc		sum, t0, sum;							\
+#define CSUMCOPY_EC_STUNALIGN(off, t0, t1, t2, t3, t4, t5, t6, t7)			\
+	stw		t0, [%dst + off + 0x04];					\
+	addcc		%sum, t0, %sum;							\
 	srlx		t0, 32, t0;							\
 	bcc,pt		%xcc, 41f;							\
-	 stw		t0, [dest + off + 0x00];					\
-	add		sum, 1, sum;							\
-41:	stw		t1, [dest + off + 0x0c];					\
-	addcc		sum, t1, sum;							\
+	 stw		t0, [%dst + off + 0x00];					\
+	add		%sum, 1, %sum;							\
+41:	stw		t1, [%dst + off + 0x0c];					\
+	addcc		%sum, t1, %sum;							\
 	srlx		t1, 32, t1;							\
 	bcc,pt		%xcc, 42f;							\
-	 stw		t1, [dest + off + 0x08];					\
-	add		sum, 1, sum;							\
-42:	stw		t2, [dest + off + 0x14];					\
-	addcc		sum, t2, sum;							\
+	 stw		t1, [%dst + off + 0x08];					\
+	add		%sum, 1, %sum;							\
+42:	stw		t2, [%dst + off + 0x14];					\
+	addcc		%sum, t2, %sum;							\
 	srlx		t2, 32, t2;							\
 	bcc,pt		%xcc, 43f;							\
-	 stw		t2, [dest + off + 0x10];					\
-	add		sum, 1, sum;							\
-43:	stw		t3, [dest + off + 0x1c];					\
-	addcc		sum, t3, sum;							\
+	 stw		t2, [%dst + off + 0x10];					\
+	add		%sum, 1, %sum;							\
+43:	stw		t3, [%dst + off + 0x1c];					\
+	addcc		%sum, t3, %sum;							\
 	srlx		t3, 32, t3;							\
 	bcc,pt		%xcc, 44f;							\
-	 stw		t3, [dest + off + 0x18];					\
-	add		sum, 1, sum;							\
-44:	stw		t4, [dest + off + 0x24];					\
-	addcc		sum, t4, sum;							\
+	 stw		t3, [%dst + off + 0x18];					\
+	add		%sum, 1, %sum;							\
+44:	stw		t4, [%dst + off + 0x24];					\
+	addcc		%sum, t4, %sum;							\
 	srlx		t4, 32, t4;							\
 	bcc,pt		%xcc, 45f;							\
-	 stw		t4, [dest + off + 0x20];					\
-	add		sum, 1, sum;							\
-45:	stw		t5, [dest + off + 0x2c];					\
-	addcc		sum, t5, sum;							\
+	 stw		t4, [%dst + off + 0x20];					\
+	add		%sum, 1, %sum;							\
+45:	stw		t5, [%dst + off + 0x2c];					\
+	addcc		%sum, t5, %sum;							\
 	srlx		t5, 32, t5;							\
 	bcc,pt		%xcc, 46f;							\
-	 stw		t5, [dest + off + 0x28];					\
-	add		sum, 1, sum;							\
-46:	stw		t6, [dest + off + 0x34];					\
-	addcc		sum, t6, sum;							\
+	 stw		t5, [%dst + off + 0x28];					\
+	add		%sum, 1, %sum;							\
+46:	stw		t6, [%dst + off + 0x34];					\
+	addcc		%sum, t6, %sum;							\
 	srlx		t6, 32, t6;							\
 	bcc,pt		%xcc, 47f;							\
-	 stw		t6, [dest + off + 0x30];					\
-	add		sum, 1, sum;							\
-47:	stw		t7, [dest + off + 0x3c];					\
-	addcc		sum, t7, sum;							\
+	 stw		t6, [%dst + off + 0x30];					\
+	add		%sum, 1, %sum;							\
+47:	stw		t7, [%dst + off + 0x3c];					\
+	addcc		%sum, t7, %sum;							\
 	srlx		t7, 32, t7;							\
 	bcc,pt		%xcc, 48f;							\
-	 stw		t7, [dest + off + 0x38];					\
-	add		sum, 1, sum;							\
+	 stw		t7, [%dst + off + 0x38];					\
+	add		%sum, 1, %sum;							\
 48:
 
-#define CSUMCOPY_LASTCHUNK(src, dst, sum, off, t0, t1)					\
-	ldxa		[src - off - 0x08] %asi, t0;					\
-	ldxa		[src - off - 0x00] %asi, t1;					\
+#define CSUMCOPY_LASTCHUNK(off, t0, t1)							\
+	ldxa		[%src - off - 0x08] %asi, t0;					\
+	ldxa		[%src - off - 0x00] %asi, t1;					\
 	nop; nop;									\
-	addcc		t0, sum, sum;							\
-	stw		t0, [dst - off - 0x04];						\
+	addcc		t0, %sum, %sum;							\
+	stw		t0, [%dst - off - 0x04];					\
 	srlx		t0, 32, t0;							\
 	bcc,pt		%xcc, 51f;							\
-	 stw		t0, [dst - off - 0x08];						\
-	add		sum, 1, sum;							\
-51:	addcc		t1, sum, sum;							\
-	stw		t1, [dst - off + 0x04];						\
+	 stw		t0, [%dst - off - 0x08];					\
+	add		%sum, 1, %sum;							\
+51:	addcc		t1, %sum, %sum;							\
+	stw		t1, [%dst - off + 0x04];					\
 	srlx		t1, 32, t1;							\
 	bcc,pt		%xcc, 52f;							\
-	 stw		t1, [dst - off - 0x00];						\
-	add		sum, 1, sum;							\
+	 stw		t1, [%dst - off - 0x00];					\
+	add		%sum, 1, %sum;							\
 52:
 
+cpc_start:
 cc_end_cruft:
-	andcc		%o3, 8, %g0		! IEU1	Group
+	andcc		%g7, 8, %g0		! IEU1	Group
 	be,pn		%icc, 1f		! CTI
-	 and		%o3, 4, %g5		! IEU0
-	ldxa		[%o0 + 0x00] %asi, %g2	! Load	Group
-	add		%o1, 8, %o1		! IEU0
-	add		%o0, 8, %o0		! IEU1
-	addcc		%g2, %g7, %g7		! IEU1	Group + 2 bubbles
-	stw		%g2, [%o1 - 0x04]	! Store
+	 and		%g7, 4, %g5		! IEU0
+	ldxa		[%src + 0x00] %asi, %g2	! Load	Group
+	add		%dst, 8, %dst		! IEU0
+	add		%src, 8, %src		! IEU1
+	addcc		%g2, %sum, %sum		! IEU1	Group + 2 bubbles
+	stw		%g2, [%dst - 0x04]	! Store
 	srlx		%g2, 32, %g2		! IEU0
 	bcc,pt		%xcc, 1f		! CTI	Group
-	 stw		%g2, [%o1 - 0x08]	! Store
-	add		%g7, 1, %g7		! IEU0
+	 stw		%g2, [%dst - 0x08]	! Store
+	add		%sum, 1, %sum		! IEU0
 1:	brz,pt		%g5, 1f			! CTI	Group
 	 clr		%g2			! IEU0
-	lduwa		[%o0 + 0x00] %asi, %g2	! Load
-	add		%o1, 4, %o1		! IEU0	Group
-	add		%o0, 4, %o0		! IEU1
-	stw		%g2, [%o1 - 0x04]	! Store	Group + 2 bubbles
+	lduwa		[%src + 0x00] %asi, %g2	! Load
+	add		%dst, 4, %dst		! IEU0	Group
+	add		%src, 4, %src		! IEU1
+	stw		%g2, [%dst - 0x04]	! Store	Group + 2 bubbles
 	sllx		%g2, 32, %g2		! IEU0
-1:	andcc		%o3, 2, %g0		! IEU1
+1:	andcc		%g7, 2, %g0		! IEU1
 	be,pn		%icc, 1f		! CTI	Group
 	 clr		%o4			! IEU1
-	lduha		[%o0 + 0x00] %asi, %o4	! Load
-	add		%o0, 2, %o0		! IEU0	Group
-	add		%o1, 2, %o1		! IEU1
-	sth		%o4, [%o1 - 0x2]	! Store Group + 2 bubbles
+	lduha		[%src + 0x00] %asi, %o4	! Load
+	add		%src, 2, %src		! IEU0	Group
+	add		%dst, 2, %dst		! IEU1
+	sth		%o4, [%dst - 0x2]	! Store Group + 2 bubbles
 	sll		%o4, 16, %o4		! IEU0
-1:	andcc		%o3, 1, %g0		! IEU1
+1:	andcc		%g7, 1, %g0		! IEU1
 	be,pn		%icc, 1f		! CTI	Group
 	 clr		%o5			! IEU0
-	lduba		[%o0 + 0x00] %asi, %o5	! Load
-	stb		%o5, [%o1 + 0x00]	! Store	Group + 2 bubbles
+	lduba		[%src + 0x00] %asi, %o5	! Load
+	stb		%o5, [%dst + 0x00]	! Store	Group + 2 bubbles
 	sll		%o5, 8, %o5		! IEU0
 1:	or		%g2, %o4, %o4		! IEU1
 	or		%o5, %o4, %o4		! IEU0	Group
-	addcc		%o4, %g7, %g7		! IEU1
+	addcc		%o4, %sum, %sum		! IEU1
 	bcc,pt		%xcc, ccfold		! CTI
 	 sethi		%uhi(PAGE_OFFSET), %g4	! IEU0	Group
 	b,pt		%xcc, ccfold		! CTI
-	 add		%g7, 1, %g7		! IEU1
+	 add		%sum, 1, %sum		! IEU1
 
 cc_fixit:
 	bl,a,pn		%icc, ccte		! CTI
-	 andcc		%g1, 0xf, %o3		! IEU1	Group
-	andcc		%o0, 1, %g0		! IEU1	Group
-	bne,pn		%icc, ccslow		! CTI
-	 andcc		%o0, 2, %g0		! IEU1	Group
+	 andcc		%len, 0xf, %g7		! IEU1	Group
+	andcc		%src, 2, %g0		! IEU1	Group
 	be,pn		%icc, 1f		! CTI
-	 andcc		%o0, 0x4, %g0		! IEU1	Group
-	lduha		[%o0 + 0x00] %asi, %g4	! Load
-	sub		%g1, 2, %g1		! IEU0
-	add		%o0, 2, %o0		! IEU0	Group
-	add		%o1, 2, %o1		! IEU1
+	 andcc		%src, 0x4, %g0		! IEU1	Group
+	lduha		[%src + 0x00] %asi, %g4	! Load
+	sub		%len, 2, %len		! IEU0
+	add		%src, 2, %src		! IEU0	Group
+	add		%dst, 2, %dst		! IEU1
 	sll		%g4, 16, %g3		! IEU0	Group + 1 bubble
-	addcc		%g3, %g7, %g7		! IEU1
+	addcc		%g3, %sum, %sum		! IEU1
 	bcc,pt		%xcc, 0f		! CTI
-	 srl		%g7, 16, %g3		! IEU0	Group
+	 srl		%sum, 16, %g3		! IEU0	Group
 	add		%g3, 1, %g3		! IEU0	4 clocks (mispredict)
-0:	andcc		%o0, 0x4, %g0		! IEU1	Group
-	sth		%g4, [%o1 - 0x2]	! Store
-	sll		%g7, 16, %g7		! IEU0
+0:	andcc		%src, 0x4, %g0		! IEU1	Group
+	sth		%g4, [%dst - 0x2]	! Store
+	sll		%sum, 16, %sum		! IEU0
 	sll		%g3, 16, %g3		! IEU0	Group
-	srl		%g7, 16, %g7		! IEU0	Group
-	or		%g3, %g7, %g7		! IEU0	Group (regdep)
+	srl		%sum, 16, %sum		! IEU0	Group
+	or		%g3, %sum, %sum		! IEU0	Group (regdep)
 1:	be,pt		%icc, cc_dword_aligned	! CTI
-	 andn		%g1, 0xff, %g2		! IEU1
-	lduwa		[%o0 + 0x00] %asi, %g4	! Load	Group
-	sub		%g1, 4, %g1		! IEU0
-	add		%o0, 4, %o0		! IEU1
-	add		%o1, 4, %o1		! IEU0	Group
-	addcc		%g4, %g7, %g7		! IEU1	Group + 1 bubble
-	stw		%g4, [%o1 - 0x4]	! Store
+	 andn		%len, 0xff, %g2		! IEU1
+	lduwa		[%src + 0x00] %asi, %g4	! Load	Group
+	sub		%len, 4, %len		! IEU0
+	add		%src, 4, %src		! IEU1
+	add		%dst, 4, %dst		! IEU0	Group
+	addcc		%g4, %sum, %sum		! IEU1	Group + 1 bubble
+	stw		%g4, [%dst - 0x4]	! Store
 	bcc,pt		%xcc, cc_dword_aligned	! CTI
-	 andn		%g1, 0xff, %g2		! IEU0	Group
+	 andn		%len, 0xff, %g2		! IEU0	Group
 	b,pt		%xcc, cc_dword_aligned	! CTI	4 clocks (mispredict)
-	 add		%g7, 1, %g7		! IEU0
+	 add		%sum, 1, %sum		! IEU0
 
 	.align		32
-	.globl		__csum_partial_copy_sparc_generic, csum_partial_copy
-csum_partial_copy:
-__csum_partial_copy_sparc_generic:		/* %o0=src, %o1=dest, %g1=len, %g7=sum */
-	xorcc		%o0, %o1, %o4		! IEU1	Group
-	srl		%g7, 0, %g7		! IEU0
+	.globl		csum_partial_copy_sparc64
+csum_partial_copy_sparc64:			/* %o0=src, %o1=dest, %o2=len, %o3=sum */
+	xorcc		%src, %dst, %o4		! IEU1	Group
+	srl		%sum, 0, %sum		! IEU0
 	andcc		%o4, 3, %g0		! IEU1	Group
-	srl		%g1, 0, %g1		! IEU0
+	srl		%len, 0, %len		! IEU0
 	bne,pn		%icc, ccslow		! CTI
-	 andcc		%o0, 7, %g0		! IEU1	Group
+	 andcc		%src, 1, %g0		! IEU1	Group
+	bne,pn		%icc, ccslow		! CTI
+	 cmp		%len, 256		! IEU1	Group
+	bgeu,pt		%icc, csum_partial_copy_vis ! CTI
+	 andcc		%src, 7, %g0		! IEU1	Group
 	be,pt		%icc, cc_dword_aligned	! CTI
-	 andn		%g1, 0xff, %g2		! IEU0
+	 andn		%len, 0xff, %g2		! IEU0
 	b,pt		%xcc, cc_fixit		! CTI	Group
-	 cmp		%g1, 6			! IEU1
+	 cmp		%len, 6			! IEU1
 cc_dword_aligned:
 	brz,pn		%g2, 3f			! CTI	Group
-	 andcc		%o1, 4, %g0		! IEU1	Group (brz uses IEU1)
+	 andcc		%dst, 4, %g0		! IEU1	Group (brz uses IEU1)
 	be,pn		%icc, ccdbl + 4		! CTI
-5:	CSUMCOPY_ECACHE_LOAD(       %o0,    0x00,    %o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-	CSUMCOPY_EC_STUNALIGN_LDNXT(%o0,%o1,0x40,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-	CSUMCOPY_EC_STUNALIGN_LDNXT(%o0,%o1,0x80,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-	CSUMCOPY_EC_STUNALIGN_LDNXT(%o0,%o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-	CSUMCOPY_EC_STUNALIGN(          %o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+5:	CSUMCOPY_ECACHE_LOAD(       0x00,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+	CSUMCOPY_EC_STUNALIGN_LDNXT(0x40,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+	CSUMCOPY_EC_STUNALIGN_LDNXT(0x80,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+	CSUMCOPY_EC_STUNALIGN_LDNXT(0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+	CSUMCOPY_EC_STUNALIGN(      0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
 10:
-	sub		%g1, 256, %g1		! IEU0	Group
-	add		%o0, 256, %o0		! IEU1
-	andncc		%g1, 0xff, %g0		! IEU1	Group
+	sub		%len, 256, %len		! IEU0	Group
+	add		%src, 256, %src		! IEU1
+	andncc		%len, 0xff, %g0		! IEU1	Group
 	bne,pt		%icc, 5b		! CTI
-	 add		%o1, 256, %o1		! IEU0
-3:	andcc		%g1, 0xf0, %o2		! IEU1	Group
+	 add		%dst, 256, %dst		! IEU0
+3:	andcc		%len, 0xf0, %g1		! IEU1	Group
 ccmerge:be,pn		%icc, ccte		! CTI
-	 andcc		%g1, 0xf, %o3		! IEU1	Group
-	sll		%o2, 2, %o4		! IEU0
-13:	rd		%pc, %o5		! LSU	Group + 4 clocks
-	add		%o0, %o2, %o0		! IEU0	Group
-	sub		%o5, %o4, %o5		! IEU1	Group
-	jmpl		%o5 + (12f - 13b), %g0	! CTI	Group brk forced
-	 add		%o1, %o2, %o1		! IEU0	Group
-cctbl:	CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xe8,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xd8,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xc8,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xb8,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xa8,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x98,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x88,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x78,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x68,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x58,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x48,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x38,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x28,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x18,%g2,%g3)
-	CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x08,%g2,%g3)
+	 andcc		%len, 0xf, %g7		! IEU1	Group
+	sll		%g1, 2, %o4		! IEU0
+13:	sethi		%hi(12f), %o5		! IEU0	Group
+	add		%src, %g1, %src		! IEU1	
+	sub		%o5, %o4, %o5		! IEU0	Group
+	jmpl		%o5 + %lo(12f), %g0	! CTI	Group brk forced
+	 add		%dst, %g1, %dst		! IEU0	Group
+cctbl:	CSUMCOPY_LASTCHUNK(0xe8,%g2,%g3)
+	CSUMCOPY_LASTCHUNK(0xd8,%g2,%g3)
+	CSUMCOPY_LASTCHUNK(0xc8,%g2,%g3)
+	CSUMCOPY_LASTCHUNK(0xb8,%g2,%g3)
+	CSUMCOPY_LASTCHUNK(0xa8,%g2,%g3)
+	CSUMCOPY_LASTCHUNK(0x98,%g2,%g3)
+	CSUMCOPY_LASTCHUNK(0x88,%g2,%g3)
+	CSUMCOPY_LASTCHUNK(0x78,%g2,%g3)
+	CSUMCOPY_LASTCHUNK(0x68,%g2,%g3)
+	CSUMCOPY_LASTCHUNK(0x58,%g2,%g3)
+	CSUMCOPY_LASTCHUNK(0x48,%g2,%g3)
+	CSUMCOPY_LASTCHUNK(0x38,%g2,%g3)
+	CSUMCOPY_LASTCHUNK(0x28,%g2,%g3)
+	CSUMCOPY_LASTCHUNK(0x18,%g2,%g3)
+	CSUMCOPY_LASTCHUNK(0x08,%g2,%g3)
 12:
-	andcc		%g1, 0xf, %o3		! IEU1	Group
+	andcc		%len, 0xf, %g7		! IEU1	Group
 ccte:	bne,pn		%icc, cc_end_cruft	! CTI
 	 sethi		%uhi(PAGE_OFFSET), %g4	! IEU0
-ccfold:	sllx		%g7, 32, %o0		! IEU0	Group
-	addcc		%g7, %o0, %o0		! IEU1	Group (regdep)
+ccfold:	sllx		%sum, 32, %o0		! IEU0	Group
+	addcc		%sum, %o0, %o0		! IEU1	Group (regdep)
 	srlx		%o0, 32, %o0		! IEU0	Group (regdep)
 	bcs,a,pn	%xcc, 1f		! CTI
 	 add		%o0, 1, %o0		! IEU1	4 clocks (mispredict)
 1:	retl					! CTI	Group brk forced
 	 sllx		%g4, 32,%g4		! IEU0	Group
-ccdbl:	CSUMCOPY_ECACHE_LOAD(       %o0,    0x00,    %o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-	CSUMCOPY_EC_STALIGNED_LDNXT(%o0,%o1,0x40,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-	CSUMCOPY_EC_STALIGNED_LDNXT(%o0,%o1,0x80,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-	CSUMCOPY_EC_STALIGNED_LDNXT(%o0,%o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
-	CSUMCOPY_EC_STALIGNED(          %o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
+ccdbl:	CSUMCOPY_ECACHE_LOAD(       0x00,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+	CSUMCOPY_EC_STALIGNED_LDNXT(0x40,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+	CSUMCOPY_EC_STALIGNED_LDNXT(0x80,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+	CSUMCOPY_EC_STALIGNED_LDNXT(0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
+	CSUMCOPY_EC_STALIGNED(      0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7)
 11:
-	sub		%g1, 256, %g1		! IEU0	Group
-	add		%o0, 256, %o0		! IEU1
-	andncc		%g1, 0xff, %g0		! IEU1	Group	
+	sub		%len, 256, %len		! IEU0	Group
+	add		%src, 256, %src		! IEU1
+	andncc		%len, 0xff, %g0		! IEU1	Group	
 	bne,pt		%icc, ccdbl		! CTI
-	 add		%o1, 256, %o1		! IEU0
+	 add		%dst, 256, %dst		! IEU0
 	b,pt		%xcc, ccmerge		! CTI	Group
-	 andcc		%g1, 0xf0, %o2		! IEU1
+	 andcc		%len, 0xf0, %g1		! IEU1
 
 ccslow:	mov	0, %g5
-	brlez,pn %g1, 4f
-	 andcc	%o0, 1, %o5		
+	brlez,pn %len, 4f
+	 andcc	%src, 1, %o5		
 	be,a,pt	%icc, 1f
-	 srl	%g1, 1, %o3		
-	sub	%g1, 1, %g1	
-	lduba [%o0] %asi, %g5
-	add	%o0, 1, %o0	
-	stb	%g5, [%o1]
-	srl	%g1, 1, %o3
-	add	%o1, 1, %o1
-1:	brz,a,pn %o3, 3f
-	 andcc	%g1, 1, %g0
-	andcc	%o0, 2, %g0	
+	 srl	%len, 1, %g7		
+	sub	%len, 1, %len	
+	lduba [%src] %asi, %g5
+	add	%src, 1, %src	
+	stb	%g5, [%dst]
+	srl	%len, 1, %g7
+	add	%dst, 1, %dst
+1:	brz,a,pn %g7, 3f
+	 andcc	%len, 1, %g0
+	andcc	%src, 2, %g0	
 	be,a,pt	%icc, 1f
-	 srl	%o3, 1, %o3
-	lduha [%o0] %asi, %o4
-	sub	%g1, 2, %g1	
+	 srl	%g7, 1, %g7
+	lduha [%src] %asi, %o4
+	sub	%len, 2, %len	
 	srl	%o4, 8, %g2
-	sub	%o3, 1, %o3	
-	stb	%g2, [%o1]
+	sub	%g7, 1, %g7	
+	stb	%g2, [%dst]
 	add	%o4, %g5, %g5
-	stb	%o4, [%o1 + 1]
-	add	%o0, 2, %o0	
-	srl	%o3, 1, %o3
-	add	%o1, 2, %o1
-1:	brz,a,pn %o3, 2f		
-	 andcc	%g1, 2, %g0
-	lda	[%o0] %asi, %o4
+	stb	%o4, [%dst + 1]
+	add	%src, 2, %src	
+	srl	%g7, 1, %g7
+	add	%dst, 2, %dst
+1:	brz,a,pn %g7, 2f		
+	 andcc	%len, 2, %g0
+	lduwa	[%src] %asi, %o4
 5:	srl	%o4, 24, %g2
 	srl	%o4, 16, %g3
-	stb	%g2, [%o1]
+	stb	%g2, [%dst]
 	srl	%o4, 8, %g2
-	stb	%g3, [%o1 + 1]
-	add	%o0, 4, %o0
-	stb	%g2, [%o1 + 2]
+	stb	%g3, [%dst + 1]
+	add	%src, 4, %src
+	stb	%g2, [%dst + 2]
 	addcc	%o4, %g5, %g5
-	stb	%o4, [%o1 + 3]
-	addc	%g5, %g0, %g5	! I am now to lazy to optimize this (question is if it
-	add	%o1, 4, %o1	! is worthy). Maybe some day - with the sll/srl
-	subcc	%o3, 1, %o3	! tricks
+	stb	%o4, [%dst + 3]
+	addc	%g5, %g0, %g5
+	add	%dst, 4, %dst
+	subcc	%g7, 1, %g7
 	bne,a,pt %icc, 5b
-	 lda [%o0] %asi, %o4
+	 lduwa [%src] %asi, %o4
 	sll	%g5, 16, %g2
 	srl	%g5, 16, %g5
 	srl	%g2, 16, %g2
-	andcc	%g1, 2, %g0
+	andcc	%len, 2, %g0
 	add	%g2, %g5, %g5 
 2:	be,a,pt	%icc, 3f		
-	 andcc	%g1, 1, %g0
-	lduha [%o0] %asi, %o4
-	andcc	%g1, 1, %g0
+	 andcc	%len, 1, %g0
+	lduha [%src] %asi, %o4
+	andcc	%len, 1, %g0
 	srl	%o4, 8, %g2
-	add	%o0, 2, %o0	
-	stb	%g2, [%o1]
+	add	%src, 2, %src	
+	stb	%g2, [%dst]
 	add	%g5, %o4, %g5
-	stb	%o4, [%o1 + 1]
-	add	%o1, 2, %o1
+	stb	%o4, [%dst + 1]
+	add	%dst, 2, %dst
 3:	be,a,pt	%icc, 1f		
 	 sll	%g5, 16, %o4
-	lduba [%o0] %asi, %g2
+	lduba [%src] %asi, %g2
 	sll	%g2, 8, %o4	
-	stb	%g2, [%o1]
+	stb	%g2, [%dst]
 	add	%g5, %o4, %g5
 	sll	%g5, 16, %o4
 1:	addcc	%o4, %g5, %g5
@@ -484,8 +484,22 @@
 	and	%o4, 0xff, %o4
 	sll	%g2, 8, %g2
 	or	%g2, %o4, %g5
-4:	addcc	%g7, %g5, %g7
-	addc	%g0, %g7, %o0
+4:	addcc	%sum, %g5, %sum
+	addc	%g0, %sum, %o0
 	retl	
 	 srl	%o0, 0, %o0
-__csum_partial_copy_end:
+cpc_end:
+
+	.globl	cpc_handler
+cpc_handler:
+	ldx	[%sp + 0x7ff + 128], %g1
+	sub	%g0, EFAULT, %g2
+	brnz,a,pt %g1, 1f
+	 st	%g2, [%g1]
+1:	retl
+	 nop
+
+	.section __ex_table
+	.align  8
+	.xword  cpc_start, 0, cpc_end, cpc_handler
+
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/lib/locks.S linux/arch/sparc64/lib/locks.S
--- v2.1.50/linux/arch/sparc64/lib/locks.S	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc64/lib/locks.S	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/* $Id: locks.S,v 1.3 1997/07/22 05:51:42 davem Exp $
+/* $Id: locks.S,v 1.5 1997/07/31 05:28:16 davem Exp $
  * locks.S: SMP low-level lock primitives on Sparc64.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -12,9 +12,9 @@
 	.align		32
 
 ___lk_busy_spin:
-	orcc		%g2, 0, %g0
-	bne,pt		%icc, ___lk_busy_spin
-	 ldub		[%g1 + 0], %g2
+	ldub		[%g1 + 0], %g2
+	brnz,pt		%g2, ___lk_busy_spin
+	 membar		#LoadLoad
 	b,pt		%xcc, 1f
 	 ldstub		[%g1 + 0], %g2
 
@@ -23,16 +23,15 @@
 	addcc		%g2, -1, %g2
 	rdpr		%pil, %g3
 	bcs,a,pn	%icc, 9f
-	 st		%g2, [%g6 + AOFF_task_lock_depth]
+	 stw		%g2, [%g6 + AOFF_task_lock_depth]
 	wrpr		%g0, 15, %pil
 	ldstub		[%g1 + 0], %g2
-1:	brnz,a,pn	%g2, ___lk_busy_spin
-	 ldub		[%g1 + 0], %g2
+1:	brnz,pn		%g2, ___lk_busy_spin
+	 membar		#StoreLoad | #StoreStore
 	lduw		[%g6 + AOFF_task_processor], %g2
-	membar		#LoadLoad | #LoadStore
 	stb		%g2, [%g1 + 1]
 2:	mov		-1, %g2
-	st		%g2, [%g6 + AOFF_task_lock_depth]
+	stw		%g2, [%g6 + AOFF_task_lock_depth]
 	wrpr		%g3, 0, %pil
 9:	jmpl		%o7 + 0x8, %g0
 	 mov		%g5, %o7
@@ -41,16 +40,16 @@
 ___lock_reacquire_kernel:
 	rdpr		%pil, %g3
 	wrpr		%g0, 15, %pil
-	st		%g2, [%g6 + AOFF_task_lock_depth]
+	stw		%g2, [%g6 + AOFF_task_lock_depth]
 	ldstub		[%g1 + 0], %g2
 1:	brz,pt		%g2, 3f
-	 ldub		[%g1 + 0], %g2
-2:	brnz,a,pt	%g2, 2b
-	 ldub		[%g1 + 0], %g2
+	 membar		#StoreLoad | #StoreStore
+2:	ldub		[%g1 + 0], %g2
+	brnz,pt		%g2, 2b
+	 membar		#LoadLoad
 	b,pt		%xcc, 1b
 	 ldstub		[%g1 + 0], %g2
 3:	lduw		[%g6 + AOFF_task_processor], %g2
-	membar		#LoadLoad | #LoadStore
 	stb		%g2, [%g1 + 1]
 	wrpr		%g3, 0, %pil
 	jmpl		%o7 + 0x8, %g0
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c
--- v2.1.50/linux/arch/sparc64/mm/fault.c	Thu Jul 17 10:06:04 1997
+++ linux/arch/sparc64/mm/fault.c	Sat Aug 16 10:00:22 1997
@@ -217,56 +217,3 @@
 out:
 	unlock_kernel();
 }
-
-void fixup_dcache_alias(struct vm_area_struct *vma, unsigned long address, pte_t pte)
-{
-	struct vm_area_struct *vmaring;
-	struct inode *inode;
-	unsigned long vaddr, offset, start;
-	pgd_t *pgdp;
-	pmd_t *pmdp;
-	pte_t *ptep;
-	int alias_found = 0;
-
-	inode = vma->vm_dentry->d_inode;
-	if(!inode)
-		return;
-
-	offset = (address & PAGE_MASK) - vma->vm_start;
-	vmaring = inode->i_mmap;
-	do {
-		vaddr = vmaring->vm_start + offset;
-
-		/* This conditional is misleading... */
-		if((vaddr ^ address) & PAGE_SIZE) {
-			alias_found++;
-			start = vmaring->vm_start;
-			while(start < vmaring->vm_end) {
-				pgdp = pgd_offset(vmaring->vm_mm, start);
-				if(!pgdp) goto next;
-				pmdp = pmd_offset(pgdp, start);
-				if(!pmdp) goto next;
-				ptep = pte_offset(pmdp, start);
-				if(!ptep) goto next;
-
-				if(pte_val(*ptep) & _PAGE_PRESENT) {
-					flush_cache_page(vmaring, start);
-					*ptep = __pte(pte_val(*ptep) &
-						      ~(_PAGE_CV));
-					flush_tlb_page(vmaring, start);
-				}
-			next:
-				start += PAGE_SIZE;
-			}
-		}
-	} while((vmaring = vmaring->vm_next_share) != NULL);
-
-	if(alias_found && (pte_val(pte) & _PAGE_CV)) {
-		pgdp = pgd_offset(vma->vm_mm, address);
-		pmdp = pmd_offset(pgdp, address);
-		ptep = pte_offset(pmdp, address);
-		flush_cache_page(vma, address);
-		*ptep = __pte(pte_val(*ptep) & ~(_PAGE_CV));
-		flush_tlb_page(vma, address);
-	}
-}
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.1.50/linux/arch/sparc64/mm/init.c	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc64/mm/init.c	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.40 1997/07/24 16:48:27 davem Exp $
+/*  $Id: init.c,v 1.54 1997/08/15 06:44:23 davem Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -37,6 +37,18 @@
 /* References to section boundaries */
 extern char __init_begin, __init_end, etext, __bss_start;
 
+extern void __bfill64(void *, unsigned long *);
+
+static __inline__ void __init_pmd(pmd_t *pmdp)
+{
+	__bfill64((void *)pmdp, &null_pte_table);
+}
+
+static __inline__ void __init_pgd(pgd_t *pgdp)
+{
+	__bfill64((void *)pgdp, &null_pmd_table);
+}
+
 /*
  * BAD_PAGE is the page that is used for page faults when linux
  * is out-of-memory. Older versions of linux just did a
@@ -103,47 +115,71 @@
 
 /* IOMMU support, the ideas are right, the code should be cleaned a bit still... */
 
-/* XXX Also, play with the streaming buffers at some point, both
- * XXX Fusion and Sunfire both have them aparently... -DaveM
- */
-
 /* This keeps track of pages used in sparc_alloc_dvma() invocations. */
 static unsigned long dvma_map_pages[0x10000000 >> 16] = { 0, };
 static unsigned long dvma_pages_current_offset = 0;
 static int dvma_pages_current_index = 0;
 
+/* #define E3000_DEBUG */
+
 __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start,
 				    unsigned long memory_end, struct linux_sbus *sbus))
 {
 	struct iommu_struct *iommu;
 	struct sysio_regs *sregs;
-	struct linux_prom_registers rprop[2];
+	struct linux_prom64_registers rprop;
 	unsigned long impl, vers;
 	unsigned long control, tsbbase;
 	unsigned long *iopte;
+	u32 rlow, rhigh;
 	int err, i;
 
-	err = prom_getproperty(iommu_node, "reg", (char *)rprop,
+#ifdef E3000_DEBUG
+	prom_printf("\niommu_init: [%x:%016lx:%016lx:%p] ",
+		    iommu_node, memory_start, memory_end, sbus);
+#endif
+	err = prom_getproperty(iommu_node, "reg", (char *)&rprop,
 			       sizeof(rprop));
 	if(err == -1) {
 		prom_printf("iommu_init: Cannot map SYSIO control registers.\n");
 		prom_halt();
 	}
-	sregs = (struct sysio_regs *) sparc_alloc_io(rprop[0].phys_addr,
-						     (void *)0,
+	rlow  = (rprop.phys_addr & 0xffffffff);
+	rhigh = (rprop.phys_addr >> 32);
+#ifdef E3000_DEBUG
+	prom_printf("rlow[%08x] rhigh[%08x] ", rlow, rhigh);
+#endif
+	sregs = (struct sysio_regs *) sparc_alloc_io(rlow, (void *)0,
 						     sizeof(struct sysio_regs),
-						     "SYSIO Regs",
-						     rprop[0].which_io, 0x0);
+						     "SYSIO Regs", rhigh, 0x0);
+#ifdef E3000_DEBUG
+	prom_printf("sregs[%p]\n");
+#endif
+	if(!sregs) {
+		prom_printf("iommu_init: Fatal error, sysio regs not mapped\n");
+		prom_halt();
+	}
 
 	memory_start = (memory_start + 7) & ~7;
 	iommu = (struct iommu_struct *) memory_start;
 	memory_start += sizeof(struct iommu_struct);
+
+#ifdef E3000_DEBUG
+	prom_printf("iommu_init: iommu[%p] ", iommu);
+#endif
+
+	spin_lock_init(&iommu->iommu_lock);
 	iommu->sysio_regs = sregs;
 	sbus->iommu = iommu;
 
 	control = sregs->iommu_control;
 	impl = (control & IOMMU_CTRL_IMPL) >> 60;
 	vers = (control & IOMMU_CTRL_VERS) >> 56;
+#ifdef E3000_DEBUG
+	prom_printf("sreg_control[%08x]\n", control);
+	prom_printf("IOMMU: IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n",
+		    (unsigned int) impl, (unsigned int)vers, (unsigned long) sregs);
+#endif
 	printk("IOMMU: IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n",
 	       (unsigned int) impl, (unsigned int)vers, (unsigned long) sregs);
 	
@@ -168,7 +204,8 @@
 
 	/* Setup aliased mappings... */
 	for(i = 0; i < (65536 - 4096); i++) {
-		*iopte  = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE);
+		*iopte  = (IOPTE_VALID | IOPTE_64K | IOPTE_STBUF |
+			   IOPTE_CACHE | IOPTE_WRITE);
 		*iopte |= (i << 16);
 		iopte++;
 	}
@@ -177,15 +214,47 @@
 	for( ; i < 65536; i++)
 		*iopte++ = 0;
 
+#ifdef E3000_DEBUG
+	prom_printf("IOMMU: pte's mapped, enabling IOMMU... ");
+#endif
 	sregs->iommu_tsbbase = __pa(tsbbase);
 	sregs->iommu_control = control;
 
+#ifdef E3000_DEBUG
+	prom_printf("done\n");
+#endif
+	/* Get the streaming buffer going. */
+	control = sregs->sbuf_control;
+	impl = (control & SYSIO_SBUFCTRL_IMPL) >> 60;
+	vers = (control & SYSIO_SBUFCTRL_REV) >> 56;
+#ifdef E3000_DEBUG
+	prom_printf("IOMMU: enabling streaming buffer, control[%08x]... ",
+		    control);
+#endif
+	printk("IOMMU: Streaming Buffer IMPL[%x] REV[%x] ",
+	       (unsigned int)impl, (unsigned int)vers);
+	printk("FlushFLAG[%p,%016lx] ... ",
+	       (iommu->sbuf_flushflag_va = (unsigned int *)memory_start),
+	       (iommu->sbuf_flushflag_pa = __pa(memory_start)));
+	*(iommu->sbuf_flushflag_va) = 0;
+	memory_start += sizeof(unsigned long); /* yes, unsigned long, for alignment */
+
+	sregs->sbuf_control = (control | SYSIO_SBUFCTRL_SB_EN);
+
+#ifdef E3000_DEBUG
+	prom_printf("done, returning %016lx\n", memory_start);
+#endif
+	printk("ENABLED\n");
+
+	/* Finally enable DVMA arbitration for all devices, just in case. */
+	sregs->sbus_control |= SYSIO_SBCNTRL_AEN;
+
 	return memory_start;
 }
 
-void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr)
+void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr,
+		      struct linux_sbus *sbus)
 {
-	struct iommu_struct *iommu = SBus_chain->iommu; /* GROSS ME OUT! */
 	pgd_t *pgdp;
 	pmd_t *pmdp;
 	pte_t *ptep;
@@ -193,6 +262,7 @@
 	/* Find out if we need to grab some pages. */
 	if(!dvma_map_pages[dvma_pages_current_index] ||
 	   ((dvma_pages_current_offset + len) > (1 << 16))) {
+		struct linux_sbus *sbus;
 		unsigned long *iopte;
 		unsigned long newpages = __get_free_pages(GFP_KERNEL, 3, 0);
 		int i;
@@ -212,9 +282,16 @@
 
 		/* Stick it in the IOMMU. */
 		i = (65536 - 4096) + i;
-		iopte = (unsigned long *)(iommu->page_table + i);
-		*iopte  = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE);
-		*iopte |= __pa(newpages);
+		for_each_sbus(sbus) {
+			struct iommu_struct *iommu = sbus->iommu;
+			unsigned long flags;
+
+			spin_lock_irqsave(&iommu->iommu_lock, flags);
+			iopte = (unsigned long *)(iommu->page_table + i);
+			*iopte  = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE);
+			*iopte |= __pa(newpages);
+			spin_unlock_irqrestore(&iommu->iommu_lock, flags);
+		}
 	}
 
 	/* Get this out of the way. */
@@ -258,6 +335,33 @@
         return (__u32)0;
 }
 
+void mmu_release_scsi_one(u32 vaddr, unsigned long len, struct linux_sbus *sbus)
+{
+	struct iommu_struct *iommu = sbus->iommu;
+	struct sysio_regs *sregs = iommu->sysio_regs;
+	unsigned long start = (unsigned long) vaddr;
+	unsigned long end = PAGE_ALIGN(start + len);
+	unsigned long flags;
+	unsigned int *sync_word;
+
+	start &= PAGE_MASK;
+
+	spin_lock_irqsave(&iommu->iommu_lock, flags);
+
+	while(start < end) {
+		sregs->sbuf_pflush = start;
+		start += PAGE_SIZE;
+	}
+	sync_word = iommu->sbuf_flushflag_va;
+	sregs->sbuf_fsync = iommu->sbuf_flushflag_pa;
+	membar("#StoreLoad | #MemIssue");
+	while((*sync_word & 0x1) == 0)
+		membar("#LoadLoad");
+	*sync_word = 0;
+
+	spin_unlock_irqrestore(&iommu->iommu_lock, flags);
+}
+
 void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
 {
 	while(sz >= 0) {
@@ -273,6 +377,36 @@
 	}
 }
 
+void mmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus)
+{
+	struct iommu_struct *iommu = sbus->iommu;
+	struct sysio_regs *sregs = iommu->sysio_regs;
+	unsigned long flags;
+	unsigned int *sync_word;
+
+	spin_lock_irqsave(&iommu->iommu_lock, flags);
+
+	while(sz >= 0) {
+		unsigned long start = sg[sz].dvma_addr;
+		unsigned long end = PAGE_ALIGN(start + sg[sz].len);
+
+		start &= PAGE_MASK;
+		while(start < end) {
+			sregs->sbuf_pflush = start;
+			start += PAGE_SIZE;
+		}
+		sz--;
+	}
+	sync_word = iommu->sbuf_flushflag_va;
+	sregs->sbuf_fsync = iommu->sbuf_flushflag_pa;
+	membar("#StoreLoad | #MemIssue");
+	while((*sync_word & 0x1) == 0)
+		membar("#LoadLoad");
+	*sync_word = 0;
+
+	spin_unlock_irqrestore(&iommu->iommu_lock, flags);
+}
+
 static char sfmmuinfo[512];
 
 char *mmu_info(void)
@@ -340,7 +474,7 @@
 unsigned long prom_itlb_tag, prom_itlb_data;
 unsigned long prom_dtlb_tag, prom_dtlb_data;
 
-static inline void inherit_locked_prom_mappings(void)
+void inherit_locked_prom_mappings(int save_p)
 {
 	int i;
 	int dtlb_seen = 0;
@@ -367,9 +501,12 @@
 		data = spitfire_get_dtlb_data(i);
 		if(!dtlb_seen && (data & _PAGE_L)) {
 			unsigned long tag = spitfire_get_dtlb_tag(i);
-			prom_dtlb_ent = i;
-			prom_dtlb_tag = tag;
-			prom_dtlb_data = data;
+
+			if(save_p) {
+				prom_dtlb_ent = i;
+				prom_dtlb_tag = tag;
+				prom_dtlb_data = data;
+			}
 			__asm__ __volatile__("stxa %%g0, [%0] %1"
 					     : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU));
 			membar("#Sync");
@@ -390,9 +527,12 @@
 		data = spitfire_get_itlb_data(i);
 		if(!itlb_seen && (data & _PAGE_L)) {
 			unsigned long tag = spitfire_get_itlb_tag(i);
-			prom_itlb_ent = i;
-			prom_itlb_tag = tag;
-			prom_itlb_data = data;
+
+			if(save_p) {
+				prom_itlb_ent = i;
+				prom_itlb_tag = tag;
+				prom_itlb_data = data;
+			}
 			__asm__ __volatile__("stxa %%g0, [%0] %1"
 					     : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU));
 			membar("#Sync");
@@ -443,10 +583,14 @@
 /* If not locked, zap it. */
 void __flush_tlb_all(void)
 {
-	unsigned long flags;
+	unsigned long pstate;
 	int i;
 
-	save_flags(flags); cli();
+	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
+			     "wrpr	%0, %1, %%pstate\n\t"
+			     "flushw"
+			     : "=r" (pstate)
+			     : "i" (PSTATE_IE));
 	for(i = 0; i < 64; i++) {
 		if(!(spitfire_get_dtlb_data(i) & _PAGE_L)) {
 			__asm__ __volatile__("stxa %%g0, [%0] %1"
@@ -465,19 +609,67 @@
 			membar("#Sync");
 		}
 	}
-	restore_flags(flags);
+	__asm__ __volatile__("wrpr	%0, 0, %%pstate"
+			     : : "r" (pstate));
 }
 
-void get_new_mmu_context(struct mm_struct *mm, unsigned long ctx)
+/* We are always protected by scheduler_lock under SMP. */
+void get_new_mmu_context(struct mm_struct *mm, unsigned long *ctx)
 {
-	if((ctx & ~(CTX_VERSION_MASK)) == 0) {
-		flush_tlb_all();
-		ctx = (ctx & CTX_VERSION_MASK) + CTX_FIRST_VERSION;
-		if(ctx == 1)
-			ctx = CTX_FIRST_VERSION;
+	unsigned int new_ctx = *ctx;
+
+	if((new_ctx & ~(CTX_VERSION_MASK)) == 0) {
+		new_ctx += CTX_FIRST_VERSION;
+		if(new_ctx == 1)
+			new_ctx = CTX_FIRST_VERSION;
+		*ctx = new_ctx;
+		DO_LOCAL_FLUSH(smp_processor_id());
+	}
+	mm->context = new_ctx;
+	mm->cpu_vm_mask = 0;	/* Callers sets it properly. */
+	(*ctx)++;
+}
+
+#ifndef __SMP__
+unsigned long *pgd_quicklist = NULL;
+unsigned long *pmd_quicklist = NULL;
+unsigned long *pte_quicklist = NULL;
+unsigned long pgtable_cache_size = 0;
+#endif
+
+pgd_t *get_pgd_slow(void)
+{
+	pgd_t *pgd;
+
+	pgd = (pgd_t *) __get_free_page(GFP_KERNEL);
+	if(pgd)
+		__init_pgd(pgd);
+	return pgd;
+}
+
+pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
+{
+	pmd_t *pmd;
+
+	pmd = (pmd_t *) __get_free_page(GFP_KERNEL);
+	if(pmd) {
+		__init_pmd(pmd);
+		pgd_set(pgd, pmd);
+		return pmd + offset;
 	}
-	tlb_context_cache = ctx + 1;
-	mm->context = ctx;
+	return NULL;
+}
+
+pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
+{
+	pte_t *pte;
+
+	pte = (pte_t *) get_free_page(GFP_KERNEL);
+	if(pte) {
+		pmd_set(pmd, pte);
+		return pte + offset;
+	}
+	return NULL;
 }
 
 __initfunc(static void
@@ -595,7 +787,7 @@
 	 */
 	pt  = phys_base | _PAGE_VALID | _PAGE_SZ4MB;
 	pt |= _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W;
-	save_flags(flags); cli();
+	__save_and_cli(flags);
 	__asm__ __volatile__("
 	stxa	%1, [%0] %3
 	stxa	%2, [%5] %4
@@ -608,15 +800,18 @@
 	: "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt),
 	  "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3)
 	: "memory");
-	restore_flags(flags);
+	__restore_flags(flags);
 	
 	/* Now set kernel pgd to upper alias so physical page computations
 	 * work.
 	 */
 	init_mm.pgd += ((shift) / (sizeof(pgd_t *)));
 
-	null_pmd_table = __pa(((unsigned long)&empty_null_pmd_table) + shift);
-	null_pte_table = __pa(((unsigned long)&empty_null_pte_table) + shift);
+	/* The funny offsets are to make page table operations much quicker and
+	 * requite less state, see pgtable.h for gory details.
+	 */
+	null_pmd_table=__pa(((unsigned long)&empty_null_pmd_table)+shift);
+	null_pte_table=__pa(((unsigned long)&empty_null_pte_table)+shift);
 
 	pmdp = (pmd_t *) &empty_null_pmd_table;
 	for(i = 0; i < 1024; i++)
@@ -658,7 +853,7 @@
 	flushi((long)&empty_zero_page);
 	membar("#Sync");
 
-	inherit_locked_prom_mappings();
+	inherit_locked_prom_mappings(1);
 	
 	flush_tlb_all();
 	
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S
--- v2.1.50/linux/arch/sparc64/mm/ultra.S	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc64/mm/ultra.S	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/* $Id: ultra.S,v 1.9 1997/07/24 12:15:08 davem Exp $
+/* $Id: ultra.S,v 1.18 1997/08/08 08:34:23 jj Exp $
  * ultra.S: Don't expand these all over the place...
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -13,28 +13,26 @@
 	.align		32
 	.globl		__flush_tlb_mm, __flush_tlb_range, __flush_tlb_page
 __flush_tlb_mm:		/* %o0 == (mm->context & 0x1fff) */
-	rdpr		%otherwin, %g1
-	brz,pt		%g1, 1f
-	 mov		%o7, %g3
-	call		__flushw_user
-	 clr		%g2
-1:	rdpr		%pil, %g1
-9:	mov		SECONDARY_CONTEXT, %g7
-	wrpr		%g0, 15, %pil
-
-	ldxa		[%g7] ASI_DMMU, %g2
+	mov		SECONDARY_CONTEXT, %g7
+9:	ldxa		[%g7] ASI_DMMU, %g2
 	cmp		%g2, %o0
-	be,pt		%icc, 1f
+	bne,pn		%icc, 1f
 	 mov		0x50, %g3
+	stxa		%g0, [%g3] ASI_DMMU_DEMAP
+	stxa		%g0, [%g3] ASI_IMMU_DEMAP
+	retl
+	 flush		%g6
+1:	rdpr		%pstate, %g1
+	wrpr		%g1, PSTATE_IE, %pstate
 	stxa		%o0, [%g7] ASI_DMMU
-1:	stxa		%g0, [%g3] ASI_DMMU_DEMAP
-	be,pt		%icc, 1f
-	 stxa		%g0, [%g3] ASI_IMMU_DEMAP
-
+	stxa		%g0, [%g3] ASI_DMMU_DEMAP
+	stxa		%g0, [%g3] ASI_IMMU_DEMAP
+	flush		%g6
 	stxa		%g2, [%g7] ASI_DMMU
-1:	wrpr		%g1, 0x0, %pil
+	flush		%g6
 	retl
-	 flush		%g6
+	 wrpr		%g1, 0, %pstate
+	nop
 __flush_tlb_range:	/* %o0 == (mm->context & 0x1fff), %o1 == start, %o2 == end */
 	sethi		%hi(8192 - 1), %g5
 	or		%g5, %lo(8192 - 1), %g5
@@ -43,19 +41,13 @@
 
 	sub		%o2, %o1, %o3
 	add		%g5, 1, %g5
-	orcc		%o1, 0x50, %o1
+	orcc		%o1, 0x10, %o1
 	srlx		%o3, 13, %o4
-	rdpr		%otherwin, %g1
-	brz,pt		%g1, 1f
-	 mov		%o7, %g3
-	call		__flushw_user
-
-	 clr		%g2
-1:	cmp		%o4, 96
+	cmp		%o4, 96
 	bgu,pn		%icc, 9b
-	 rdpr		%pil, %g1
-	mov		SECONDARY_CONTEXT, %g7
-	wrpr		%g0, 15, %pil
+	 mov		SECONDARY_CONTEXT, %g7
+	rdpr		%pstate, %g1
+	wrpr		%g1, PSTATE_IE, %pstate
 	ldxa		[%g7] ASI_DMMU, %g2
 	cmp		%g2, %o0
 
@@ -66,37 +58,37 @@
 	stxa		%g0, [%o1 + %o3] ASI_IMMU_DEMAP
 	brnz,pt		%o3, 1b
 	 sub		%o3, %g5, %o3
-	nop
+	flush		%g6
 
-	be,pt		%icc, 1f
-	 wrpr		%g1, 0x0, %pil
+	be,a,pt		%icc, 1f
+	 nop
 	stxa		%g2, [%g7] ASI_DMMU
-1:	retl
-	 flush		%g6
+1:	flush		%g6
+	wrpr		%g1, 0, %pstate
+	retl
+	 nop
 
 	.align		32
 __flush_tlb_page:	/* %o0 == (mm->context & 0x1fff), %o1 == page & PAGE_MASK */
-	rdpr		%otherwin, %g1
-	brz,pt		%g1, 1f
-	 mov		%o7, %g3
-	call		__flushw_user
-	 clr		%g2
-1:	rdpr		%pil, %g1
 	mov		SECONDARY_CONTEXT, %g7
-	wrpr		%g0, 15, %pil
-
 	ldxa		[%g7] ASI_DMMU, %g2
 	cmp		%g2, %o0
 	be,pt		%icc, 1f
 	 or		%o1, 0x10, %g3
+	stxa		%g0, [%g3] ASI_DMMU_DEMAP
+	stxa		%g0, [%g3] ASI_IMMU_DEMAP
+	retl
+	 flush		%g6
+1:	rdpr		%pstate, %g1
+	wrpr		%g1, PSTATE_IE, %pstate
 	stxa		%o0, [%g7] ASI_DMMU
-1:	stxa		%g0, [%g3] ASI_DMMU_DEMAP
-	be,pt		%icc, 1f
-	 stxa		%g0, [%g3] ASI_IMMU_DEMAP
+	stxa		%g0, [%g3] ASI_DMMU_DEMAP
+	stxa		%g0, [%g3] ASI_IMMU_DEMAP
+	flush		%g6
 	stxa		%g2, [%g7] ASI_DMMU
-1:	wrpr		%g1, 0x0, %pil
+	flush		%g6
 	retl
-	 flush		%g6
+	 wrpr		%g1, 0, %pstate
 
 #ifdef __SMP__
 	/* These are all called by the slaves of a cross call, at
@@ -111,50 +103,29 @@
 	 *   %g2	scratch 1
 	 *   %g3	scratch 2
 	 *   %g4	scratch 3
-	 *
-	 * NOTE: We do not acknowledge the UPA until we are done
-	 *       with the service.  This is what tells the master
-	 *       that he can consider the effects of the flush
-	 *       "complete" on this cpu.
 	 */
 	.align		32
-	.globl		xcall_flush_tlb_page
+	.globl		xcall_flush_tlb_page, xcall_flush_tlb_mm, xcall_flush_tlb_range
 xcall_flush_tlb_page:
 	mov		SECONDARY_CONTEXT, %g2
-	nop
+	or		%g6, 0x10, %g4
 	ldxa		[%g2] ASI_DMMU, %g3
-	cmp		%g3, %g5
-	be,pt		%icc, 1f
-	 or		%g6, 0x10, %g4
 	stxa		%g5, [%g2] ASI_DMMU
-1:	stxa		%g0, [%g4] ASI_DMMU_DEMAP
-
-	be,pt		%icc, 1f
-	 stxa		%g0, [%g4] ASI_IMMU_DEMAP
+	stxa		%g0, [%g4] ASI_DMMU_DEMAP
+	stxa		%g0, [%g4] ASI_IMMU_DEMAP
 	stxa		%g3, [%g2] ASI_DMMU
-1:	b,pt		%xcc, do_ivec_return
-	 flush		%g1
+	retry
 
-	.align		32
-	.globl		xcall_flush_tlb_mm
 xcall_flush_tlb_mm:
 	mov		SECONDARY_CONTEXT, %g2
-	nop
+	mov		0x50, %g4
 	ldxa		[%g2] ASI_DMMU, %g3
-	cmp		%g3, %g5
-	be,pt		%icc, 1f
-	 mov		0x50, %g4
 	stxa		%g5, [%g2] ASI_DMMU
-1:	stxa		%g0, [%g4] ASI_DMMU_DEMAP
-
-	be,pt		%icc, 1f
-	 stxa		%g0, [%g4] ASI_IMMU_DEMAP
+	stxa		%g0, [%g4] ASI_DMMU_DEMAP
+	stxa		%g0, [%g4] ASI_IMMU_DEMAP
 	stxa		%g3, [%g2] ASI_DMMU
-1:	b,pt		%xcc, do_ivec_return
-	 flush		%g1
+	retry
 
-	.align		32
-	.globl		xcall_flush_tlb_range
 xcall_flush_tlb_range:
 	sethi		%hi(8192 - 1), %g2
 	or		%g2, %lo(8192 - 1), %g2
@@ -162,26 +133,54 @@
 	andn		%g7, %g2, %g7
 	sub		%g7, %g6, %g3
 	add		%g2, 1, %g2
-	orcc		%g6, 0x50, %g6
+	orcc		%g6, 0x10, %g6
 	srlx		%g3, 13, %g4
 
 	cmp		%g4, 96
 	bgu,pn		%icc, xcall_flush_tlb_mm
 	 mov		SECONDARY_CONTEXT, %g4
 	ldxa		[%g4] ASI_DMMU, %g7
-	cmp		%g7, %g5
-	be,pt		%icc, 1f
-	 sub		%g3, %g2, %g3
+	sub		%g3, %g2, %g3
 	stxa		%g5, [%g4] ASI_DMMU
+	nop
+	nop
 
 1:	stxa		%g0, [%g6 + %g3] ASI_DMMU_DEMAP
 	stxa		%g0, [%g6 + %g3] ASI_IMMU_DEMAP
 	brnz,pt		%g3, 1b
 	 sub		%g3, %g2, %g3
-	bne,a,pn	%icc, 1f
-	 stxa		%g7, [%g4] ASI_DMMU
-1:	b,pt		%xcc, do_ivec_return
-	 flush		%g1	
+	stxa		%g7, [%g4] ASI_DMMU
+	retry
+	nop
+	nop
+
+	.globl		xcall_report_regs
+xcall_report_regs:
+	rdpr		%pstate, %g2
+	wrpr		%g2, PSTATE_IG | PSTATE_AG, %pstate
+	rdpr		%pil, %g2
+	wrpr		%g0, 15, %pil
+	sethi		%hi(109f), %g7
+	b,pt		%xcc, etrap_irq
+109:	 or		%g7, %lo(109b), %g7
+	call		__show_regs
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	b,pt		%xcc, rtrap
+	 clr		%l6
+
+	.globl		xcall_capture
+xcall_capture:
+	rdpr		%pstate, %g2
+	wrpr		%g2, PSTATE_IG | PSTATE_AG, %pstate
+	rdpr		%pil, %g2
+	wrpr		%g0, 15, %pil
+	sethi		%hi(109f), %g7
+	b,pt		%xcc, etrap_irq
+109:	 or		%g7, %lo(109b), %g7
+	call		smp_penguin_jailcell
+	 nop
+	b,pt		%xcc, rtrap
+	 clr		%l6
 
 	/* These two are not performance critical... */
 	.globl		xcall_flush_tlb_all
@@ -209,8 +208,8 @@
 	cmp		%g2, 63
 	ble,pt		%icc, 1b
 	 sll		%g2, 3, %g3
-	b,pt		%xcc, do_ivec_return
-	 flush		%g1
+	flush		%g1
+	retry
 
 	.globl		xcall_flush_cache_all
 xcall_flush_cache_all:
@@ -222,6 +221,6 @@
 	cmp		%g3, %g2
 	bleu,pt		%xcc, 1b
 	 nop
-	b,pt		%xcc, do_ivec_return
-	 flush		%g1
+	flush		%g1
+	retry
 #endif /* __SMP__ */
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/prom/p1275.c linux/arch/sparc64/prom/p1275.c
--- v2.1.50/linux/arch/sparc64/prom/p1275.c	Mon Aug  4 16:25:37 1997
+++ linux/arch/sparc64/prom/p1275.c	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/* $Id: p1275.c,v 1.11 1997/07/24 12:15:11 davem Exp $
+/* $Id: p1275.c,v 1.12 1997/07/26 18:39:01 davem Exp $
  * p1275.c: Sun IEEE 1275 PROM low level interface routines
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -64,7 +64,7 @@
 	long ctx = 0;
 	
 	p = p1275buf.prom_buffer;
-	save_and_cli(flags);
+	__save_and_cli(flags);
 	ctx = spitfire_get_primary_context ();
 	if (ctx) {
 		flushw_user ();
@@ -149,7 +149,7 @@
 	
 	if (ctx)
 		spitfire_set_primary_context (ctx);
-	restore_flags(flags);
+	__restore_flags(flags);
 	return x;
 }
 
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/prom/ranges.c linux/arch/sparc64/prom/ranges.c
--- v2.1.50/linux/arch/sparc64/prom/ranges.c	Mon Apr 14 16:28:10 1997
+++ linux/arch/sparc64/prom/ranges.c	Sat Aug 16 09:51:09 1997
@@ -1,15 +1,21 @@
-/* $Id: ranges.c,v 1.3 1997/03/21 12:33:36 jj Exp $
+/* $Id: ranges.c,v 1.7 1997/08/15 06:44:29 davem Exp $
  * ranges.c: Handle ranges in newer proms for obio/sbus.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
+#include <linux/config.h>
 #include <linux/init.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/sbus.h>
+#include <asm/fhc.h>
 #include <asm/system.h>
+#ifdef CONFIG_PCI
+#include <asm/pbm.h>
+#include <asm/ebus.h>
+#endif
 
 struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX];
 int num_obio_ranges;
@@ -62,6 +68,35 @@
 	}
 }
 
+/* Apply probed fhc ranges to registers passed, if no ranges return. */
+void prom_apply_fhc_ranges(struct linux_fhc *fhc,
+			   struct linux_prom_registers *regs,
+			   int nregs)
+{
+	if(fhc->num_fhc_ranges)
+		prom_adjust_regs(regs, nregs, fhc->fhc_ranges,
+				 fhc->num_fhc_ranges);
+}
+
+/* Apply probed central ranges to registers passed, if no ranges return. */
+void prom_apply_central_ranges(struct linux_central *central,
+			       struct linux_prom_registers *regs, int nregs)
+{
+	if(central->num_central_ranges)
+		prom_adjust_regs(regs, nregs, central->central_ranges,
+				 central->num_central_ranges);
+}
+
+#ifdef CONFIG_PCI
+void prom_apply_ebus_ranges(struct linux_ebus *ebus,
+			    struct linux_prom_registers *regs, int nregs)
+{
+	if (ebus->num_ebus_ranges)
+		prom_adjust_regs(regs, nregs, ebus->ebus_ranges,
+				 ebus->num_ebus_ranges);
+}
+#endif
+
 __initfunc(void prom_ranges_init(void))
 {
 }
@@ -77,6 +112,74 @@
 	if (success != -1)
 		sbus->num_sbus_ranges = (success/sizeof(struct linux_prom_ranges));
 }
+
+__initfunc(void prom_central_ranges_init(int cnode, struct linux_central *central))
+{
+	int success;
+	
+	central->num_central_ranges = 0;
+	success = prom_getproperty(central->prom_node, "ranges",
+				   (char *) central->central_ranges,
+				   sizeof (central->central_ranges));
+	if (success != -1)
+		central->num_central_ranges = (success/sizeof(struct linux_prom_ranges));
+}
+
+__initfunc(void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc))
+{
+	int success;
+	
+	fhc->num_fhc_ranges = 0;
+	success = prom_getproperty(fhc->prom_node, "ranges",
+				   (char *) fhc->fhc_ranges,
+				   sizeof (fhc->fhc_ranges));
+	if (success != -1)
+		fhc->num_fhc_ranges = (success/sizeof(struct linux_prom_ranges));
+}
+
+#ifdef CONFIG_PCI
+__initfunc(void prom_ebus_ranges_init(struct linux_ebus *ebus))
+{
+	struct ebus_range {
+		unsigned int	cld_space;
+		unsigned int	cld_base;
+		unsigned int	prn_space;
+		unsigned int	prn_base_hi;
+		unsigned int	prn_base_lo;
+		unsigned int	size;
+	} ranges[PROMREG_MAX];
+	int i, success;
+
+	ebus->num_ebus_ranges = 0;
+	success = prom_getproperty(ebus->prom_node, "ranges",
+				   (char *)ranges, sizeof (ranges));
+	if (success != -1)
+		ebus->num_ebus_ranges = (success/sizeof(struct ebus_range));
+
+	for (i = 0; i < ebus->num_ebus_ranges; i++) {
+		ebus->ebus_ranges[i].ot_child_space = ranges[i].cld_space;
+		ebus->ebus_ranges[i].ot_child_base = ranges[i].cld_base;
+		ebus->ebus_ranges[i].ot_parent_space =
+				ranges[i].prn_space & 0x0f000000;
+		if (ranges[i].prn_base_hi)
+			prom_printf("WARNING: %s: ot_parent_base high lost\n");
+		ebus->ebus_ranges[i].ot_parent_base = ranges[i].prn_base_lo;
+		ebus->ebus_ranges[i].or_size = ranges[i].size;
+	}
+}
+
+__initfunc(void prom_pbm_ranges_init(int pnode, struct linux_pbm_info *pbm))
+{
+	int success;
+
+	pbm->num_pbm_ranges = 0;
+	success = prom_getproperty(pbm->prom_node, "ranges",
+				   (char *)&pbm->pbm_ranges,
+				   sizeof(pbm->pbm_ranges));
+	if(success != -1)
+		pbm->num_pbm_ranges = (success/sizeof(struct linux_prom_pci_ranges));
+}
+#endif
 
 void
 prom_apply_generic_ranges (int node, int parent, struct linux_prom_registers *regs, int nregs)
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/prom/tree.c linux/arch/sparc64/prom/tree.c
--- v2.1.50/linux/arch/sparc64/prom/tree.c	Mon Apr 14 16:28:10 1997
+++ linux/arch/sparc64/prom/tree.c	Sat Aug 16 09:51:09 1997
@@ -1,4 +1,4 @@
-/* $Id: tree.c,v 1.5 1997/03/24 17:44:01 jj Exp $
+/* $Id: tree.c,v 1.6 1997/08/12 16:32:48 davem Exp $
  * tree.c: Basic device tree traversal/scanning for the Linux
  *         prom library.
  *
@@ -26,7 +26,7 @@
 __inline__ int
 prom_getchild(int node)
 {
-	long cnode;
+	int cnode;
 
 	if(node == -1) return 0;
 	cnode = __prom_getchild(node);
@@ -37,7 +37,7 @@
 __inline__ int
 prom_getparent(int node)
 {
-	long cnode;
+	int cnode;
 
 	if(node == -1) return 0;
 	cnode = p1275_cmd ("parent", P1275_INOUT(1, 1), node);
@@ -57,12 +57,12 @@
 __inline__ int
 prom_getsibling(int node)
 {
-	long sibnode;
+	int sibnode;
 
 	if(node == -1) return 0;
 	sibnode = __prom_getsibling(node);
 	if(sibnode == -1) return 0;
-	return (int)sibnode;
+	return sibnode;
 }
 
 /* Return the length in bytes of property 'prop' at node 'node'.
diff -u --recursive --new-file v2.1.50/linux/arch/sparc64/vmlinux.lds linux/arch/sparc64/vmlinux.lds
--- v2.1.50/linux/arch/sparc64/vmlinux.lds	Mon Jul  7 08:18:55 1997
+++ linux/arch/sparc64/vmlinux.lds	Sat Aug 16 09:51:09 1997
@@ -52,11 +52,13 @@
    . += 8192;
    empty_bad_pte_table = .;
    . += 8192;
+   empty_bad_page = .;
+   . += 8192;
+   . += 0x40;
    empty_null_pmd_table = .;
    . += 8192;
+   . += 0x40;
    empty_null_pte_table = .;
-   . += 8192;
-   empty_bad_page = .;
    . += 8192;
   }
   _end = . ;
diff -u --recursive --new-file v2.1.50/linux/drivers/Makefile linux/drivers/Makefile
--- v2.1.50/linux/drivers/Makefile	Mon Aug  4 16:25:37 1997
+++ linux/drivers/Makefile	Sat Aug 16 09:53:08 1997
@@ -9,7 +9,7 @@
 
 SUB_DIRS     := block char net misc #streams
 MOD_SUB_DIRS := $(SUB_DIRS) sbus
-ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus sound cdrom isdn pnp
+ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus sound cdrom isdn pnp macintosh
 
 ifdef CONFIG_PCI
 SUB_DIRS += pci
@@ -17,6 +17,11 @@
 
 ifdef CONFIG_SBUS
 SUB_DIRS += sbus
+endif
+
+ifdef CONFIG_PPC
+SUB_DIRS += macintosh
+MOD_SUB_DIRS += macintosh
 endif
 
 # If CONFIG_SCSI is set, the core of scsi support will be added to the kernel,
diff -u --recursive --new-file v2.1.50/linux/drivers/block/Makefile linux/drivers/block/Makefile
--- v2.1.50/linux/drivers/block/Makefile	Sat May 24 09:10:23 1997
+++ linux/drivers/block/Makefile	Sat Aug 16 09:53:08 1997
@@ -22,6 +22,10 @@
 LX_OBJS :=
 MX_OBJS :=
 
+ifeq ($(CONFIG_MAC_FLOPPY),y)
+L_OBJS += swim3.o
+endif
+
 ifeq ($(CONFIG_BLK_DEV_FD),y)
 L_OBJS += floppy.o
 else
diff -u --recursive --new-file v2.1.50/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- v2.1.50/linux/drivers/block/floppy.c	Sun Jun 29 10:51:09 1997
+++ linux/drivers/block/floppy.c	Sat Aug 16 09:53:08 1997
@@ -3969,6 +3969,10 @@
 	}
 
 	fdc_state[0].address = FDC1;
+	if (fdc_state[0].address == -1) {
+		unregister_blkdev(MAJOR_NR,"fd");
+		return -ENODEV;
+	}
 #if N_FDC > 1
 	fdc_state[1].address = FDC2;
 #endif
diff -u --recursive --new-file v2.1.50/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v2.1.50/linux/drivers/block/genhd.c	Mon Aug  4 16:25:37 1997
+++ linux/drivers/block/genhd.c	Sat Aug 16 09:53:08 1997
@@ -672,6 +672,132 @@
 }
 #endif /* CONFIG_AMIGA_PARTITION */
 
+#ifdef CONFIG_MAC_PARTITION
+#include <linux/ctype.h>
+
+/*
+ * Code to understand MacOS partition tables.
+ */
+
+#define MAC_PARTITION_MAGIC	0x504d
+
+/* type field value for A/UX or other Unix partitions */
+#define APPLE_AUX_TYPE	"Apple_UNIX_SVR2"
+
+struct mac_partition {
+	__u16	signature;	/* expected to be MAC_PARTITION_MAGIC */
+	__u16	res1;
+	__u32	map_count;	/* # blocks in partition map */
+	__u32	start_block;	/* absolute starting block # of partition */
+	__u32	block_count;	/* number of blocks in partition */
+	char	name[32];	/* partition name */
+	char	type[32];	/* string type description */
+	__u32	data_start;	/* rel block # of first data block */
+	__u32	data_count;	/* number of data blocks */
+	__u32	status;		/* partition status bits */
+	__u32	boot_start;
+	__u32	boot_size;
+	__u32	boot_load;
+	__u32	boot_load2;
+	__u32	boot_entry;
+	__u32	boot_entry2;
+	__u32	boot_cksum;
+	char	processor[16];	/* identifies ISA of boot */
+	/* there is more stuff after this that we don't need */
+};
+
+#define MAC_STATUS_BOOTABLE	8	/* partition is bootable */
+
+#define MAC_DRIVER_MAGIC	0x4552
+
+/* Driver descriptor structure, in block 0 */
+struct mac_driver_desc {
+	__u16	signature;	/* expected to be MAC_DRIVER_MAGIC */
+	__u16	block_size;
+	__u32	block_count;
+    /* ... more stuff */
+};
+
+static int mac_partition(struct gendisk *hd, kdev_t dev, unsigned long fsec)
+{
+	struct buffer_head *bh;
+	int blk, blocks_in_map;
+	int dev_bsize, dev_pos, pos;
+	unsigned secsize;
+	int first_bootable = 1;
+	struct mac_partition *part;
+	struct mac_driver_desc *md;
+
+	dev_bsize = get_ptable_blocksize(dev);
+	dev_pos = 0;
+	/* Get 0th block and look at the first partition map entry. */
+	if ((bh = bread(dev, 0, dev_bsize)) == 0) {
+	    printk("%s: error reading partition table\n",
+		   kdevname(dev));
+	    return -1;
+	}
+	md = (struct mac_driver_desc *) bh->b_data;
+	if (be16_to_cpu(md->signature) != MAC_DRIVER_MAGIC) {
+		brelse(bh);
+		return 0;
+	}
+	secsize = be16_to_cpu(md->block_size);
+	if (secsize >= dev_bsize) {
+		brelse(bh);
+		dev_pos = secsize;
+		if ((bh = bread(dev, secsize/dev_bsize, dev_bsize)) == 0) {
+			printk("%s: error reading partition table\n",
+			       kdevname(dev));
+			return -1;
+		}
+	}
+	part = (struct mac_partition *) (bh->b_data + secsize - dev_pos);
+	if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) {
+		brelse(bh);
+		return 0;		/* not a MacOS disk */
+	}
+	blocks_in_map = be32_to_cpu(part->map_count);
+	for (blk = 1; blk <= blocks_in_map; ++blk) {
+		pos = blk * secsize;
+		if (pos >= dev_pos + dev_bsize) {
+			brelse(bh);
+			dev_pos = pos;
+			if ((bh = bread(dev, pos/dev_bsize, dev_bsize)) == 0) {
+				printk("%s: error reading partition table\n",
+				       kdevname(dev));
+				return -1;
+			}
+		}
+		part = (struct mac_partition *) (bh->b_data + pos - dev_pos);
+		if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC)
+			break;
+		blocks_in_map = be32_to_cpu(part->map_count);
+		add_partition(hd, current_minor,
+			fsec + be32_to_cpu(part->start_block) * (secsize/512),
+			be32_to_cpu(part->block_count) * (secsize/512));
+
+#ifdef CONFIG_PMAC
+		/*
+		 * If this is the first bootable partition, tell the
+		 * setup code, in case it wants to make this the root.
+		 */
+		if (first_bootable
+		    && (be32_to_cpu(part->status) & MAC_STATUS_BOOTABLE)
+		    && strcasecmp(part->processor, "powerpc") == 0) {
+			note_bootable_part(dev, blk);
+			first_bootable = 0;
+		}
+#endif /* CONFIG_PMAC */
+
+		++current_minor;
+	}
+	brelse(bh);
+	printk("\n");
+	return 1;
+}
+
+#endif /* CONFIG_MAC_PARTITION */
+
 #ifdef CONFIG_ATARI_PARTITION
 #include <asm/atari_rootsec.h>
 
@@ -846,6 +972,10 @@
 #endif
 #ifdef CONFIG_ATARI_PARTITION
 	if(atari_partition(hd, dev, first_sector))
+		return;
+#endif
+#ifdef CONFIG_MAC_PARTITION
+	if (mac_partition(hd, dev, first_sector))
 		return;
 #endif
 	printk(" unknown partition table\n");
diff -u --recursive --new-file v2.1.50/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.1.50/linux/drivers/block/ll_rw_blk.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/block/ll_rw_blk.c	Sat Aug 16 09:53:08 1997
@@ -681,10 +681,13 @@
 #ifdef CONFIG_BLK_DEV_EZ
 	ez_init();
 #endif
+#ifdef CONFIG_MAC_FLOPPY
+	swim3_init();
+#endif
 #ifdef CONFIG_BLK_DEV_FD
 	floppy_init();
 #else
-#if !defined (__mc68000__)
+#if !defined (__mc68000__) && !defined(CONFIG_PMAC) && !defined(__sparc__)
 	outb_p(0xc, 0x3f2);
 #endif
 #endif
diff -u --recursive --new-file v2.1.50/linux/drivers/block/swim3.c linux/drivers/block/swim3.c
--- v2.1.50/linux/drivers/block/swim3.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/block/swim3.c	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,1011 @@
+/*
+ * Driver for the SWIM3 (Super Woz Integrated Machine 3)
+ * floppy controller found on Power Macintoshes.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/fd.h>
+#include <linux/ioctl.h>
+#include <asm/io.h>
+#include <asm/dbdma.h>
+#include <asm/prom.h>
+#include <asm/uaccess.h>
+
+#define MAJOR_NR	FLOPPY_MAJOR
+#include <linux/blk.h>
+
+static int floppy_blocksizes[2] = {512};
+static int floppy_sizes[2] = {2880};
+
+enum swim_state {
+	idle,
+	locating,
+	seeking,
+	settling,
+	do_transfer,
+	jogging,
+	available,
+	revalidating,
+	ejecting
+};
+
+#define REG(x)	unsigned char x; char x ## _pad[15];
+
+/*
+ * The names for these registers mostly represent speculation on my part.
+ * It will be interesting to see how close they are to the names Apple uses.
+ */
+struct swim3 {
+	REG(data);
+	REG(usecs);		/* counts down at 1MHz */
+	REG(error);
+	REG(mode);
+	REG(select);		/* controls CA0, CA1, CA2 and LSTRB signals */
+	REG(reg5);
+	REG(control);		/* writing bits clears them */
+	REG(status);		/* writing bits sets them in control */
+	REG(intr);
+	REG(nseek);		/* # tracks to seek */
+	REG(ctrack);		/* current track number */
+	REG(csect);		/* current sector number */
+	REG(ssize);		/* sector size code?? */
+	REG(sector);		/* sector # to read or write */
+	REG(nsect);		/* # sectors to read or write */
+	REG(intr_enable);
+};
+
+#define control_bic	control
+#define control_bis	status
+
+/* Bits in select register */
+#define CA_MASK		7
+#define LSTRB		8
+
+/* Bits in control register */
+#define DO_SEEK		0x80
+#define SELECT		0x20
+#define WRITE_SECTORS	0x10
+#define SCAN_TRACK	0x08
+#define DRIVE_ENABLE	0x02
+#define INTR_ENABLE	0x01
+
+/* Bits in status register */
+#define DATA		0x08
+
+/* Bits in intr and intr_enable registers */
+#define ERROR		0x20
+#define DATA_CHANGED	0x10
+#define TRANSFER_DONE	0x08
+#define SEEN_SECTOR	0x04
+#define SEEK_DONE	0x02
+
+/* Select values for swim3_action */
+#define SEEK_POSITIVE	0
+#define SEEK_NEGATIVE	4
+#define STEP		1
+#define MOTOR_ON	2
+#define MOTOR_OFF	6
+#define EJECT		7
+
+/* Select values for swim3_select and swim3_readbit */
+#define STEP_DIR	0
+#define STEPPING	1
+#define MOTOR_ON	2
+#define RELAX		3
+#define READ_DATA_0	4
+#define SINGLE_SIDED	6
+#define DRIVE_PRESENT	7
+#define DISK_IN		8
+#define WRITE_PROT	9
+#define TRACK_ZERO	10
+#define TACHO		11
+#define READ_DATA_1	12
+#define SEEK_COMPLETE	14
+
+struct floppy_state {
+	enum swim_state	state;
+	volatile struct swim3 *swim3;	/* hardware registers */
+	struct dbdma_regs *dma;	/* DMA controller registers */
+	int	swim3_intr;	/* interrupt number for SWIM3 */
+	int	dma_intr;	/* interrupt number for DMA channel */
+	int	cur_cyl;	/* cylinder head is on, or -1 */
+	int	cur_sector;	/* last sector we saw go past */
+	int	req_cyl;	/* the cylinder for the current r/w request */
+	int	head;		/* head number ditto */
+	int	req_sector;	/* sector number ditto */
+	int	scount;		/* # sectors we're transferring at present */
+	int	retries;
+	int	secpercyl;	/* disk geometry information */
+	int	secpertrack;
+	int	total_secs;
+	int	write_prot;	/* 1 if write-protected, 0 if not, -1 dunno */
+	struct dbdma_cmd *dma_cmd;
+	int	ref_count;
+	int	expect_cyl;
+	struct timer_list timeout;
+	int	ejected;
+	struct wait_queue *wait;
+	int	wanted;
+	char	dbdma_cmd_space[5 * sizeof(struct dbdma_cmd)];
+};
+
+static struct floppy_state floppy_states[1];
+
+static unsigned short write_preamble[] = {
+	0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e, 0x4e4e,	/* gap field */
+	0, 0, 0, 0, 0, 0,			/* sync field */
+	0x99a1, 0x99a1, 0x99a1, 0x99fb,		/* data address mark */
+	0x990f					/* init CRC generator */
+};
+
+static unsigned short write_postamble[] = {
+	0x9904,					/* insert CRC */
+	0x4e4e, 0x4e4e,
+	0x9908,					/* stop writing */
+	0, 0, 0, 0, 0, 0
+};
+
+static void swim3_select(struct floppy_state *fs, int sel);
+static void swim3_action(struct floppy_state *fs, int action);
+static int swim3_readbit(struct floppy_state *fs, int bit);
+static void do_fd_request(void);
+static void start_request(struct floppy_state *fs);
+static void scan_track(struct floppy_state *fs);
+static void seek_track(struct floppy_state *fs, int n);
+static void init_dma(struct dbdma_cmd *cp, int cmd, void *buf, int count);
+static void setup_transfer(struct floppy_state *fs);
+static void act(struct floppy_state *fs);
+static void scan_timeout(unsigned long data);
+static void seek_timeout(unsigned long data);
+static void xfer_timeout(unsigned long data);
+static void swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int grab_drive(struct floppy_state *fs, enum swim_state state,
+		      int interruptible);
+static void release_drive(struct floppy_state *fs);
+static int fd_eject(struct floppy_state *fs);
+static int floppy_ioctl(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long param);
+static int floppy_open(struct inode *inode, struct file *filp);
+static int floppy_release(struct inode *inode, struct file *filp);
+static long floppy_read(struct inode *inode, struct file *filp,
+			char *buf, unsigned long count);
+static long floppy_write(struct inode *inode, struct file *filp,
+			 const char *buf, unsigned long count);
+static int floppy_check_change(kdev_t dev);
+static int floppy_revalidate(kdev_t dev);
+int swim3_init(void);
+
+#define IOCTL_MODE_BIT	8
+#define OPEN_WRITE_BIT	16
+
+static void swim3_select(struct floppy_state *fs, int sel)
+{
+	volatile struct swim3 *sw = fs->swim3;
+
+	out_8(&sw->select, RELAX);
+	if (sel & 8)
+		out_8(&sw->control_bis, SELECT);
+	else
+		out_8(&sw->control_bic, SELECT);
+	out_8(&sw->select, sel & CA_MASK);
+}
+
+static void swim3_action(struct floppy_state *fs, int action)
+{
+	volatile struct swim3 *sw = fs->swim3;
+
+	swim3_select(fs, action);
+	udelay(1);
+	sw->select |= LSTRB; eieio();
+	udelay(2);
+	sw->select &= ~LSTRB; eieio();
+	udelay(1);
+	out_8(&sw->select, RELAX);
+}
+
+static int swim3_readbit(struct floppy_state *fs, int bit)
+{
+	volatile struct swim3 *sw = fs->swim3;
+	int stat;
+
+	swim3_select(fs, bit);
+	udelay(1);
+	stat = in_8(&sw->status);
+	out_8(&sw->select, RELAX);
+	return (stat & DATA) == 0;
+}
+
+static void do_fd_request(void)
+{
+	start_request(&floppy_states[0]);
+	sti();
+}
+
+static void start_request(struct floppy_state *fs)
+{
+	int drive;
+	unsigned long x;
+
+	if (fs->state == idle && fs->wanted) {
+		fs->state = available;
+		wake_up(&fs->wait);
+		return;
+	}
+	while (CURRENT && fs->state == idle) {
+		if (MAJOR(CURRENT->rq_dev) != MAJOR_NR)
+			panic(DEVICE_NAME ": request list destroyed");
+		if (CURRENT->bh && !buffer_locked(CURRENT->bh))
+			panic(DEVICE_NAME ": block not locked");
+#if 0
+		printk("do_fd_req: dev=%x cmd=%d sec=%ld nr_sec=%ld buf=%p\n",
+		       kdev_t_to_nr(CURRENT->rq_dev), CURRENT->cmd,
+		       CURRENT->sector, CURRENT->nr_sectors, CURRENT->buffer);
+		printk("           rq_status=%d errors=%d current_nr_sectors=%ld\n",
+		       CURRENT->rq_status, CURRENT->errors, CURRENT->current_nr_sectors);
+#endif
+
+		drive = MINOR(CURRENT->rq_dev);
+		if (drive != 0) {
+			end_request(0);
+			continue;
+		}
+		if (CURRENT->sector < 0 || CURRENT->sector >= fs->total_secs) {
+			end_request(0);
+			continue;
+		}
+		if (CURRENT->current_nr_sectors == 0) {
+			end_request(1);
+			continue;
+		}
+		if (fs->ejected) {
+			end_request(0);
+			continue;
+		}
+
+		if (CURRENT->cmd == WRITE) {
+			if (fs->write_prot < 0)
+				fs->write_prot = swim3_readbit(fs, WRITE_PROT);
+			if (fs->write_prot) {
+				end_request(0);
+				continue;
+			}
+		}
+
+		fs->req_cyl = CURRENT->sector / fs->secpercyl;
+		x = CURRENT->sector % fs->secpercyl;
+		fs->head = x / fs->secpertrack;
+		fs->req_sector = x % fs->secpertrack + 1;
+		fs->state = do_transfer;
+		fs->retries = 0;
+
+		act(fs);
+	}
+}
+
+static inline void scan_track(struct floppy_state *fs)
+{
+	volatile struct swim3 *sw = fs->swim3;
+	int xx;
+
+	swim3_select(fs, READ_DATA_0);
+	xx = sw->intr;		/* clear SEEN_SECTOR bit */
+	out_8(&sw->control_bis, SCAN_TRACK);
+	/* enable intr when track found */
+	out_8(&sw->intr_enable, ERROR | SEEN_SECTOR);
+	/* enable timeout */
+	fs->timeout.expires = jiffies + HZ;
+	fs->timeout.function = scan_timeout;
+	fs->timeout.data = (unsigned long) fs;
+	add_timer(&fs->timeout);
+}
+
+static inline void seek_track(struct floppy_state *fs, int n)
+{
+	volatile struct swim3 *sw = fs->swim3;
+
+	if (n >= 0) {
+		swim3_action(fs, SEEK_POSITIVE);
+		sw->nseek = n;
+	} else {
+		swim3_action(fs, SEEK_NEGATIVE);
+		sw->nseek = -n;
+	}
+	fs->expect_cyl = (fs->cur_cyl > 0)? fs->cur_cyl + n: -1;
+	swim3_select(fs, STEP);
+	out_8(&sw->control_bis, DO_SEEK);
+	/* enable intr when seek finished */
+	out_8(&sw->intr_enable, ERROR | SEEK_DONE);
+	/* enable timeout */
+	fs->timeout.expires = jiffies + HZ/2;
+	fs->timeout.function = seek_timeout;
+	fs->timeout.data = (unsigned long) fs;
+	add_timer(&fs->timeout);
+}
+
+static inline void init_dma(struct dbdma_cmd *cp, int cmd,
+			    void *buf, int count)
+{
+	st_le16(&cp->req_count, count);
+	st_le16(&cp->command, cmd);
+	st_le32(&cp->phy_addr, virt_to_bus(buf));
+	cp->xfer_status = 0;
+}
+
+static inline void setup_transfer(struct floppy_state *fs)
+{
+	int n;
+	volatile struct swim3 *sw = fs->swim3;
+	struct dbdma_cmd *cp = fs->dma_cmd;
+	struct dbdma_regs *dr = fs->dma;
+
+	if (CURRENT->current_nr_sectors <= 0) {
+		printk(KERN_ERR "swim3: transfer 0 sectors?\n");
+		return;
+	}
+	if (CURRENT->cmd == WRITE)
+		n = 1;
+	else {
+		n = fs->secpertrack - fs->req_sector + 1;
+		if (n > CURRENT->current_nr_sectors)
+			n = CURRENT->current_nr_sectors;
+	}
+	fs->scount = n;
+	swim3_select(fs, fs->head? READ_DATA_1: READ_DATA_0);
+	out_8(&sw->sector, fs->req_sector);
+	out_8(&sw->nsect, n);
+	out_8(&sw->ssize, 0);
+	st_le32(&dr->cmdptr, virt_to_bus(cp));
+	if (CURRENT->cmd == WRITE) {
+		/* Set up 3 dma commands: write preamble, data, postamble */
+		init_dma(cp, OUTPUT_MORE, write_preamble, sizeof(write_preamble));
+		++cp;
+		init_dma(cp, OUTPUT_MORE, CURRENT->buffer, 512);
+		++cp;
+		init_dma(cp, OUTPUT_MORE, write_postamble, sizeof(write_postamble));
+	} else {
+		init_dma(cp, INPUT_MORE, CURRENT->buffer, n * 512);
+	}
+	++cp;
+	out_le16(&cp->command, DBDMA_STOP);
+	out_le32(&dr->control, (RUN << 16) | RUN);
+	out_8(&sw->control_bis,
+	      (CURRENT->cmd == WRITE? WRITE_SECTORS: 0) | SCAN_TRACK);
+	/* enable intr when transfer complete */
+	out_8(&sw->intr_enable, ERROR | TRANSFER_DONE);
+	/* enable timeout */
+	fs->timeout.expires = jiffies + 2*HZ;
+	fs->timeout.function = xfer_timeout;
+	fs->timeout.data = (unsigned long) fs;
+	add_timer(&fs->timeout);
+}
+
+static void act(struct floppy_state *fs)
+{
+	volatile struct swim3 *sw = fs->swim3;
+
+	for (;;) {
+		switch (fs->state) {
+		case idle:
+			return;		/* XXX shouldn't get here */
+
+		case locating:
+			if (swim3_readbit(fs, TRACK_ZERO)) {
+				fs->cur_cyl = 0;
+				if (fs->req_cyl == 0)
+					fs->state = do_transfer;
+				else
+					fs->state = seeking;
+				break;
+			}
+			scan_track(fs);
+			return;
+
+		case seeking:
+			if (fs->cur_cyl < 0) {
+				fs->expect_cyl = -1;
+				fs->state = locating;
+				break;
+			}
+			if (fs->req_cyl == fs->cur_cyl) {
+				printk("whoops, seeking 0\n");
+				fs->state = do_transfer;
+				break;
+			}
+			seek_track(fs, fs->req_cyl - fs->cur_cyl);
+			return;
+
+		case settling:
+			/* wait for SEEK_COMPLETE to become true */
+			swim3_select(fs, SEEK_COMPLETE);
+			udelay(1);
+			out_8(&sw->intr_enable, ERROR | DATA_CHANGED);
+			in_8(&sw->intr);	/* clear DATA_CHANGED */
+			if (in_8(&sw->status) & DATA) {
+				/* seek_complete is not yet true */
+				fs->timeout.expires = jiffies + HZ/2;
+				fs->timeout.function = seek_timeout;
+				fs->timeout.data = (unsigned long) fs;
+				add_timer(&fs->timeout);
+				return;
+			}
+			out_8(&sw->intr_enable, 0);
+			in_8(&sw->intr);
+			fs->state = locating;
+			break;
+
+		case do_transfer:
+			if (fs->cur_cyl != fs->req_cyl) {
+				if (fs->retries > 5) {
+					end_request(0);
+					fs->state = idle;
+					return;
+				}
+				fs->state = seeking;
+				break;
+			}
+			setup_transfer(fs);
+			return;
+
+		case jogging:
+			seek_track(fs, -5);
+			return;
+
+		default:
+			printk(KERN_ERR"swim3: unknown state %d\n", fs->state);
+			return;
+		}
+	}
+}
+
+static void scan_timeout(unsigned long data)
+{
+	struct floppy_state *fs = (struct floppy_state *) data;
+	volatile struct swim3 *sw = fs->swim3;
+
+	out_8(&sw->control_bic, SCAN_TRACK);
+	out_8(&sw->select, RELAX);
+	out_8(&sw->intr_enable, 0);
+	fs->cur_cyl = -1;
+	if (fs->retries > 5) {
+		end_request(0);
+		fs->state = idle;
+		start_request(fs);
+	} else {
+		fs->state = jogging;
+		act(fs);
+	}
+}
+
+static void seek_timeout(unsigned long data)
+{
+	struct floppy_state *fs = (struct floppy_state *) data;
+	volatile struct swim3 *sw = fs->swim3;
+
+	if (fs->state == settling) {
+		printk(KERN_ERR "swim3: MSI sel=%x ctrl=%x stat=%x intr=%x ie=%x\n",
+		       sw->select, sw->control, sw->status, sw->intr, sw->intr_enable);
+	}
+	out_8(&sw->control_bic, DO_SEEK);
+	out_8(&sw->select, RELAX);
+	out_8(&sw->intr_enable, 0);
+	if (fs->state == settling && swim3_readbit(fs, SEEK_COMPLETE)) {
+		/* printk(KERN_DEBUG "swim3: missed settling interrupt\n"); */
+		fs->state = locating;
+		act(fs);
+		return;
+	}
+	printk(KERN_ERR "swim3: seek timeout\n");
+	end_request(0);
+	fs->state = idle;
+	start_request(fs);
+}
+
+static void xfer_timeout(unsigned long data)
+{
+	struct floppy_state *fs = (struct floppy_state *) data;
+	volatile struct swim3 *sw = fs->swim3;
+	struct dbdma_regs *dr = fs->dma;
+	struct dbdma_cmd *cp = fs->dma_cmd;
+	unsigned long s;
+
+	st_le32(&dr->control, RUN << 16);
+	out_8(&sw->intr_enable, 0);
+	out_8(&sw->control_bic, WRITE_SECTORS | SCAN_TRACK);
+	out_8(&sw->select, RELAX);
+	if (CURRENT->cmd == WRITE)
+		++cp;
+	if (ld_le16(&cp->xfer_status) != 0)
+		s = fs->scount - ((ld_le16(&cp->res_count) + 511) >> 9);
+	else
+		s = 0;
+	CURRENT->sector += s;
+	CURRENT->current_nr_sectors -= s;
+	printk(KERN_ERR "swim3: timeout %sing sector %ld\n",
+	       (CURRENT->cmd==WRITE? "writ": "read"), CURRENT->sector);
+	end_request(0);
+	fs->state = idle;
+	start_request(fs);
+}
+
+static void swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct floppy_state *fs = (struct floppy_state *) dev_id;
+	volatile struct swim3 *sw = fs->swim3;
+	int intr, err, n;
+	int stat, resid;
+	struct dbdma_regs *dr;
+	struct dbdma_cmd *cp;
+
+	err = in_8(&sw->error);
+	intr = in_8(&sw->intr);
+	if ((intr & ERROR) && fs->state != do_transfer)
+		printk(KERN_ERR "swim3_interrupt, state=%d, cmd=%x, intr=%x, err=%x\n",
+		       fs->state, CURRENT->cmd, intr, err);
+	switch (fs->state) {
+	case locating:
+		if (intr & SEEN_SECTOR) {
+			out_8(&sw->control_bic, SCAN_TRACK);
+			out_8(&sw->select, RELAX);
+			out_8(&sw->intr_enable, 0);
+			del_timer(&fs->timeout);
+			if (sw->ctrack == 0xff) {
+				printk(KERN_ERR "swim3: seen sector but cyl=ff?\n");
+				fs->cur_cyl = -1;
+				if (fs->retries > 5) {
+					end_request(0);
+					fs->state = idle;
+					start_request(fs);
+				} else {
+					fs->state = jogging;
+					act(fs);
+				}
+				break;
+			}
+			fs->cur_cyl = sw->ctrack;
+			fs->cur_sector = sw->csect;
+			if (fs->expect_cyl != -1 && fs->expect_cyl != fs->cur_cyl)
+				printk(KERN_ERR "swim3: expected cyl %d, got %d\n",
+				       fs->expect_cyl, fs->cur_cyl);
+			fs->state = do_transfer;
+			act(fs);
+		}
+		break;
+	case seeking:
+	case jogging:
+		if (sw->nseek == 0) {
+			out_8(&sw->control_bic, DO_SEEK);
+			out_8(&sw->select, RELAX);
+			out_8(&sw->intr_enable, 0);
+			del_timer(&fs->timeout);
+			if (fs->state == seeking)
+				++fs->retries;
+			fs->state = settling;
+			act(fs);
+		}
+		break;
+	case settling:
+		out_8(&sw->intr_enable, 0);
+		del_timer(&fs->timeout);
+		act(fs);
+		break;
+	case do_transfer:
+		if ((intr & (ERROR | TRANSFER_DONE)) == 0)
+			break;
+		dr = fs->dma;
+		cp = fs->dma_cmd;
+		st_le32(&dr->control, RUN << 16);
+		out_8(&sw->intr_enable, 0);
+		out_8(&sw->control_bic, WRITE_SECTORS | SCAN_TRACK);
+		out_8(&sw->select, RELAX);
+		del_timer(&fs->timeout);
+		if (CURRENT->cmd == WRITE)
+			++cp;
+		stat = ld_le16(&cp->xfer_status);
+		resid = ld_le16(&cp->res_count);
+		if (intr & ERROR) {
+			n = fs->scount - 1 - resid / 512;
+			if (n > 0) {
+				CURRENT->sector += n;
+				CURRENT->current_nr_sectors -= n;
+				CURRENT->buffer += n * 512;
+				fs->req_sector += n;
+			}
+			if (fs->retries < 5) {
+				++fs->retries;
+				act(fs);
+			} else {
+				printk("swim3: error %sing block %ld (err=%x)\n",
+				       CURRENT->cmd == WRITE? "writ": "read",
+				       CURRENT->sector, err);
+				end_request(0);
+				fs->state = idle;
+			}
+		} else {
+			if ((stat & ACTIVE) == 0 || resid != 0) {
+				/* musta been an error */
+				printk(KERN_ERR "swim3: fd dma: stat=%x resid=%d\n", stat, resid);
+				printk(KERN_ERR "  state=%d, cmd=%x, intr=%x, err=%x\n",
+				       fs->state, CURRENT->cmd, intr, err);
+				end_request(0);
+				fs->state = idle;
+				start_request(fs);
+				break;
+			}
+			CURRENT->sector += fs->scount;
+			CURRENT->current_nr_sectors -= fs->scount;
+			CURRENT->buffer += fs->scount * 512;
+			if (CURRENT->current_nr_sectors <= 0) {
+				end_request(1);
+				fs->state = idle;
+			} else {
+				fs->req_sector += fs->scount;
+				if (fs->req_sector > fs->secpertrack) {
+					fs->req_sector -= fs->secpertrack;
+					if (++fs->head > 1) {
+						fs->head = 0;
+						++fs->req_cyl;
+					}
+				}
+				act(fs);
+			}
+		}
+		if (fs->state == idle)
+			start_request(fs);
+		break;
+	default:
+		printk(KERN_ERR "swim3: don't know what to do in state %d\n", fs->state);
+	}
+}
+
+static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static int grab_drive(struct floppy_state *fs, enum swim_state state,
+		      int interruptible)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	if (fs->state != idle) {
+		++fs->wanted;
+		while (fs->state != available) {
+			if (interruptible
+			    && (current->signal & ~current->blocked)) {
+				--fs->wanted;
+				restore_flags(flags);
+				return -EINTR;
+			}
+			interruptible_sleep_on(&fs->wait);
+		}
+		--fs->wanted;
+	}
+	fs->state = state;
+	restore_flags(flags);
+	return 0;
+}
+
+static void release_drive(struct floppy_state *fs)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	fs->state = idle;
+	start_request(fs);
+	restore_flags(flags);
+}
+
+static int fd_eject(struct floppy_state *fs)
+{
+	int err, n;
+
+	err = grab_drive(fs, ejecting, 1);
+	if (err)
+		return err;
+	swim3_action(fs, EJECT);
+	for (n = 2*HZ; n > 0; --n) {
+		if (swim3_readbit(fs, RELAX))
+			break;
+		if ((current->signal & ~current->blocked) != 0) {
+			err = -EINTR;
+			break;
+		}
+		current->state = TASK_INTERRUPTIBLE;
+		current->timeout = jiffies + 1;
+		schedule();
+	}
+	fs->ejected = 1;
+	release_drive(fs);
+	return err;
+}
+
+static struct floppy_struct floppy_type =
+	{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL };	/*  7 1.44MB 3.5"   */
+
+static int floppy_ioctl(struct inode *inode, struct file *filp,
+			unsigned int cmd, unsigned long param)
+{
+	struct floppy_state *fs;
+	int err;
+
+	if (((cmd & 0x80) && !suser())
+	    || ((cmd & 0x40) && !(filp && (filp->f_mode & IOCTL_MODE_BIT))))
+		return -EPERM;
+
+	fs = &floppy_states[0];
+	switch (cmd) {
+	case FDEJECT:
+		if (fs->ref_count != 1)
+			return -EBUSY;
+		err = fd_eject(fs);
+		return err;
+	case FDGETPRM:
+	        err = copy_to_user((void *) param, (void *) &floppy_type,
+				   sizeof(struct floppy_struct));
+		return err;
+	}
+	return -ENOIOCTLCMD;
+}
+
+static int floppy_open(struct inode *inode, struct file *filp)
+{
+	struct floppy_state *fs;
+	volatile struct swim3 *sw;
+	int n, err;
+
+	if (MINOR(inode->i_rdev) != 0)
+		return -ENODEV;
+	fs = &floppy_states[0];
+	sw = fs->swim3;
+	err = 0;
+	if (fs->ref_count == 0) {
+		out_8(&sw->intr_enable, 0);
+		out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE);
+		swim3_action(fs, MOTOR_ON);
+		fs->write_prot = -1;
+		fs->cur_cyl = -1;
+		for (n = HZ; n > 0; --n) {
+			if (swim3_readbit(fs, SEEK_COMPLETE))
+				break;
+			if ((current->signal & ~current->blocked) != 0) {
+				err = -EINTR;
+				break;
+			}
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + 1;
+			schedule();
+		}
+		if (err == 0 && (swim3_readbit(fs, SEEK_COMPLETE) == 0
+				 || swim3_readbit(fs, DISK_IN) == 0))
+			err = -ENXIO;
+		swim3_action(fs, 9);
+
+	} else if (fs->ref_count == -1 || filp->f_flags & O_EXCL)
+		return -EBUSY;
+
+	if (err == 0 && filp && (filp->f_flags & O_NDELAY) == 0
+	    && (filp->f_mode & 3)) {
+		check_disk_change(inode->i_rdev);
+		if (fs->ejected)
+			err = -ENXIO;
+	}
+
+	if (err == 0 && filp && (filp->f_flags & (O_WRONLY | O_RDWR))) {
+		if (fs->write_prot < 0)
+			fs->write_prot = swim3_readbit(fs, WRITE_PROT);
+		if (fs->write_prot)
+			err = -EROFS;
+	}
+
+	if (err) {
+		if (fs->ref_count == 0) {
+			swim3_action(fs, MOTOR_OFF);
+			out_8(&sw->control_bic, DRIVE_ENABLE | INTR_ENABLE);
+		}
+		return err;
+	}
+
+	if (filp->f_flags & O_EXCL)
+		fs->ref_count = -1;
+	else
+		++fs->ref_count;
+
+	/* Allow ioctls if we have write-permissions even if read-only open */
+	if ((filp->f_mode & 2) || (permission(inode, 2) == 0))
+		filp->f_mode |= IOCTL_MODE_BIT;
+	if (filp->f_mode & 2)
+		filp->f_mode |= OPEN_WRITE_BIT;
+
+	return 0;
+}
+
+static int floppy_release(struct inode *inode, struct file *filp)
+{
+	struct floppy_state *fs;
+	volatile struct swim3 *sw;
+
+	if (MINOR(inode->i_rdev) != 0)
+		return -ENXIO;
+	fs = &floppy_states[0];
+	if (filp == 0 || (filp->f_mode & (2 | OPEN_WRITE_BIT)))
+		block_fsync(inode, filp);
+	sw = fs->swim3;
+	if (fs->ref_count > 0 && --fs->ref_count == 0) {
+		swim3_action(fs, MOTOR_OFF);
+		out_8(&sw->control_bic, 0xff);
+	}
+	return 0;
+}
+
+static int floppy_check_change(kdev_t dev)
+{
+	struct floppy_state *fs;
+
+	if (MAJOR(dev) != MAJOR_NR || MINOR(dev) != 0)
+		return 0;
+	fs = &floppy_states[0];
+	return fs->ejected;
+}
+
+static int floppy_revalidate(kdev_t dev)
+{
+	struct floppy_state *fs;
+	volatile struct swim3 *sw;
+	int ret, n;
+
+	if (MAJOR(dev) != MAJOR_NR || MINOR(dev) != 0)
+		return 0;
+	fs = &floppy_states[0];
+	sw = fs->swim3;
+	grab_drive(fs, revalidating, 0);
+	out_8(&sw->intr_enable, 0);
+	out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE);
+	swim3_action(fs, MOTOR_ON);
+	fs->write_prot = -1;
+	fs->cur_cyl = -1;
+	for (n = HZ; n > 0; --n) {
+		if (swim3_readbit(fs, SEEK_COMPLETE))
+			break;
+		if ((current->signal & ~current->blocked) != 0)
+			break;
+		current->state = TASK_INTERRUPTIBLE;
+		current->timeout = jiffies + 1;
+		schedule();
+	}
+	ret = swim3_readbit(fs, SEEK_COMPLETE) == 0
+		|| swim3_readbit(fs, DISK_IN) == 0;
+	if (ret)
+		swim3_action(fs, MOTOR_OFF);
+	else {
+		fs->ejected = 0;
+		swim3_action(fs, 9);
+	}
+
+	release_drive(fs);
+	return ret;
+}
+
+static long floppy_read(struct inode *inode, struct file *filp,
+			char *buf, unsigned long count)
+{
+	struct floppy_state *fs;
+
+	if (MINOR(inode->i_rdev) != 0)
+		return -ENODEV;
+	fs = &floppy_states[0];
+	if (fs->ejected)
+		return -ENXIO;
+	return block_read(inode, filp, buf, count);
+}
+
+static long floppy_write(struct inode *inode, struct file *filp,
+			 const char *buf, unsigned long count)
+{
+	struct floppy_state *fs;
+
+	if (MINOR(inode->i_rdev) != 0)
+		return -ENODEV;
+	fs = &floppy_states[0];
+	if (fs->ejected)
+		return -ENXIO;
+	return block_write(inode, filp, buf, count);
+}
+
+static void floppy_off(unsigned int nr)
+{
+}
+
+static struct file_operations floppy_fops = {
+	NULL,			/* lseek */
+	floppy_read,		/* read */
+	floppy_write,		/* write */
+	NULL,			/* readdir */
+	NULL,			/* poll */
+	floppy_ioctl,		/* ioctl */
+	NULL,			/* mmap */
+	floppy_open,		/* open */
+	floppy_release,		/* release */
+	block_fsync,		/* fsync */
+	NULL,			/* fasync */
+	floppy_check_change,	/* check_media_change */
+	floppy_revalidate,	/* revalidate */
+};
+
+int swim3_init(void)
+{
+	struct device_node *swims;
+	struct floppy_state *fs = &floppy_states[0];
+	volatile struct swim3 *sw;
+
+	swims = find_devices("swim3");
+	if (swims == NULL)
+		return 0;
+
+	if (swims->next != NULL)
+		printk(KERN_ERR "Warning: only using first SWIM3 floppy controller\n");
+	if (swims->n_addrs != 2 || swims->n_intrs != 2) {
+		printk(KERN_ERR "swim3: expecting 2 addrs and 2 intrs! (%d, %d)\n",
+		       swims->n_addrs, swims->n_intrs);
+		return -EINVAL;
+	}
+
+	if (register_blkdev(MAJOR_NR, "fd", &floppy_fops)) {
+		printk(KERN_ERR "Unable to get major %d for floppy\n",
+		       MAJOR_NR);
+		return -EBUSY;
+	}
+	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+	blksize_size[MAJOR_NR] = floppy_blocksizes;
+	blk_size[MAJOR_NR] = floppy_sizes;
+
+	memset(fs, 0, sizeof(*fs));
+	fs->state = idle;
+	fs->swim3 = (volatile struct swim3 *) swims->addrs[0].address;
+	fs->dma = (struct dbdma_regs *) swims->addrs[1].address;
+	fs->swim3_intr = swims->intrs[0];
+	fs->dma_intr = swims->intrs[1];
+	fs->cur_cyl = -1;
+	fs->cur_sector = -1;
+	fs->secpercyl = 36;
+	fs->secpertrack = 18;
+	fs->total_secs = 2880;
+
+	fs->dma_cmd = (struct dbdma_cmd *) DBDMA_ALIGN(fs->dbdma_cmd_space);
+	memset(fs->dma_cmd, 0, 2 * sizeof(struct dbdma_cmd));
+	st_le16(&fs->dma_cmd[1].command, DBDMA_STOP);
+
+	if (request_irq(fs->swim3_intr, swim3_interrupt, 0, "SWIM3", fs)) {
+		printk(KERN_ERR "Couldn't get irq %d for SWIM3\n", fs->swim3_intr);
+		return -EBUSY;
+	}
+	if (request_irq(fs->dma_intr, fd_dma_interrupt, 0, "SWIM3-dma", fs)) {
+		printk(KERN_ERR "Couldn't get irq %d for SWIM3 DMA",
+		       fs->dma_intr);
+		return -EBUSY;
+	}
+
+	sw = fs->swim3;
+	out_8(&sw->mode, 0x95);
+	out_8(&sw->control_bic, 0xff);
+	out_8(&sw->reg5, 0x28);
+
+	do_floppy = NULL;
+
+	printk(KERN_INFO "fd0: SWIM3 floppy controller\n");
+
+	return 0;
+}
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/Makefile linux/drivers/macintosh/Makefile
--- v2.1.50/linux/drivers/macintosh/Makefile	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/Makefile	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,46 @@
+#
+# Makefile for the Macintosh-specific device drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+#
+
+SUB_DIRS     := 
+MOD_SUB_DIRS := $(SUB_DIRS)
+
+L_TARGET := macintosh.a
+M_OBJS   :=
+L_OBJS   := via-cuda.o adb.o nvram.o
+
+ifeq ($(CONFIG_SERIAL),y)
+  LX_OBJS += macserial.o
+else
+  ifeq ($(CONFIG_SERIAL),m)
+    MX_OBJS += macserial.o
+  endif
+endif
+
+ifdef CONFIG_MAC_KEYBOARD
+L_OBJS += mac_keyb.o mackeymap.o
+endif
+
+ifdef CONFIG_VT
+  ifdef CONFIG_PMAC_CONSOLE
+    L_OBJS += pmac-cons.o control.o platinum.o valkyrie.o
+    ifdef CONFIG_ATY_VIDEO
+      L_OBJS += aty.o
+    endif
+    ifdef CONFIG_IMSTT_VIDEO
+      L_OBJS += imstt.o
+    endif
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
+
+mackeymap.c: mackeymap.map
+	loadkeys --mktable mackeymap.map > mackeymap.c
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/adb.c linux/drivers/macintosh/adb.c
--- v2.1.50/linux/drivers/macintosh/adb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/adb.c	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,169 @@
+/*
+ * Device driver for the /dev/adb device on macintoshes.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <asm/prom.h>
+#include <asm/cuda.h>
+#include <asm/uaccess.h>
+
+#define ADB_MAJOR	56	/* major number for /dev/adb */
+
+extern void adbdev_init(void);
+
+struct adbdev_state {
+	struct cuda_request req;
+};
+
+static struct wait_queue *adb_wait;
+
+static int adb_wait_reply(struct adbdev_state *state, struct file *file)
+{
+	int ret = 0;
+	struct wait_queue wait = { current, NULL };
+
+	add_wait_queue(&adb_wait, &wait);
+	current->state = TASK_INTERRUPTIBLE;
+
+	while (!state->req.got_reply) {
+		if (file->f_flags & O_NONBLOCK) {
+			ret = -EAGAIN;
+			break;
+		}
+		if (current->signal & ~current->blocked) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+		schedule();
+	}
+
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&adb_wait, &wait);
+
+	return ret;
+}
+
+static void adb_write_done(struct cuda_request *req)
+{
+	if (!req->got_reply) {
+		req->reply_len = 0;
+		req->got_reply = 1;
+	}
+	wake_up_interruptible(&adb_wait);
+}
+
+static int adb_open(struct inode *inode, struct file *file)
+{
+	struct adbdev_state *state;
+
+	if (MINOR(inode->i_rdev) > 0)
+		return -ENXIO;
+	state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
+	if (state == 0)
+		return -ENOMEM;
+	file->private_data = state;
+	state->req.reply_expected = 0;
+	return 0;
+}
+
+static int adb_release(struct inode *inode, struct file *file)
+{
+	struct adbdev_state *state = file->private_data;
+
+	if (state) {
+		file->private_data = NULL;
+		if (state->req.reply_expected && !state->req.got_reply)
+			if (adb_wait_reply(state, file))
+				return 0;
+		kfree(state);
+	}
+	return 0;
+}
+
+static long long adb_lseek(struct inode *inode, struct file *file,
+			   long long offset, int origin)
+{
+	return -ESPIPE;
+}
+
+static long adb_read(struct inode *inode, struct file *file,
+		     char *buf, unsigned long count)
+{
+	int ret;
+	struct adbdev_state *state = file->private_data;
+
+	if (count < 2)
+		return -EINVAL;
+	if (count > sizeof(state->req.reply))
+		count = sizeof(state->req.reply);
+	ret = verify_area(VERIFY_WRITE, buf, count);
+	if (ret)
+		return ret;
+
+	if (!state->req.reply_expected)
+		return 0;
+
+	ret = adb_wait_reply(state, file);
+	if (ret)
+		return ret;
+
+	ret = state->req.reply_len;
+	copy_to_user(buf, state->req.reply, ret);
+	state->req.reply_expected = 0;
+
+	return ret;
+}
+
+static long adb_write(struct inode *inode, struct file *file,
+		      const char *buf, unsigned long count)
+{
+	int ret;
+	struct adbdev_state *state = file->private_data;
+
+	if (count < 2 || count > sizeof(state->req.data))
+		return -EINVAL;
+	ret = verify_area(VERIFY_READ, buf, count);
+	if (ret)
+		return ret;
+
+	if (state->req.reply_expected && !state->req.got_reply) {
+		/* A previous request is still being processed.
+		   Wait for it to finish. */
+		ret = adb_wait_reply(state, file);
+		if (ret)
+			return ret;
+	}
+
+	state->req.nbytes = count;
+	state->req.done = adb_write_done;
+	copy_from_user(state->req.data, buf, count);
+	state->req.reply_expected = 1;
+	state->req.got_reply = 0;
+	cuda_send_request(&state->req);
+
+	return count;
+}
+
+static struct file_operations adb_fops = {
+	adb_lseek,
+	adb_read,
+	adb_write,
+	NULL,		/* no readdir */
+	NULL,		/* no poll yet */
+	NULL,		/* no ioctl yet */
+	NULL,		/* no mmap */
+	adb_open,
+	adb_release
+};
+
+void adbdev_init()
+{
+	if (register_chrdev(ADB_MAJOR, "adb", &adb_fops))
+		printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR);
+}
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/ati-gt.h linux/drivers/macintosh/ati-gt.h
--- v2.1.50/linux/drivers/macintosh/ati-gt.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/ati-gt.h	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,149 @@
+#if 0		/* not filled inaty_gt_reg_init yet */
+/* Register values for 1280x1024, 75Hz mode (20) */
+static struct aty_regvals aty_gt_reg_init_20 = {
+	{ 0x10, 0x28, 0x3c },
+	{ },
+	{ }	/* pixel clock = 134.61MHz for V=74.81Hz */
+};
+
+/* Register values for 1280x960, 75Hz mode (19) */
+static struct aty_regvals aty_gt_reg_init_19 = {
+	{ 0x10, 0x28, 0x3c },
+	{ },
+	{ }	/* pixel clock = 126.01MHz for V=75.01 Hz */
+};
+
+/* Register values for 1152x870, 75Hz mode (18) */
+static struct aty_regvals aty_gt_reg_init_18 = {
+	{ 0x10, 0x28, 0x50 },
+	{ },
+	{ }	/* pixel clock = 100.33MHz for V=75.31Hz */
+};
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct aty_regvals aty_gt_reg_init_17 = {
+	{ 0x10, 0x28, 0x50 },
+	{ },
+	{ }	/* pixel clock = 79.55MHz for V=74.50Hz */
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct aty_regvals aty_gt_reg_init_15 = {
+	{ 0x10, 0x28, 0x50 },
+	{ },
+	{ }	/* pixel clock = 78.12MHz for V=72.12Hz */
+};
+
+#endif
+
+
+/* Register values for 1280x1024, 60Hz mode (20) */
+static struct aty_regvals aty_gt_reg_init_20 = {
+   { 0, 0, 0 },
+
+    { 0x310086, 0x310084, 0x310084 },
+    { 0x3070200, 0x30e0300, 0x30e0300 },
+    { 0x2002312, 0x3002312, 0x3002312 },
+
+    0x7f00a5, 0x2ff0325, 0x260302, 0x20100000,
+    { 0x88, 0x7 }
+};     
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct aty_regvals aty_gt_reg_init_17 = {
+    { 0, 0, 0 },
+
+    { 0xc0085, 0xc0083, 0xc0083 },
+    { 0x3070200, 0x30e0300, 0x30e0300 },
+    { 0x2002312, 0x3002312, 0x3002312 },
+
+    0x7f00a3, 0x2ff031f, 0x30300, 0x20100000,
+    { 0x41, 0x3 }
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct aty_regvals aty_gt_reg_init_15 = {
+    { 0, 0, 0 },
+
+    { 0x310086, 0x310084, 0x310084 },
+    { 0x3070200, 0x30e0300, 0x30e0300 },
+    { 0x2002312, 0x3002312, 0x3002312 },
+
+    0x7f00a5, 0x2ff0325, 0x260302, 0x20100000,
+    { 0x88, 0x7 }
+};    
+
+/* Register values for 1024x768, 60Hz mode (14) */
+static struct aty_regvals aty_gt_reg_init_14 = {
+	{ 0, 0, 0 },
+
+	{ 0x310086, 0x310084, 0x310084 },
+	{ 0x3060200, 0x30d0300, 0x30d0300 },
+	{ 0x2002312, 0x3002312, 0x3002312 },
+
+	0x7f00a7, 0x2ff0325, 0x260302, 0x20100000,
+	{ 0x6c, 0x6 }
+};  
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct aty_regvals aty_gt_reg_init_13 = {
+	{ 0x200, 0x200, 0x200 },
+
+	{ 0x28006f, 0x28006d, 0x28006c },
+	{ 0x3050200, 0x30b0300, 0x30e0600 },
+	{ 0x2002312, 0x3002312, 0x6002312 },
+
+	0x67008f, 0x26f029a, 0x230270, 0x1a100040,
+        { 0x4f, 0x05 }
+};
+
+#if 0		/* not filled in yet */
+/* Register values for 800x600, 75Hz mode (12) */
+static struct aty_regvals aty_gt_reg_init_12 = {
+	{ 0x10, 0x28, 0x50 },
+	{ },
+	{ }	/* pixel clock = 49.11MHz for V=74.40Hz */
+};
+
+/* Register values for 800x600, 72Hz mode (11) */
+static struct aty_regvals aty_gt_reg_init_11 = {
+	{ 0x10, 0x28, 0x50 },
+	{ },
+	{ }	/* pixel clock = 49.63MHz for V=71.66Hz */
+};
+
+/* Register values for 800x600, 60Hz mode (10) */
+static struct aty_regvals aty_gt_reg_init_10 = {
+	{ 0x10, 0x28, 0x50 },
+	{ },
+	{ }	/* pixel clock = 41.41MHz for V=59.78Hz */
+};
+
+/* Register values for 640x870, 75Hz Full Page Display (7) */
+static struct aty_regvals aty_gt_reg_init_7 = {
+	{ 0x10, 0x30, 0x68 },
+	{ },
+	{ }	/* pixel clock = 57.29MHz for V=75.01Hz */
+};
+#endif
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct aty_regvals aty_gt_reg_init_6 = {
+	{ 0x200, 0x200, 0x200 },
+
+	{ 0x28005b, 0x280059, 0x280058 },
+	{ 0x3040200, 0x3060300, 0x30c0600 },
+	{ 0x2002312, 0x3002312, 0x6002312 },
+
+	0x4f006b, 0x1df020c, 0x2301e2, 0x14100040,
+        { 0x35, 0x07 }
+};
+
+#if 0		/* not filled in yet */
+/* Register values for 640x480, 60Hz mode (5) */
+static struct aty_regvals aty_gt_reg_init_5 = {
+	{ 0x200, 0x200, 0x200 },
+	{ },
+        { 0x35, 0x07 }
+};
+#endif
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/ati-vt.h linux/drivers/macintosh/ati-vt.h
--- v2.1.50/linux/drivers/macintosh/ati-vt.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/ati-vt.h	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,147 @@
+#if 0		/* not filled inaty_vt_reg_init yet */
+/* Register values for 640x870, 75Hz Full Page Display (7) */
+static struct aty_regvals aty_vt_reg_init_7 = {
+	{ 0x10, 0x30, 0x68 },
+	{ },
+	{ }	/* pixel clock = 57.29MHz for V=75.01Hz */
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct aty_regvals aty_vt_reg_init_15 = {
+	{ 0x10, 0x28, 0x50 },
+	{ },
+	{ }	/* pixel clock = 78.12MHz for V=72.12Hz */
+};
+
+#endif
+
+/* Register values for 1280x1024, 60Hz mode (20) */
+static struct aty_regvals aty_vt_reg_init_20 = {
+	{ 0, 0, 0 },
+	{ 0x2e02a7, 0x2e02a7, 0x2e02a7},
+	{ 0x3070200, 0x3070200, 0x3070200},
+	{ 0xa00cb22, 0xb00cb23, 0xe00cb24 },
+	
+	0x9f00d2, 0x3ff0429, 0x30400, 0x28000000,
+	{ 0x00, 0xaa }
+};
+
+/* Register values for 1152x870, 75Hz mode (18) */
+static struct aty_regvals aty_vt_reg_init_18 = {
+	{ 0, 0, 0 },
+	{ 0x300295, 0x300194, 0x300194 },
+	{ 0x3060200, 0x30e0300, 0x30e0300 },
+	{ 0xa00cb21, 0xb00cb22, 0xe00cb23 },
+    
+    0x8f00b5, 0x3650392, 0x230368, 0x24000000,
+    { 0x00, 0x9d }
+	/* pixel clock = 100.33MHz for V=75.31Hz */
+};
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct aty_regvals aty_vt_reg_init_17 = {
+    { 0, 0, 0 },
+
+    { 0x2c0283, 0x2c0182, 0x2c0182 },
+    { 0x3060200, 0x30a0300, 0x30a0300 },
+    { 0xa00cb21, 0xb00cb22, 0xe00cb23 },
+    
+    0x7f00a3, 0x2ff031f, 0x30300, 0x20000000,
+    { 0x01, 0xf7 }
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct aty_regvals aty_vt_reg_init_15 = {
+    { 0, 0, 0 },
+
+    { 0x310284, 0x310183, 0x310183 },
+    { 0x3060200, 0x3090300, 0x3090600 },
+    { 0xa00cb21, 0xb00cb22, 0xe00cb23 },
+    
+    0x7f00a5, 0x2ff0325, 0x260302, 0x20000000,
+    { 0x01, 0xeb }
+};    
+
+/* Register values for 1024x768, 60Hz mode (14) */
+static struct aty_regvals aty_vt_reg_init_14 = {
+	{ 0, 0, 0 },
+    { 0x310284, 0x310183, 0x310183 },
+    { 0x3060200, 0x3080300, 0x30f0600 },
+    { 0xa00cb21, 0xb00cb22, 0xe00cb23 },
+    
+    0x7f00a7, 0x2ff0325, 0x260302, 0x20000000,
+    { 0x01, 0xcc }
+};  
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct aty_regvals aty_vt_reg_init_13 = {
+	{ 0, 0, 0 },
+
+    { 0x28026d, 0x28016c, 0x28016c },
+    { 0x3060200, 0x3080300, 0x30f0600 },
+    { 0xa00cb21, 0xb00cb21, 0xe00cb22 },
+    
+    0x67008f, 0x26f029a, 0x230270, 0x1a000000,
+    { 0x01, 0xb4 }
+};
+
+/* Register values for 800x600, 75Hz mode (12) */
+static struct aty_regvals aty_vt_reg_init_12 = {
+	{ 0, 0, 0 },
+    { 0x2a0267, 0x2a0166, 0x2a0565 },
+    { 0x3040200, 0x3060300, 0x30d0600 },
+    { 0xa00cb21, 0xb00cb21, 0xe00cb22 },
+    
+    0x630083, 0x2570270, 0x30258, 0x19000000,
+    { 0x01, 0x9c }
+	/* pixel clock = 49.11MHz for V=74.40Hz */
+};
+
+/* Register values for 800x600, 72Hz mode (11) */
+static struct aty_regvals aty_vt_reg_init_11 = {
+	{ 0, 0, 0 },
+    
+    { 0x2f026c, 0x2f016b, 0x2f056a },
+    { 0x3040200, 0x3060300, 0x30d0600 },
+    { 0xa00cb21, 0xb00cb21, 0xe00cb22 },
+    
+    0x630081, 0x257029b, 0x6027c, 0x19000000,
+    { 0x01, 0x9d }
+	/* pixel clock = 49.63MHz for V=71.66Hz */
+};
+
+/* Register values for 800x600, 60Hz mode (10) */
+static struct aty_regvals aty_vt_reg_init_10 = {
+	{ 0, 0, 0 },
+    { 0x30026a, 0x300169, 0x300568 },
+    { 0x3030200, 0x3050300, 0x30b0600 },
+    { 0xa00cb21, 0xb00cb21, 0xe00cb22 },
+    
+    0x630083, 0x2570273, 0x40258, 0x19000000,
+    { 0x02, 0xfb }
+/* pixel clock = 41.41MHz for V=59.78Hz */
+};
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct aty_regvals aty_vt_reg_init_6 = {
+	{ 0, 0, 0 },
+
+    { 0x280259, 0x280158, 0x280557 },
+    { 0x3030200, 0x3040300, 0x3080600 },
+    { 0xa00cb21, 0xb00cb21, 0xe00cb22 },
+    
+    0x4f006b, 0x1df020c, 0x2301e2, 0x14000000,
+    { 0x02, 0xbe }
+};
+
+/* Register values for 640x480, 60Hz mode (5) */
+static struct aty_regvals aty_vt_reg_init_5 = {
+	{ 0, 0, 0 },
+	
+    { 0x2c0253, 0x2c0152, 0x2c0551 },
+    { 0x3030200, 0x3040300, 0x3060600 },
+    { 0xa00cb21, 0xb00cb21, 0xe00cb22 },
+    
+    0x4f0063, 0x1df020c, 0x2201e9, 0x14000000,
+    { 0x02, 0x9e }
+};
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/aty.c linux/drivers/macintosh/aty.c
--- v2.1.50/linux/drivers/macintosh/aty.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/aty.c	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,568 @@
+/*
+ * aty.c: Console support for ATI/mach64 display adaptor cards.
+ *
+ * Copyright (C) 1997 Michael AK Tesch
+ *  written with much help from Jon Howell
+ *  changes to support the vt chip set by harry ac eaton
+ * 
+ * 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.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/vc_ioctl.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/nvram.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <linux/selection.h>
+#include <linux/vt_kern.h>
+#include "pmac-cons.h"
+#include "aty.h"
+
+struct aty_cmap_regs {
+	unsigned char windex;
+	unsigned char lut;
+	unsigned char mask;
+	unsigned char rindex;
+	unsigned char cntl;
+};
+
+struct aty_regvals {
+     int	offset[3];		 /* first pixel address */
+
+     int	crtc_h_sync_strt_wid[3]; /* depth dependant */
+     int	crtc_gen_cntl[3];
+     int	mem_cntl[3];
+
+     int	crtc_h_tot_disp;         /* mode dependant */
+     int	crtc_v_tot_disp;
+     int	crtc_v_sync_strt_wid;
+     int	crtc_off_pitch;
+
+     unsigned char clock_val[2];        /* vals for 20 and 21 */
+};
+
+/*static void set_aty_clock(unsigned char *params);*/
+static int aty_vram_reqd(int vmode, int cmode);
+
+static unsigned char *frame_buffer;
+static int total_vram;		/* total amount of video memory, bytes */
+static int is_vt_chip;		/* whether a vt chip type was detected */
+
+static unsigned long aty_regbase;
+static struct aty_cmap_regs *aty_cmap_regs;
+
+/* this array contains the number of bytes/line for each mode and color depth */
+static int pitch[20][3] = {
+	{0,0,0},  /* mode 1?? */
+	{0,0,0},  /* mode 2?? */
+	{0,0,0},  /* mode 3??*/
+	{0,0,0},  /* mode 4?? */
+	{640, 1280, 2560},  /* mode 5 */
+	{640, 1280, 2560},  /* mode 6 */
+	{640, 1280, 2560},  /* mode 7 */
+	{800, 1600, 3200},  /* mode 8 */
+	{0,0,0},  /* mode 9 ??*/
+	{800, 1600, 3200},  /* mode 10 */
+	{800, 1600, 3200},  /* mode 11 */
+	{800, 1600, 3200},  /* mode 12 */
+	{832, 1664, 3328},  /* mode 13 */
+	{1024, 2048, 4096},  /* mode 14 */
+	{1024, 2048, 4096},  /* mode 15 */
+	{1024, 2048, 4096},  /* mode 16 */
+	{1024, 2048, 4096},  /* mode 17 */
+	{1152, 2304, 4608},  /* mode 18 */
+	{1280, 2560, 5120},  /* mode 19 */
+	{1280, 2560, 5120}   /* mode 20 */
+};
+
+#include "ati-gt.h"
+#include "ati-vt.h"
+
+static struct aty_regvals *aty_gt_reg_init[20] = {
+	NULL, NULL, NULL, NULL,
+	&aty_gt_reg_init_6,
+	&aty_gt_reg_init_6,
+	NULL,
+	NULL, NULL,
+	NULL,
+	NULL,NULL,
+	&aty_gt_reg_init_13,
+	&aty_gt_reg_init_14,
+	&aty_gt_reg_init_15,
+	NULL,
+	&aty_gt_reg_init_17,
+	NULL,
+	NULL,
+	&aty_gt_reg_init_20
+};
+
+static struct aty_regvals *aty_vt_reg_init[20] = {
+	NULL, NULL, NULL, NULL,
+	&aty_vt_reg_init_5,
+	&aty_vt_reg_init_6,
+	NULL,
+	NULL, NULL,
+	&aty_vt_reg_init_10,
+	&aty_vt_reg_init_11,
+	&aty_vt_reg_init_12,
+	&aty_vt_reg_init_13,
+	&aty_vt_reg_init_14,
+	&aty_vt_reg_init_15,
+	NULL,
+	&aty_vt_reg_init_17,
+	&aty_vt_reg_init_18,
+	NULL,
+	&aty_vt_reg_init_20
+};
+
+static inline int aty_vram_reqd(int vmode, int cmode)
+{
+	return vmode_attrs[vmode-1].vres
+		* pitch[vmode-1][cmode];
+}
+
+extern inline unsigned aty_ld_rev(volatile unsigned long addr)
+{
+     unsigned val;
+
+     (long)addr += (long)aty_regbase;
+     asm volatile("lwbrx %0,0,%1" : "=r" (val) : "r" (addr));
+     return val;
+}
+
+extern inline void aty_st_rev(volatile unsigned long addr, unsigned val)
+{
+     (long)addr += (long)aty_regbase;
+     asm volatile("stwbrx %0,0,%1" : : "r" (val), "r" (addr) : "memory");
+}
+
+extern inline unsigned char aty_ld_byte(volatile unsigned long addr)
+{
+     unsigned char val;
+
+     val = *(char*)((long)addr+(long)aty_regbase);
+     return val;
+}
+
+extern inline void aty_st_byte(volatile unsigned long addr, unsigned char val)
+{
+     *(unsigned char*)(addr+(unsigned long)aty_regbase) = val;
+}
+
+void
+aty_st_514( int offset, char val )
+{
+     aty_WaitQueue(5);
+     aty_st_byte( DAC_CNTL, 1);
+     aty_st_byte( DAC_W_INDEX, offset & 0xff );   /* right addr byte */
+     aty_st_byte( DAC_DATA, (offset>>8) & 0xff ); /* left addr byte */
+     aty_st_byte( DAC_MASK, val );
+     aty_st_byte( DAC_CNTL, 0 );
+}
+
+void
+aty_st_pll( int offset, char val )
+{
+     aty_WaitQueue(3);
+     aty_st_byte( CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN );   /* write addr byte */
+     aty_st_byte( CLOCK_CNTL + 2, val); /* write the register value */
+     aty_st_byte( CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN);
+}
+
+#if 0
+unsigned char
+aty_ld_514( int offset )
+{
+/* do the same thing as aty_st_514, just read the DAC_MASK instead of writing*/
+}
+#endif
+
+void
+aty_set_palette(unsigned char red[], unsigned char green[],
+		unsigned char blue[], int index, int ncolors)
+{
+     int i,scale;
+
+     aty_WaitQueue(2);
+     aty_st_byte(DAC_CNTL, aty_ld_byte(DAC_CNTL) & 0xfc);
+     aty_st_byte(DAC_REGS + DAC_MASK, 0xff);
+     eieio();
+     scale = (is_vt_chip) ? ((color_mode == CMODE_16) ? 3 : 0) : 0;
+     for (i = 0; i < ncolors; ++i) {
+	  aty_WaitQueue(4);
+          aty_cmap_regs->windex = (index + i) << scale;	eieio();
+          aty_cmap_regs->lut = red[i];		eieio();
+          aty_cmap_regs->lut = green[i];	eieio();
+          aty_cmap_regs->lut = blue[i];		eieio();
+     }
+   
+}
+
+void
+map_aty_display(struct device_node *dp)
+{
+     int i, sense;
+     unsigned long addr;
+     unsigned char bus, devfn;
+     unsigned short cmd;
+
+     if (dp->next != 0)
+	  printk("Warning: only using first ATI card detected\n");
+     if (dp->n_addrs != 1)
+	  panic("expecting 1 addresses for ATY (got %d)", dp->n_addrs);
+
+     aty_regbase = (int)ioremap((0x7ffc00 + dp->addrs[0].address), 0x1000);
+     aty_cmap_regs = (struct aty_cmap_regs *)(aty_regbase+0xC0);
+
+     /* enable memory-space accesses using config-space command register */
+     if (pci_device_loc(dp, &bus, &devfn) == 0) {
+	  pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
+	  if (cmd != 0xffff) {
+	       cmd |= PCI_COMMAND_MEMORY;
+	       pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
+	  }
+     }
+
+     switch( aty_ld_rev(MEM_CNTL)&MEM_SIZE_ALIAS ) {
+     case MEM_SIZE_512K:
+	  total_vram = 0x80000;
+	  break;
+     case MEM_SIZE_1M:
+	  total_vram = 0x100000;
+	  break;
+     case MEM_SIZE_2M:
+	  total_vram = 0x200000;
+	  break;
+     case MEM_SIZE_4M:
+	  total_vram = 0x400000;
+	  break;
+     case MEM_SIZE_6M:
+	  total_vram = 0x600000;
+	  break;
+     case MEM_SIZE_8M:
+	  total_vram = 0x800000;
+	  break;
+     default:
+	  total_vram = 0x80000;
+     }
+#if 1
+     printk("aty_display_init: node = %p, addrs = ", dp->node);
+     printk(" %x(%x)", dp->addrs[0].address, dp->addrs[0].size);
+     printk(", intrs =");
+     for (i = 0; i < dp->n_intrs; ++i)
+	  printk(" %x", dp->intrs[i]);
+     printk( "\nregbase: %x pci loc: %x:%x total_vram: %x cregs: %x\n", (int)aty_regbase, 
+	     bus, devfn, total_vram, (int)aty_cmap_regs );
+#endif
+     is_vt_chip = ((aty_ld_rev(CONFIG_CHIP_ID) & CFG_CHIP_TYPE) == MACH64_VT_ID);
+     /* Map in frame buffer */
+     addr = dp->addrs[0].address;
+
+     /* use the big-endian aperture (??) */
+     addr += 0x800000;
+     frame_buffer = ioremap(addr, 0x800000);
+     
+
+     /*	sense = read_aty_sense(); XXX not yet, just give it mine */
+     sense = 0x62b;
+     if (video_mode == VMODE_NVRAM) {
+	  video_mode = nvram_read_byte(NV_VMODE);
+	  if (video_mode <= 0 || video_mode > VMODE_MAX
+	      || ((is_vt_chip) ? aty_vt_reg_init[video_mode-1] : aty_gt_reg_init[video_mode-1]) == 0)
+	       video_mode = VMODE_CHOOSE;
+     }
+     if (video_mode == VMODE_CHOOSE)
+	  video_mode = map_monitor_sense(sense);
+     if (((is_vt_chip) ? aty_vt_reg_init[video_mode-1] : aty_gt_reg_init[video_mode-1]) == 0)
+	  video_mode = VMODE_640_480_60;
+
+     /*
+      * Reduce the pixel size if we don't have enough VRAM.
+      */
+
+     if (color_mode == CMODE_NVRAM)
+        color_mode = nvram_read_byte(NV_CMODE);
+     if (color_mode < CMODE_8 || color_mode > CMODE_32)
+	color_mode = CMODE_8;
+     while (aty_vram_reqd(video_mode, color_mode) > total_vram) {
+     	while (color_mode > CMODE_8
+	    && aty_vram_reqd(video_mode, color_mode) > total_vram)
+	  --color_mode;
+        /*
+	 * adjust the video mode smaller if there still is not enough VRAM
+	 */
+	if (aty_vram_reqd(video_mode, color_mode) > total_vram)
+	  while ((((is_vt_chip) ? aty_vt_reg_init[--video_mode - 1]
+	        : aty_gt_reg_init[--video_mode -1 ]) == 0) && (video_mode > VMODE_640_480_60)) ;
+    }
+}
+
+#if 0
+static void
+set_aty_clock(unsigned char *params)
+{
+     /* done in aty_init...probably need to change for different modes */
+     printk("tried to set ATY clock\n");
+}
+#endif
+
+void
+RGB514_Program(int cmode)
+{
+     typedef struct {
+          char    pixel_dly;
+          char    misc2_cntl;
+          char    pixel_rep;
+          char    pixel_cntl_index;
+          char    pixel_cntl_v1;
+     } RGB514_DAC_Table;
+
+     static  RGB514_DAC_Table RGB514DAC_Tab[8] = {
+          { 0, 0x41, 0x03, 0x71, 0x45 },          // 8bpp
+          { 0, 0x45, 0x04, 0x0c, 0x01 },          // 555
+          { 0, 0x45, 0x06, 0x0e, 0x00 },          // XRGB
+     };
+     RGB514_DAC_Table *pDacProgTab;
+
+     pDacProgTab = &RGB514DAC_Tab[cmode];
+
+     aty_st_514(0x90, 0x00);
+     aty_st_514(0x04, pDacProgTab->pixel_dly);
+     aty_st_514(0x05, 0x00);
+
+     aty_st_514(0x2, 0x1);
+     aty_st_514(0x71, pDacProgTab->misc2_cntl);
+     aty_st_514(0x0a, pDacProgTab->pixel_rep);
+
+     aty_st_514(pDacProgTab->pixel_cntl_index, pDacProgTab->pixel_cntl_v1);
+}
+
+/* The vt chipset seems to need a specialized color table for 15 bit mode */
+void
+VT_Program(int cmode)
+{
+#if 0
+	int i;
+	if (cmode != CMODE_8) {
+		aty_WaitQueue(2);
+		aty_cmap_regs->mask = 0xff; eieio();
+		aty_cmap_regs->windex = 0; eieio();
+		for (i = 0; i < 0x100; i++) {
+			aty_WaitQueue(3);
+			aty_cmap_regs->lut = i;
+			aty_cmap_regs->lut = i;
+			aty_cmap_regs->lut = i; eieio();
+		}
+	}
+#endif
+}
+
+void
+aty_init()
+{
+     int i, yoff, hres;
+     unsigned *p;
+     struct aty_regvals *init;
+
+     if (video_mode <= 0 || video_mode > VMODE_MAX
+	 || (init = ((is_vt_chip) ? aty_vt_reg_init[video_mode-1] : aty_gt_reg_init[video_mode-1])) == 0)
+	  panic("aty: display mode %d not supported", video_mode);
+     n_scanlines = vmode_attrs[video_mode-1].vres;
+     hres = vmode_attrs[video_mode-1].hres;
+     pixel_size = 1 << color_mode;
+     line_pitch = pitch[video_mode-1][color_mode];
+     row_pitch = line_pitch * 16;
+
+     aty_st_rev(BUS_CNTL, aty_ld_rev(BUS_CNTL) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK);
+		
+     /* Reset engine */
+     i = aty_ld_rev(GEN_TEST_CNTL);
+     aty_st_rev(GEN_TEST_CNTL, i & ~GUI_ENGINE_ENABLE);
+     eieio();
+     aty_WaitIdleEmpty();
+     aty_st_rev(GEN_TEST_CNTL, i | GUI_ENGINE_ENABLE);
+     aty_WaitIdleEmpty();
+			
+     i = aty_ld_byte(CRTC_GEN_CNTL+3);
+     aty_st_byte(CRTC_GEN_CNTL+3, i | (CRTC_EXT_DISP_EN >> 24));
+
+     i = aty_ld_byte(GEN_TEST_CNTL);
+     aty_st_byte(GEN_TEST_CNTL, i | GEN_OVR_OUTPUT_EN );
+
+     if (!is_vt_chip) {		
+     	RGB514_Program(color_mode);
+
+     	aty_WaitIdleEmpty();
+
+     	aty_st_514(0x06, 0x02);
+     	aty_st_514(0x10, 0x01);
+     	aty_st_514(0x70, 0x01);
+     	aty_st_514(0x8f, 0x1f);
+     	aty_st_514(0x03, 0x00);
+     	aty_st_514(0x05, 0x00);
+     
+     	aty_st_514(0x20, init->clock_val[0]);
+    	aty_st_514(0x21, init->clock_val[1]);
+     } else {
+	VT_Program(color_mode);
+    	aty_st_pll(PLL_MACRO_CNTL, 0xb5);
+    	aty_st_pll(PLL_REF_DIV, 0x2d);
+    	aty_st_pll(PLL_GEN_CNTL, 0x14);
+    	aty_st_pll(MCLK_FB_DIV, 0xbd);
+    	aty_st_pll(PLL_VCLK_CNTL, 0x0b);
+    	aty_st_pll(VCLK_POST_DIV, init->clock_val[0]);
+    	aty_st_pll(VCLK0_FB_DIV, init->clock_val[1]);
+    	aty_st_pll(VCLK1_FB_DIV, 0xd6);
+    	aty_st_pll(VCLK2_FB_DIV, 0xee);
+    	aty_st_pll(VCLK3_FB_DIV, 0xf8);
+    	aty_st_pll(PLL_XCLK_CNTL, 0x0);
+    	aty_st_pll(PLL_TEST_CTRL, 0x0);
+     	aty_st_pll(PLL_TEST_COUNT, 0x0);
+     }
+ 	  	
+     aty_ld_byte( DAC_REGS ); /* clear counter */
+			
+     aty_WaitIdleEmpty();
+
+     aty_st_rev(CRTC_H_TOTAL_DISP, init->crtc_h_tot_disp);
+     aty_st_rev(CRTC_H_SYNC_STRT_WID, init->crtc_h_sync_strt_wid[color_mode]);
+     aty_st_rev(CRTC_V_TOTAL_DISP, init->crtc_v_tot_disp);
+     aty_st_rev(CRTC_V_SYNC_STRT_WID, init->crtc_v_sync_strt_wid);
+
+     aty_st_byte(CLOCK_CNTL, 0);
+     aty_st_byte(CLOCK_CNTL, CLOCK_STROBE);
+
+     aty_st_rev(CRTC_OFF_PITCH, init->crtc_off_pitch);
+     
+     aty_st_rev(CRTC_VLINE_CRNT_VLINE, 0x14e01d0);
+/* The magic constant below translates into: 
+ * 5   = No RDY delay, 1 wait st for mem write, increment during burst transfer
+ * 9   = DAC access delayed, 1 wait state for DAC
+ * 0   = Disables interupts for FIFO errors
+ * e   = Allows FIFO to generate 14 wait states before generating error
+ * 1   = DAC snooping disabled, ROM disabled
+ * 0   = ROM page at 0 (disabled so doesn't matter)
+ * f   = 15 ROM wait states (disabled so doesn't matter) 
+ * f   = 15 BUS wait states (I'm not sure this applies to PCI bus types)
+ * at some point it would be good to experiment with bench marks to see if
+ * we can gain some speed by fooling with the wait states etc.
+ */
+     aty_st_rev(BUS_CNTL, 0x590e10ff);
+     i = aty_ld_rev(MEM_CNTL) & MEM_SIZE_ALIAS;
+     if (total_vram >= 0x400000)
+        aty_st_rev(MEM_CNTL, (init->mem_cntl[color_mode] &0xffff0000) | 0x0538 | i);
+     else
+        aty_st_rev(MEM_CNTL, (init->mem_cntl[color_mode] & ~MEM_SIZE_ALIAS) | i ); 
+     aty_st_rev(CRTC_INT_CNTL, 0x2);
+     aty_WaitIdleEmpty();
+/* These magic constants are harder to figure out
+ * on the vt chipset bit 3 set makes the screen brighter
+ * and bit 15 makes the screen black! But nothing else
+ * seems to matter for the vt DAC_CNTL
+ */
+     if (is_vt_chip)
+	aty_st_rev(DAC_CNTL, 0x47012104);
+     else
+        aty_st_rev(DAC_CNTL, 0x47012100);
+
+     aty_st_byte(DAC_MASK, 0xff);
+
+     aty_st_rev(CRTC_INT_CNTL, 0x00000002);
+     
+     aty_st_byte(CRTC_FIFO, ((char*)&init->crtc_gen_cntl[color_mode])[1] );
+     aty_st_byte(CRTC_PIX_WIDTH, ((char*)&init->crtc_gen_cntl[color_mode])[2] );
+     aty_st_byte(CRTC_EXT_DISP, ((char*)&init->crtc_gen_cntl[color_mode])[0] );
+     
+     aty_st_rev(GEN_TEST_CNTL, 0x300); /* gui_en block_en*/
+
+     pmac_init_palette();		/* Initialize colormap */
+     yoff = (n_scanlines % 16) / 2;
+     fb_start = frame_buffer + yoff * line_pitch + init->offset[color_mode];
+
+     /* Clear screen */
+     p = (unsigned *) fb_start;
+
+     for (i = n_scanlines * line_pitch * pixel_size / sizeof(unsigned); i != 0; --i)
+	  *p++ = 0;
+     display_info.height = n_scanlines;
+     display_info.width = hres;
+     display_info.depth = pixel_size * 8;
+     display_info.pitch = line_pitch;
+     display_info.mode = video_mode;
+     strncpy(display_info.name, "ATY Mach64", sizeof(display_info.name));
+     display_info.fb_address = (unsigned long) frame_buffer + init->offset[color_mode];
+     display_info.cmap_adr_address = (unsigned long) &aty_cmap_regs->windex;
+     display_info.cmap_data_address = (unsigned long) &aty_cmap_regs->lut;
+     display_info.disp_reg_address = aty_regbase;
+}
+
+int
+aty_setmode(struct vc_mode *mode, int doit)
+{
+	int cmode;
+#if 0
+	if (mode->mode == 21) {
+		printk("hace: about to set 0x%x to 0x%x\n",mode->depth, mode->pitch & 0xff);
+		aty_st_byte(mode->depth, mode->pitch & 0xff);
+		return 0;
+	}
+
+	if (mode->mode == 0) {
+		printk("hace: 0x%x contains 0x%x\n",mode->depth, aty_ld_byte(mode->depth));
+		return 0;
+	}
+#endif		
+	
+	if (mode->mode <= 0 || mode->mode > VMODE_MAX
+	    || ((is_vt_chip) ? aty_vt_reg_init[mode->mode-1] : aty_gt_reg_init[mode->mode-1]) == NULL)
+		return -EINVAL;
+	switch (mode->depth) {
+	case 24:
+	case 32:
+		cmode = CMODE_32;
+		break;
+	case 16:
+		cmode = CMODE_16;
+		break;
+	case 8:
+	case 0:		/* (default) */
+		cmode = CMODE_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (aty_vram_reqd(mode->mode, cmode) > total_vram) {
+		return -EINVAL;
+	}
+	if (doit) {
+		video_mode = mode->mode;
+		color_mode = cmode;
+		aty_init();
+	}
+	return 0;
+}
+
+void
+aty_set_blanking(int blank_mode)
+{
+	char gen_cntl;
+
+	gen_cntl = aty_ld_byte(CRTC_GEN_CNTL);
+	if (blank_mode & VESA_VSYNC_SUSPEND)
+		gen_cntl |= 0x8;
+	if (blank_mode & VESA_HSYNC_SUSPEND)
+		gen_cntl |= 0x4;
+	if ((blank_mode & VESA_POWERDOWN) == VESA_POWERDOWN)
+		gen_cntl |= 0x40;
+	if (blank_mode == VESA_NO_BLANKING)
+		gen_cntl &= ~(0x4c);
+	aty_st_byte(CRTC_GEN_CNTL, gen_cntl);
+}
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/aty.h linux/drivers/macintosh/aty.h
--- v2.1.50/linux/drivers/macintosh/aty.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/aty.h	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,614 @@
+/*
+ * Exported procedures for the ATI/mach64 display driver on PowerMacs.
+ *
+ * Copyright (C) 1997 Michael AK Tesch
+ *  written with much help from Jon Howell
+ *	
+ * 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.
+ */
+
+extern void map_aty_display(struct device_node *);
+extern void aty_init(void);
+extern int aty_setmode(struct vc_mode *mode, int doit);
+extern void aty_set_palette(unsigned char red[], unsigned char green[],
+			    unsigned char blue[], int index, int ncolors);
+extern void aty_set_blanking(int blank_mode);
+
+/*
+ * most of the rest of this file comes from ATI sample code
+ */
+#ifndef REGMACH64_H
+#define REGMACH64_H
+
+/* NON-GUI MEMORY MAPPED Registers - expressed in BYTE offsets */
+
+#define CRTC_H_TOTAL_DISP       0x0000  /* Dword offset 00 */
+#define CRTC_H_SYNC_STRT_WID    0x0004  /* Dword offset 01 */
+#define CRTC_H_SYNC_STRT        0x0004
+#define CRTC_H_SYNC_DLY         0x0005
+#define CRTC_H_SYNC_WID         0x0006
+
+#define CRTC_V_TOTAL_DISP       0x0008  /* Dword offset 02 */
+#define CRTC_V_TOTAL            0x0008
+#define CRTC_V_DISP             0x000a
+#define CRTC_V_SYNC_STRT_WID    0x000C  /* Dword offset 03 */
+#define CRTC_V_SYNC_STRT        0x000c
+#define CRTC_V_SYNC_WID         0x000e
+
+#define CRTC_VLINE_CRNT_VLINE   0x0010  /* Dword offset 04 */
+#define CRTC_OFF_PITCH          0x0014  /* Dword offset 05 */
+#define CRTC_OFFSET             0x0014
+#define CRTC_PITCH              0x0016
+
+#define CRTC_INT_CNTL           0x0018  /* Dword offset 06 */
+#define CRTC_GEN_CNTL           0x001C  /* Dword offset 07 */
+#define CRTC_PIX_WIDTH          0x001d
+#define CRTC_FIFO               0x001e
+#define CRTC_EXT_DISP           0x001f
+
+#define OVR_CLR                 0x0040  /* Dword offset 10 */
+#define OVR_WID_LEFT_RIGHT      0x0044  /* Dword offset 11 */
+#define OVR_WID_TOP_BOTTOM      0x0048  /* Dword offset 12 */
+
+#define CUR_CLR0                0x0060  /* Dword offset 18 */
+#define CUR_CLR1                0x0064  /* Dword offset 19 */
+#define CUR_OFFSET              0x0068  /* Dword offset 1A */
+#define CUR_HORZ_VERT_POSN      0x006C  /* Dword offset 1B */
+#define CUR_HORZ_VERT_OFF       0x0070  /* Dword offset 1C */
+
+#define SCRATCH_REG0            0x0080  /* Dword offset 20 */
+#define SCRATCH_REG1            0x0084  /* Dword offset 21 */
+
+#define CLOCK_CNTL              0x0090  /* Dword offset 24 */
+#define CLOCK_SEL_CNTL          0x0090  // Dword offset 24
+
+#define BUS_CNTL                0x00A0  /* Dword offset 28 */
+
+#define MEM_CNTL                0x00B0  /* Dword offset 2C */
+
+#define MEM_VGA_WP_SEL          0x00B4  /* Dword offset 2D */
+#define MEM_VGA_RP_SEL          0x00B8  /* Dword offset 2E */
+
+#define DAC_REGS                0x00C0  /* Dword offset 30 */
+#define DAC_W_INDEX             0x00C0  /* Dword offset 30 */
+#define DAC_DATA                0x00C1  /* Dword offset 30 */
+#define DAC_MASK                0x00C2  /* Dword offset 30 */
+#define DAC_R_INDEX             0x00C3  /* Dword offset 30 */
+#define DAC_CNTL                0x00C4  /* Dword offset 31 */
+
+#define GEN_TEST_CNTL           0x00D0  /* Dword offset 34 */
+
+#define CONFIG_CNTL		0x00DC	/* Dword offset 37 (CT, ET, VT) */
+#define CONFIG_CHIP_ID          0x00E0  /* Dword offset 38 */
+#define CONFIG_STAT0            0x00E4  /* Dword offset 39 */
+#define CONFIG_STAT1            0x00E8  /* Dword offset 3A */
+
+
+/* GUI MEMORY MAPPED Registers */
+
+#define DST_OFF_PITCH           0x0100  /* Dword offset 40 */
+#define DST_X                   0x0104  /* Dword offset 41 */
+#define DST_Y                   0x0108  /* Dword offset 42 */
+#define DST_Y_X                 0x010C  /* Dword offset 43 */
+#define DST_WIDTH               0x0110  /* Dword offset 44 */
+#define DST_HEIGHT              0x0114  /* Dword offset 45 */
+#define DST_HEIGHT_WIDTH        0x0118  /* Dword offset 46 */
+#define DST_X_WIDTH             0x011C  /* Dword offset 47 */
+#define DST_BRES_LNTH           0x0120  /* Dword offset 48 */
+#define DST_BRES_ERR            0x0124  /* Dword offset 49 */
+#define DST_BRES_INC            0x0128  /* Dword offset 4A */
+#define DST_BRES_DEC            0x012C  /* Dword offset 4B */
+#define DST_CNTL                0x0130  /* Dword offset 4C */
+
+#define SRC_OFF_PITCH           0x0180  /* Dword offset 60 */
+#define SRC_X                   0x0184  /* Dword offset 61 */
+#define SRC_Y                   0x0188  /* Dword offset 62 */
+#define SRC_Y_X                 0x018C  /* Dword offset 63 */
+#define SRC_WIDTH1              0x0190  /* Dword offset 64 */
+#define SRC_HEIGHT1             0x0194  /* Dword offset 65 */
+#define SRC_HEIGHT1_WIDTH1      0x0198  /* Dword offset 66 */
+#define SRC_X_START             0x019C  /* Dword offset 67 */
+#define SRC_Y_START             0x01A0  /* Dword offset 68 */
+#define SRC_Y_X_START           0x01A4  /* Dword offset 69 */
+#define SRC_WIDTH2              0x01A8  /* Dword offset 6A */
+#define SRC_HEIGHT2             0x01AC  /* Dword offset 6B */
+#define SRC_HEIGHT2_WIDTH2      0x01B0  /* Dword offset 6C */
+#define SRC_CNTL                0x01B4  /* Dword offset 6D */
+
+#define HOST_DATA0              0x0200  /* Dword offset 80 */
+#define HOST_DATA1              0x0204  /* Dword offset 81 */
+#define HOST_DATA2              0x0208  /* Dword offset 82 */
+#define HOST_DATA3              0x020C  /* Dword offset 83 */
+#define HOST_DATA4              0x0210  /* Dword offset 84 */
+#define HOST_DATA5              0x0214  /* Dword offset 85 */
+#define HOST_DATA6              0x0218  /* Dword offset 86 */
+#define HOST_DATA7              0x021C  /* Dword offset 87 */
+#define HOST_DATA8              0x0220  /* Dword offset 88 */
+#define HOST_DATA9              0x0224  /* Dword offset 89 */
+#define HOST_DATAA              0x0228  /* Dword offset 8A */
+#define HOST_DATAB              0x022C  /* Dword offset 8B */
+#define HOST_DATAC              0x0230  /* Dword offset 8C */
+#define HOST_DATAD              0x0234  /* Dword offset 8D */
+#define HOST_DATAE              0x0238  /* Dword offset 8E */
+#define HOST_DATAF              0x023C  /* Dword offset 8F */
+#define HOST_CNTL               0x0240  /* Dword offset 90 */
+
+#define PAT_REG0                0x0280  /* Dword offset A0 */
+#define PAT_REG1                0x0284  /* Dword offset A1 */
+#define PAT_CNTL                0x0288  /* Dword offset A2 */
+
+#define SC_LEFT                 0x02A0  /* Dword offset A8 */
+#define SC_RIGHT                0x02A4  /* Dword offset A9 */
+#define SC_LEFT_RIGHT           0x02A8  /* Dword offset AA */
+#define SC_TOP                  0x02AC  /* Dword offset AB */
+#define SC_BOTTOM               0x02B0  /* Dword offset AC */
+#define SC_TOP_BOTTOM           0x02B4  /* Dword offset AD */
+
+#define DP_BKGD_CLR             0x02C0  /* Dword offset B0 */
+#define DP_FRGD_CLR             0x02C4  /* Dword offset B1 */
+#define DP_WRITE_MASK           0x02C8  /* Dword offset B2 */
+#define DP_CHAIN_MASK           0x02CC  /* Dword offset B3 */
+#define DP_PIX_WIDTH            0x02D0  /* Dword offset B4 */
+#define DP_MIX                  0x02D4  /* Dword offset B5 */
+#define DP_SRC                  0x02D8  /* Dword offset B6 */
+
+#define CLR_CMP_CLR             0x0300  /* Dword offset C0 */
+#define CLR_CMP_MASK            0x0304  /* Dword offset C1 */
+#define CLR_CMP_CNTL            0x0308  /* Dword offset C2 */
+
+#define FIFO_STAT               0x0310  /* Dword offset C4 */
+
+#define CONTEXT_MASK            0x0320  /* Dword offset C8 */
+#define CONTEXT_LOAD_CNTL       0x032C  /* Dword offset CB */
+
+#define GUI_TRAJ_CNTL           0x0330  /* Dword offset CC */
+#define GUI_STAT                0x0338  /* Dword offset CE */
+
+
+/* CRTC control values (mostly CRTC_GEN_CNTL) */
+
+#define CRTC_H_SYNC_NEG		0x00200000
+#define CRTC_V_SYNC_NEG		0x00200000
+
+#define CRTC_DBL_SCAN_EN	0x00000001
+#define CRTC_INTERLACE_EN	0x00000002
+#define CRTC_HSYNC_DIS		0x00000004
+#define CRTC_VSYNC_DIS		0x00000008
+#define CRTC_CSYNC_EN		0x00000010
+#define CRTC_PIX_BY_2_EN	0x00000020
+#define CRTC_BLANK		0x00000040
+
+#define CRTC_PIX_WIDTH_MASK		0x00000700
+#define CRTC_PIX_WIDTH_4BPP		0x00000100
+#define CRTC_PIX_WIDTH_8BPP		0x00000200
+#define CRTC_PIX_WIDTH_15BPP	0x00000300
+#define CRTC_PIX_WIDTH_16BPP	0x00000400
+#define CRTC_PIX_WIDTH_24BPP	0x00000500
+#define CRTC_PIX_WIDTH_32BPP	0x00000600
+
+#define CRTC_BYTE_PIX_ORDER	0x00000800
+#define CRTC_PIX_ORDER_MSN_LSN	0x00000000
+#define CRTC_PIX_ORDER_LSN_MSN	0x00000800
+
+#define CRTC_FIFO_LWM		0x000f0000
+#define CRTC_EXT_DISP_EN	0x01000000
+#define CRTC_EXT_EN		0x02000000
+
+#define CRTC_CRNT_VLINE		0x07f00000
+#define CRTC_VBLANK		0x00000001
+
+/* DAC control values */
+
+#define DAC_EXT_SEL_RS2		0x01
+#define DAC_EXT_SEL_RS3		0x02
+#define DAC_8BIT_EN		0x00000100
+#define DAC_PIX_DLY_MASK	0x00000600
+#define DAC_PIX_DLY_0NS		0x00000000
+#define DAC_PIX_DLY_2NS		0x00000200
+#define DAC_PIX_DLY_4NS		0x00000400
+#define DAC_BLANK_ADJ_MASK	0x00001800
+#define DAC_BLANK_ADJ_0		0x00000000
+#define DAC_BLANK_ADJ_1		0x00000800
+#define DAC_BLANK_ADJ_2		0x00001000
+
+
+/* Mix control values */
+
+#define MIX_NOT_DST                     0x0000
+#define MIX_0                           0x0001
+#define MIX_1                           0x0002
+#define MIX_DST                         0x0003
+#define MIX_NOT_SRC                     0x0004
+#define MIX_XOR                         0x0005
+#define MIX_XNOR                        0x0006
+#define MIX_SRC                         0x0007
+#define MIX_NAND                        0x0008
+#define MIX_NOT_SRC_OR_DST              0x0009
+#define MIX_SRC_OR_NOT_DST              0x000a
+#define MIX_OR                          0x000b
+#define MIX_AND                         0x000c
+#define MIX_SRC_AND_NOT_DST             0x000d
+#define MIX_NOT_SRC_AND_DST             0x000e
+#define MIX_NOR                         0x000f
+
+/* Maximum engine dimensions */
+#define ENGINE_MIN_X        0
+#define ENGINE_MIN_Y        0
+#define ENGINE_MAX_X        4095
+#define ENGINE_MAX_Y        16383
+
+/* Mach64 engine bit constants - these are typically ORed together */
+
+/* BUS_CNTL register constants */
+#define BUS_FIFO_ERR_ACK        0x00200000
+#define BUS_HOST_ERR_ACK        0x00800000
+
+/* GEN_TEST_CNTL register constants */
+#define GEN_OVR_OUTPUT_EN       0x20
+#define HWCURSOR_ENABLE         0x80
+#define GUI_ENGINE_ENABLE       0x100
+#define BLOCK_WRITE_ENABLE      0x200
+
+/* CLOCK_CNTL register constants */
+#define CLOCK_SEL		0x0f
+#define CLOCK_DIV		0x30
+#define CLOCK_DIV1		0x00
+#define CLOCK_DIV2		0x10
+#define CLOCK_DIV4		0x20
+#define CLOCK_STROBE	0x40
+#define PLL_WR_EN		0x02
+
+/* PLL registers */
+#define PLL_MACRO_CNTL		0x01
+#define PLL_REF_DIV		0x02
+#define PLL_GEN_CNTL		0x03
+#define MCLK_FB_DIV		0x04
+#define PLL_VCLK_CNTL		0x05
+#define VCLK_POST_DIV		0x06
+#define VCLK0_FB_DIV		0x07
+#define VCLK1_FB_DIV		0x08
+#define VCLK2_FB_DIV		0x09
+#define VCLK3_FB_DIV		0x0A
+#define PLL_XCLK_CNTL		0x0B
+#define PLL_TEST_CTRL		0x0E
+#define PLL_TEST_COUNT		0x0F
+
+/* Fields in PLL registers */
+#define PLL_PC_GAIN		0x07
+#define PLL_VC_GAIN		0x18
+#define PLL_DUTY_CYC	0xE0
+#define PLL_OVERRIDE	0x01
+#define PLL_MCLK_RST	0x02
+#define OSC_EN			0x04
+#define EXT_CLK_EN		0x08
+#define MCLK_SRC_SEL	0x70
+#define EXT_CLK_CNTL	0x80
+#define VCLK_SRC_SEL	0x03
+#define PLL_VCLK_RST	0x04
+#define VCLK_INVERT		0x08
+#define VCLK0_POST		0x03
+#define VCLK1_POST		0x0C
+#define VCLK2_POST		0x30
+#define VCLK3_POST		0xC0
+
+/* CONFIG_CNTL register constants */
+#define APERTURE_4M_ENABLE      1
+#define APERTURE_8M_ENABLE      2
+#define VGA_APERTURE_ENABLE     4
+
+/* CONFIG_STAT0 register constants (GX, CX) */
+#define CFG_BUS_TYPE		0x00000007
+#define CFG_MEM_TYPE		0x00000038
+#define CFG_INIT_DAC_TYPE	0x00000e00
+
+/* CONFIG_STAT0 register constants (CT, ET, VT) */
+#define CFG_MEM_TYPE_xT		0x00000007
+
+#define ISA			0
+#define EISA		1
+#define LOCAL_BUS	6
+#define PCI			7
+
+/* Memory types for GX, CX */
+#define DRAMx4			0
+#define VRAMx16			1
+#define VRAMx16ssr		2
+#define DRAMx16			3
+#define GraphicsDRAMx16		4
+#define EnhancedVRAMx16		5
+#define EnhancedVRAMx16ssr	6
+
+/* Memory types for CT, ET, VT, GT */
+#define DRAM			0
+#define EDO_DRAM		1
+#define PSEUDO_EDO		2
+#define SDRAM			3
+
+#define DAC_INTERNAL		0x00
+#define DAC_IBMRGB514		0x01
+#define DAC_ATI68875		0x02
+#define DAC_TVP3026_A		0x72
+#define DAC_BT476			0x03
+#define DAC_BT481			0x04
+#define DAC_ATT20C491		0x14
+#define DAC_SC15026			0x24
+#define DAC_MU9C1880		0x34
+#define DAC_IMSG174			0x44
+#define DAC_ATI68860_B		0x05
+#define DAC_ATI68860_C		0x15
+#define DAC_TVP3026_B		0x75
+#define DAC_STG1700			0x06
+#define DAC_ATT498			0x16
+#define DAC_STG1702			0x07
+#define DAC_SC15021			0x17
+#define DAC_ATT21C498		0x27
+#define DAC_STG1703			0x37
+#define DAC_CH8398			0x47
+#define DAC_ATT20C408		0x57
+
+#define CLK_ATI18818_0		0
+#define CLK_ATI18818_1		1
+#define CLK_STG1703			2
+#define CLK_CH8398			3
+#define CLK_INTERNAL		4
+#define CLK_ATT20C408		5
+#define CLK_IBMRGB514		6
+
+/* MEM_CNTL register constants */
+#define MEM_SIZE_ALIAS		0x00000007
+#define MEM_SIZE_512K		0x00000000
+#define MEM_SIZE_1M		0x00000001
+#define MEM_SIZE_2M		0x00000002
+#define MEM_SIZE_4M		0x00000003
+#define MEM_SIZE_6M		0x00000004
+#define MEM_SIZE_8M		0x00000005
+#define MEM_SIZE_ALIAS_GTB	0x0000000F
+#define MEM_SIZE_2M_GTB		0x00000003
+#define MEM_SIZE_4M_GTB		0x00000007
+#define MEM_SIZE_6M_GTB		0x00000009
+#define MEM_SIZE_8M_GTB		0x0000000B
+#define MEM_BNDRY               0x00030000
+#define MEM_BNDRY_0K            0x00000000
+#define MEM_BNDRY_256K          0x00010000
+#define MEM_BNDRY_512K          0x00020000
+#define MEM_BNDRY_1M            0x00030000
+#define MEM_BNDRY_EN            0x00040000
+
+/* ATI PCI constants */
+#define PCI_ATI_VENDOR_ID	0x1002
+#define PCI_MACH64_GX		0x4758
+#define PCI_MACH64_CX		0x4358
+#define PCI_MACH64_CT		0x4354
+#define PCI_MACH64_ET		0x4554
+#define PCI_MACH64_VT		0x5654
+#define PCI_MACH64_GT		0x4754
+
+/* CONFIG_CHIP_ID register constants */
+#define CFG_CHIP_TYPE		0x0000FFFF
+#define CFG_CHIP_CLASS		0x00FF0000
+#define CFG_CHIP_REV		0xFF000000
+#define CFG_CHIP_VERSION	0x07000000
+#define CFG_CHIP_FOUNDRY	0x38000000
+#define CFG_CHIP_REVISION	0xC0000000
+
+/* Chip IDs read from CONFIG_CHIP_ID */
+#define MACH64_GX_ID		0xD7
+#define MACH64_CX_ID		0x57
+#define MACH64_CT_ID		0x4354
+#define MACH64_ET_ID		0x4554
+#define MACH64_VT_ID		0x5654
+#define MACH64_GT_ID		0x4754
+
+/* Mach64 chip types */
+#define MACH64_UNKNOWN		0
+#define MACH64_GX		1
+#define MACH64_CX		2
+#define MACH64_CT		3
+#define MACH64_ET		4
+#define MACH64_VT		5
+#define MACH64_GT		6
+
+/* DST_CNTL register constants */
+#define DST_X_RIGHT_TO_LEFT     0
+#define DST_X_LEFT_TO_RIGHT     1
+#define DST_Y_BOTTOM_TO_TOP     0
+#define DST_Y_TOP_TO_BOTTOM     2
+#define DST_X_MAJOR             0
+#define DST_Y_MAJOR             4
+#define DST_X_TILE              8
+#define DST_Y_TILE              0x10
+#define DST_LAST_PEL            0x20
+#define DST_POLYGON_ENABLE      0x40
+#define DST_24_ROTATION_ENABLE  0x80
+
+/* SRC_CNTL register constants */
+#define SRC_PATTERN_ENABLE      1
+#define SRC_ROTATION_ENABLE     2
+#define SRC_LINEAR_ENABLE       4
+#define SRC_BYTE_ALIGN          8
+#define SRC_LINE_X_RIGHT_TO_LEFT 0
+#define SRC_LINE_X_LEFT_TO_RIGHT 0x10
+
+/* HOST_CNTL register constants */
+#define HOST_BYTE_ALIGN         1
+
+/* GUI_TRAJ_CNTL register constants */
+#define PAT_MONO_8x8_ENABLE     0x01000000
+#define PAT_CLR_4x2_ENABLE      0x02000000
+#define PAT_CLR_8x1_ENABLE      0x04000000
+
+/* DP_CHAIN_MASK register constants */
+#define DP_CHAIN_4BPP		0x8888
+#define DP_CHAIN_7BPP		0xD2D2
+#define DP_CHAIN_8BPP		0x8080
+#define DP_CHAIN_8BPP_RGB	0x9292
+#define DP_CHAIN_15BPP		0x4210
+#define DP_CHAIN_16BPP		0x8410
+#define DP_CHAIN_24BPP		0x8080
+#define DP_CHAIN_32BPP		0x8080
+
+/* DP_PIX_WIDTH register constants */
+#define DST_1BPP                0
+#define DST_4BPP                1
+#define DST_8BPP                2
+#define DST_15BPP               3
+#define DST_16BPP               4
+#define DST_32BPP               6
+#define SRC_1BPP                0
+#define SRC_4BPP                0x100
+#define SRC_8BPP                0x200
+#define SRC_15BPP               0x300
+#define SRC_16BPP               0x400
+#define SRC_32BPP               0x600
+#define HOST_1BPP               0
+#define HOST_4BPP               0x10000
+#define HOST_8BPP               0x20000
+#define HOST_15BPP              0x30000
+#define HOST_16BPP              0x40000
+#define HOST_32BPP              0x60000
+#define BYTE_ORDER_MSB_TO_LSB   0
+#define BYTE_ORDER_LSB_TO_MSB   0x1000000
+
+/* DP_MIX register constants */
+#define BKGD_MIX_NOT_D              0
+#define BKGD_MIX_ZERO               1
+#define BKGD_MIX_ONE                2
+#define BKGD_MIX_D                  3
+#define BKGD_MIX_NOT_S              4
+#define BKGD_MIX_D_XOR_S            5
+#define BKGD_MIX_NOT_D_XOR_S        6
+#define BKGD_MIX_S                  7
+#define BKGD_MIX_NOT_D_OR_NOT_S     8
+#define BKGD_MIX_D_OR_NOT_S         9
+#define BKGD_MIX_NOT_D_OR_S         10
+#define BKGD_MIX_D_OR_S             11
+#define BKGD_MIX_D_AND_S            12
+#define BKGD_MIX_NOT_D_AND_S        13
+#define BKGD_MIX_D_AND_NOT_S        14
+#define BKGD_MIX_NOT_D_AND_NOT_S    15
+#define BKGD_MIX_D_PLUS_S_DIV2      0x17
+#define FRGD_MIX_NOT_D              0
+#define FRGD_MIX_ZERO               0x10000
+#define FRGD_MIX_ONE                0x20000
+#define FRGD_MIX_D                  0x30000
+#define FRGD_MIX_NOT_S              0x40000
+#define FRGD_MIX_D_XOR_S            0x50000
+#define FRGD_MIX_NOT_D_XOR_S        0x60000
+#define FRGD_MIX_S                  0x70000
+#define FRGD_MIX_NOT_D_OR_NOT_S     0x80000
+#define FRGD_MIX_D_OR_NOT_S         0x90000
+#define FRGD_MIX_NOT_D_OR_S         0xa0000
+#define FRGD_MIX_D_OR_S             0xb0000
+#define FRGD_MIX_D_AND_S            0xc0000
+#define FRGD_MIX_NOT_D_AND_S        0xd0000
+#define FRGD_MIX_D_AND_NOT_S        0xe0000
+#define FRGD_MIX_NOT_D_AND_NOT_S    0xf0000
+#define FRGD_MIX_D_PLUS_S_DIV2      0x170000
+
+/* DP_SRC register constants */
+#define BKGD_SRC_BKGD_CLR           0
+#define BKGD_SRC_FRGD_CLR           1
+#define BKGD_SRC_HOST               2
+#define BKGD_SRC_BLIT               3
+#define BKGD_SRC_PATTERN            4
+#define FRGD_SRC_BKGD_CLR           0
+#define FRGD_SRC_FRGD_CLR           0x100
+#define FRGD_SRC_HOST               0x200
+#define FRGD_SRC_BLIT               0x300
+#define FRGD_SRC_PATTERN            0x400
+#define MONO_SRC_ONE                0
+#define MONO_SRC_PATTERN            0x10000
+#define MONO_SRC_HOST               0x20000
+#define MONO_SRC_BLIT               0x30000
+
+/* CLR_CMP_CNTL register constants */
+#define COMPARE_FALSE               0
+#define COMPARE_TRUE                1
+#define COMPARE_NOT_EQUAL           4
+#define COMPARE_EQUAL               5
+#define COMPARE_DESTINATION         0
+#define COMPARE_SOURCE              0x1000000
+
+/* FIFO_STAT register constants */
+#define FIFO_ERR                    0x80000000
+
+/* CONTEXT_LOAD_CNTL constants */
+#define CONTEXT_NO_LOAD             0
+#define CONTEXT_LOAD                0x10000
+#define CONTEXT_LOAD_AND_DO_FILL    0x20000
+#define CONTEXT_LOAD_AND_DO_LINE    0x30000
+#define CONTEXT_EXECUTE             0
+#define CONTEXT_CMD_DISABLE         0x80000000
+
+/* GUI_STAT register constants */
+#define ENGINE_IDLE                 0
+#define ENGINE_BUSY                 1
+#define SCISSOR_LEFT_FLAG           0x10
+#define SCISSOR_RIGHT_FLAG          0x20
+#define SCISSOR_TOP_FLAG            0x40
+#define SCISSOR_BOTTOM_FLAG         0x80
+
+/* ATI VGA Extended Regsiters */
+#define sioATIEXT	0x1ce
+#define bioATIEXT	0x3ce
+
+#define ATI2E		0xae
+#define ATI32		0xb2
+#define ATI36		0xb6
+
+/* VGA Graphics Controller Registers */
+#define VGAGRA		0x3ce
+#define GRA06		0x06
+
+/* VGA Seququencer Registers */
+#define VGASEQ		0x3c4
+#define SEQ02		0x02
+#define SEQ04		0x04
+
+#define MACH64_MAX_X	ENGINE_MAX_X
+#define MACH64_MAX_Y	ENGINE_MAX_Y
+
+#define INC_X           0x0020
+#define INC_Y           0x0080
+
+#define RGB16_555               0x0000
+#define RGB16_565               0x0040
+#define RGB16_655               0x0080
+#define RGB16_664               0x00c0
+
+#define POLY_TEXT_TYPE          0x0001
+#define IMAGE_TEXT_TYPE         0x0002
+#define TEXT_TYPE_8_BIT         0x0004
+#define TEXT_TYPE_16_BIT        0x0008
+#define POLY_TEXT_TYPE_8        (POLY_TEXT_TYPE | TEXT_TYPE_8_BIT)
+#define IMAGE_TEXT_TYPE_8       (IMAGE_TEXT_TYPE | TEXT_TYPE_8_BIT)
+#define POLY_TEXT_TYPE_16       (POLY_TEXT_TYPE | TEXT_TYPE_16_BIT)
+#define IMAGE_TEXT_TYPE_16      (IMAGE_TEXT_TYPE | TEXT_TYPE_16_BIT)
+
+#define MACH64_NUM_CLOCKS	16
+#define MACH64_NUM_FREQS	50
+
+/* Wait until "v" queue entries are free */
+#define aty_WaitQueue(v)    { while ((aty_ld_rev(FIFO_STAT) & 0xffff) > \
+			 ((unsigned short)(0x8000 >> (v)))); }
+
+/* Wait until GP is idle and queue is empty */
+#define aty_WaitIdleEmpty() { aty_WaitQueue(16); \
+			  while ((aty_ld_rev(GUI_STAT) & 1) != 0); }
+
+#define SKIP_2(_v) ((((_v)<<1)&0xfff8)|((_v)&0x3)|(((_v)&0x80)>>5))
+
+#define MACH64_BIT_BLT(_srcx, _srcy, _dstx, _dsty, _w, _h, _dir) \
+{ \
+    aty_WaitQueue(5); \
+    aty_st_rev(SRC_Y_X, (((_srcx) << 16) | ((_srcy) & 0x0000ffff))); \
+    aty_st_rev(SRC_WIDTH1, (_w)); \
+    aty_st_rev(DST_CNTL, (_dir)); \
+    aty_st_rev(DST_Y_X, (((_dstx) << 16) | ((_dsty) & 0x0000ffff))); \
+    aty_st_rev(DST_HEIGHT_WIDTH, (((_w) << 16) | ((_h) & 0x0000ffff))); \
+}
+#endif /* REGMACH64_H */
+
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/control.c linux/drivers/macintosh/control.c
--- v2.1.50/linux/drivers/macintosh/control.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/control.c	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,520 @@
+/*
+ * control.c: Console support for PowerMac "control" display adaptor.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *	
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/vc_ioctl.h>
+#include <linux/nvram.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/cuda.h>
+#include <linux/selection.h>
+#include "pmac-cons.h"
+#include "control.h"
+
+/*
+ * Structure of the registers for the RADACAL colormap device.
+ */
+struct cmap_regs {
+	unsigned char addr;
+	char pad1[15];
+	unsigned char d1;
+	char pad2[15];
+	unsigned char d2;
+	char pad3[15];
+	unsigned char lut;
+	char pad4[15];
+};
+
+/*
+ * Structure of the registers for the "control" display adaptor".
+ */
+#define PAD(x)	char x[12]
+
+struct preg {			/* padded register */
+	unsigned r;
+	char pad[12];
+};
+
+struct control_regs {
+	struct preg vcount;	/* vertical counter */
+	/* Vertical parameters are in units of 1/2 scan line */
+	struct preg vswin;	/* between vsblank and vssync */
+	struct preg vsblank;	/* vert start blank */
+	struct preg veblank;	/* vert end blank (display start) */
+	struct preg vewin;	/* between vesync and veblank */
+	struct preg vesync;	/* vert end sync */
+	struct preg vssync;	/* vert start sync */
+	struct preg vperiod;	/* vert period */
+	struct preg reg8;
+	/* Horizontal params are in units of 2 pixels */
+	struct preg hperiod;	/* horiz period - 2 */
+	struct preg hsblank;	/* horiz start blank */
+	struct preg heblank;	/* horiz end blank */
+	struct preg hesync;	/* horiz end sync */
+	struct preg hssync;	/* horiz start sync */
+	struct preg rege;
+	struct preg regf;
+	struct preg reg10;
+	struct preg reg11;
+	struct preg ctrl;	/* display control */
+	struct preg start_addr;	/* start address: 5 lsbs zero */
+	struct preg pitch;	/* addrs diff between scan lines */
+	struct preg mon_sense;	/* monitor sense bits */
+	struct preg flags;
+	struct preg mode;
+	struct preg reg18;
+	struct preg reg19;
+	struct preg res[6];
+};
+
+static void set_control_clock(unsigned char *params);
+static int read_control_sense(void);
+static int control_vram_reqd(int vmode, int cmode);
+
+static int total_vram;		/* total amount of video memory, bytes */
+static unsigned char *frame_buffer;
+static struct cmap_regs *cmap_regs;
+static struct control_regs *disp_regs;
+static int control_use_bank2;
+
+/*
+ * Register initialization tables for the control display.
+ *
+ * Dot clock rate is
+ * 3.9064MHz * 2**clock_params[2] * clock_params[1] / clock_params[0].
+ *
+ * The values for vertical frequency (V) in the comments below
+ * are the values measured using the modes under MacOS.
+ */
+struct control_regvals {
+	int	pitch[3];		/* bytes/line, indexed by color_mode */
+	int	offset[3];		/* first pixel address */
+	unsigned regs[16];		/* for vswin .. reg10 */
+	unsigned char mode[3];		/* indexed by color_mode */
+	unsigned char radacal_ctrl[3];
+	unsigned char clock_params[3];
+};
+
+/* Register values for 1280x1024, 75Hz mode (20) */
+static struct control_regvals control_reg_init_20 = {
+	{ 1280, 2560, 0 },
+	{ 0x10, 0x20, 0 },
+	{ 2129, 2128, 80, 42, 4, 2130, 2132, 88,
+	  420, 411, 91, 35, 421, 18, 211, 386, },
+	{ 1, 1, 1},
+	{ 0x50, 0x64, 0x64 },
+	{ 13, 56, 3 }	/* pixel clock = 134.61MHz for V=74.81Hz */
+};
+
+/* Register values for 1280x960, 75Hz mode (19) */
+static struct control_regvals control_reg_init_19 = {
+	{ 1280, 2560, 0 },
+	{ 0x10, 0x20, 0 },
+	{ 1997, 1996, 76, 40, 4, 1998, 2000, 86,
+	  418, 409, 89, 35, 419, 18, 210, 384, },
+	{ 1, 1, 1 },
+	{ 0x50, 0x64, 0x64 },
+	{ 31, 125, 3 }	/* pixel clock = 126.01MHz for V=75.01 Hz */
+};
+
+/* Register values for 1152x870, 75Hz mode (18) */
+static struct control_regvals control_reg_init_18 = {
+	{ 1152, 2304, 4608 },
+	{ 0x10, 0x28, 0x50 },
+	{ 1825, 1822, 82, 43, 4, 1828, 1830, 120,
+	  726, 705, 129, 63, 727, 32, 364, 664 },
+	{ 2, 1, 1 },
+	{ 0x10, 0x14, 0x28 },
+	{ 19, 61, 3 }	/* pixel clock = 100.33MHz for V=75.31Hz */
+};
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct control_regvals control_reg_init_17 = {
+	{ 1024, 2048, 4096 },
+	{ 0x10, 0x28, 0x50 },
+	{ 1603, 1600, 64, 34, 4, 1606, 1608, 120,
+	  662, 641, 129, 47, 663, 24, 332, 616 },
+	{ 2, 1, 1 },
+	{ 0x10, 0x14, 0x28 },
+	{ 11, 28, 3 }	/* pixel clock = 79.55MHz for V=74.50Hz */
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct control_regvals control_reg_init_15 = {
+	{ 1024, 2048, 4096 },
+	{ 0x10, 0x28, 0x50 },
+	{ 1607, 1604, 68, 39, 10, 1610, 1612, 132,
+	  670, 653, 141, 67, 671, 34, 336, 604, },
+	{ 2, 1, 1 },
+	{ 0x10, 0x14, 0x28 },
+	{ 12, 30, 3 }	/* pixel clock = 78.12MHz for V=72.12Hz */
+};
+
+/* Register values for 1024x768, 60Hz mode (14) */
+static struct control_regvals control_reg_init_14 = {
+	{ 1024, 2048, 4096 },
+	{ 0x10, 0x28, 0x50 },
+	{ 1607, 1604, 68, 39, 10, 1610, 1612, 132,
+	  670, 653, 141, 67, 671, 34, 336, 604, },
+	{ 2, 1, 1 },
+	{ 0x10, 0x14, 0x28 },
+	{ 15, 31, 3 }	/* pixel clock = 64.58MHz for V=59.62Hz */
+};
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct control_regvals control_reg_init_13 = {
+	{ 832, 1664, 3328 },
+	{ 0x10, 0x28, 0x50 },
+	{ 1331, 1330, 82, 43, 4, 1332, 1334, 128,
+	  574, 553, 137, 31, 575, 16, 288, 544 },
+	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+	{ 23, 42, 3 }	/* pixel clock = 57.07MHz for V=74.27Hz */
+};
+
+/* Register values for 800x600, 75Hz mode (12) */
+static struct control_regvals control_reg_init_12 = {
+	{ 800, 1600, 3200 },
+	{ 0x10, 0x28, 0x50 },
+	{ 1247, 1246, 46, 25, 4, 1248, 1250, 104,
+	  526, 513, 113, 39, 527, 20, 264, 488, },
+	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+	{ 7, 11, 3 }	/* pixel clock = 49.11MHz for V=74.40Hz */
+};
+
+/* Register values for 800x600, 72Hz mode (11) */
+static struct control_regvals control_reg_init_11 = {
+	{ 800, 1600, 3200 },
+	{ 0x10, 0x28, 0x50 },
+	{ 1293, 1256, 56, 33, 10, 1330, 1332, 76,
+	  518, 485, 85, 59, 519, 30, 260, 460, },
+	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+	{ 17, 27, 3 }	/* pixel clock = 49.63MHz for V=71.66Hz */
+};
+
+/* Register values for 800x600, 60Hz mode (10) */
+static struct control_regvals control_reg_init_10 = {
+	{ 800, 1600, 3200 },
+	{ 0x10, 0x28, 0x50 },
+	{ 1293, 1256, 56, 33, 10, 1330, 1332, 76,
+	  518, 485, 85, 59, 519, 30, 260, 460, },
+	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+	{ 20, 53, 2 }	/* pixel clock = 41.41MHz for V=59.78Hz */
+};
+
+/* Register values for 640x870, 75Hz Full Page Display (7) */
+static struct control_regvals control_reg_init_7 = {
+        { 640, 1280, 2560 },
+	{ 0x10, 0x30, 0x68 },
+	{ 0x727, 0x724, 0x58, 0x2e, 0x4, 0x72a, 0x72c, 0x40,
+	  0x19e, 0x18c, 0x4c, 0x27, 0x19f, 0x14, 0xd0, 0x178 },
+	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+	{ 9, 33, 2 }	/* pixel clock = 57.29MHz for V=75.01Hz */
+};
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct control_regvals control_reg_init_6 = {
+	{ 640, 1280, 2560 },
+	{ 0, 8, 0x10 },
+	{ 1045, 1042, 82, 43, 4, 1048, 1050, 72,
+	  430, 393, 73, 31, 431, 16, 216, 400 },
+	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+	{ 14, 27, 2 }	/* pixel clock = 30.13MHz for V=66.43Hz */
+};
+
+/* Register values for 640x480, 60Hz mode (5) */
+static struct control_regvals control_reg_init_5 = {
+	{ 640, 1280, 2560 },
+	{ 0x10, 0x28, 0x50 },
+	{ 1037, 1026, 66, 34, 2, 1048, 1050, 56,
+	  398, 385, 65, 47, 399, 24, 200, 352, },
+	{ 2, 1, 0 }, { 0x10, 0x14, 0x18 },
+	{ 23, 37, 2 }	/* pixel clock = 25.14MHz for V=59.85Hz */
+};
+
+static struct control_regvals *control_reg_init[20] = {
+	NULL, NULL, NULL, NULL,
+	&control_reg_init_5,
+	&control_reg_init_6,
+	&control_reg_init_7,
+	NULL, NULL,
+	&control_reg_init_10,
+	&control_reg_init_11,
+	&control_reg_init_12,
+	&control_reg_init_13,
+	&control_reg_init_14,
+	&control_reg_init_15,
+	NULL,
+	&control_reg_init_17,
+	&control_reg_init_18,
+	&control_reg_init_19,
+	&control_reg_init_20
+};
+
+/*
+ * Get the monitor sense value.
+ * Note that this can be called before calibrate_delay,
+ * so we can't use udelay.
+ */
+static int
+read_control_sense()
+{
+	int sense;
+
+	out_le32(&disp_regs->mon_sense.r, 7);	/* drive all lines high */
+	__delay(200);
+	out_le32(&disp_regs->mon_sense.r, 077);	/* turn off drivers */
+	__delay(2000);
+	sense = (in_le32(&disp_regs->mon_sense.r) & 0x1c0) << 2;
+
+	/* drive each sense line low in turn and collect the other 2 */
+	out_le32(&disp_regs->mon_sense.r, 033);	/* drive A low */
+	__delay(2000);
+	sense |= (in_le32(&disp_regs->mon_sense.r) & 0xc0) >> 2;
+	out_le32(&disp_regs->mon_sense.r, 055);	/* drive B low */
+	__delay(2000);
+	sense |= ((in_le32(&disp_regs->mon_sense.r) & 0x100) >> 5)
+		| ((in_le32(&disp_regs->mon_sense.r) & 0x40) >> 4);
+	out_le32(&disp_regs->mon_sense.r, 066);	/* drive C low */
+	__delay(2000);
+	sense |= (in_le32(&disp_regs->mon_sense.r) & 0x180) >> 7;
+
+	out_le32(&disp_regs->mon_sense.r, 077);	/* turn off drivers */
+	return sense;
+}
+
+static inline int control_vram_reqd(int vmode, int cmode)
+{
+	return vmode_attrs[vmode-1].vres
+		* control_reg_init[vmode-1]->pitch[cmode];
+}
+
+void
+map_control_display(struct device_node *dp)
+{
+	int i, sense;
+	unsigned long addr, size;
+	int bank1, bank2;
+
+	if (dp->next != 0)
+		printk("Warning: only using first control display device\n");
+	if (dp->n_addrs != 2)
+		panic("expecting 2 addresses for control (got %d)", dp->n_addrs);
+
+#if 0
+	printk("pmac_display_init: node = %p, addrs =", dp->node);
+	for (i = 0; i < dp->n_addrs; ++i)
+		printk(" %x(%x)", dp->addrs[i].address, dp->addrs[i].size);
+	printk(", intrs =");
+	for (i = 0; i < dp->n_intrs; ++i)
+		printk(" %x", dp->intrs[i]);
+	printk("\n");
+#endif
+
+	/* Map in frame buffer and registers */
+	for (i = 0; i < dp->n_addrs; ++i) {
+		addr = dp->addrs[i].address;
+		size = dp->addrs[i].size;
+		if (size >= 0x800000) {
+			/* use the big-endian aperture (??) */
+			addr += 0x800000;
+			/* map at most 8MB for the frame buffer */
+			frame_buffer = ioremap(addr, 0x800000);
+		} else {
+			disp_regs = ioremap(addr, size);
+		}
+	}
+	cmap_regs = ioremap(0xf301b000, 0x1000);	/* XXX not in prom? */
+
+	/* Work out which banks of VRAM we have installed. */
+	frame_buffer[0] = 0x5a;
+	frame_buffer[1] = 0xc7;
+	bank1 = frame_buffer[0] == 0x5a && frame_buffer[1] == 0xc7;
+	frame_buffer[0x600000] = 0xa5;
+	frame_buffer[0x600001] = 0x38;
+	bank2 = frame_buffer[0x600000] == 0xa5 && frame_buffer[0x600001] == 0x38;
+	total_vram = (bank1 + bank2) * 0x200000;
+	/* If we don't have bank 1 installed, we hope we have bank 2 :-) */
+	control_use_bank2 = !bank1;
+	if (control_use_bank2)
+		frame_buffer += 0x600000;
+
+	sense = read_control_sense();
+	if (video_mode == VMODE_NVRAM) {
+		video_mode = nvram_read_byte(NV_VMODE);
+		if (video_mode <= 0 || video_mode > VMODE_MAX
+		    || control_reg_init[video_mode-1] == 0)
+			video_mode = VMODE_CHOOSE;
+	}
+	if (video_mode == VMODE_CHOOSE)
+		video_mode = map_monitor_sense(sense);
+	if (control_reg_init[video_mode-1] == 0)
+		video_mode = VMODE_640_480_60;
+
+	/*
+	 * Reduce the pixel size if we don't have enough VRAM.
+	 */
+	if (color_mode == CMODE_NVRAM)
+		color_mode = nvram_read_byte(NV_CMODE);
+	if (color_mode < CMODE_8 || color_mode > CMODE_32)
+		color_mode = CMODE_8;
+	while (color_mode > CMODE_8
+	       && control_vram_reqd(video_mode, color_mode) > total_vram)
+		--color_mode;
+
+	printk("Monitor sense value = 0x%x, ", sense);
+}
+
+static void
+set_control_clock(unsigned char *params)
+{
+	struct cuda_request req;
+	int i;
+
+	for (i = 0; i < 3; ++i) {
+		cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+			     0x50, i + 1, params[i]);
+		while (!req.got_reply)
+			cuda_poll();
+	}
+}
+
+void
+control_init()
+{
+	struct preg *rp;
+	int i, yoff, hres;
+	int ctrl, flags;
+	unsigned *p;
+	struct control_regvals *init;
+
+	if (video_mode <= 0 || video_mode > VMODE_MAX
+	    || (init = control_reg_init[video_mode-1]) == 0)
+		panic("control: display mode %d not supported", video_mode);
+	n_scanlines = vmode_attrs[video_mode-1].vres;
+	hres = vmode_attrs[video_mode-1].hres;
+	pixel_size = 1 << color_mode;
+	line_pitch = init->pitch[color_mode];
+	row_pitch = line_pitch * 16;
+
+	if (control_vram_reqd(video_mode, color_mode) > 0x200000)
+		flags = 0x51;
+	else if (control_use_bank2)
+		flags = 0x39;
+	else
+		flags = 0x31;
+	if (video_mode >= VMODE_1280_960_75 && color_mode >= CMODE_16)
+		ctrl = 0x7f;
+	else
+		ctrl = 0x3b;
+
+	/* Initialize display timing registers */
+	out_le32(&disp_regs->ctrl.r, 0x43b);
+	set_control_clock(init->clock_params);
+	cmap_regs->addr = 0x20; cmap_regs->d2 = init->radacal_ctrl[color_mode];
+	cmap_regs->addr = 0x21; cmap_regs->d2 = control_use_bank2? 0: 1;
+	cmap_regs->addr = 0x10; cmap_regs->d2 = 0;
+	cmap_regs->addr = 0x11; cmap_regs->d2 = 0;
+	rp = &disp_regs->vswin;
+	for (i = 0; i < 16; ++i, ++rp)
+		out_le32(&rp->r, init->regs[i]);
+	out_le32(&disp_regs->pitch.r, line_pitch);
+	out_le32(&disp_regs->mode.r, init->mode[color_mode]);
+	out_le32(&disp_regs->flags.r, flags);
+	out_le32(&disp_regs->start_addr.r, 0);
+	out_le32(&disp_regs->reg18.r, 0x1e5);
+	out_le32(&disp_regs->reg19.r, 0);
+
+	pmac_init_palette();	/* Initialize colormap */
+
+	/* Turn on display */
+	out_le32(&disp_regs->ctrl.r, ctrl);
+
+	yoff = (n_scanlines % 16) / 2;
+	fb_start = frame_buffer + yoff * line_pitch + init->offset[color_mode];
+
+	/* Clear screen */
+	p = (unsigned *) (frame_buffer + init->offset[color_mode]);
+	for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
+		*p++ = 0;
+
+	display_info.height = n_scanlines;
+	display_info.width = hres;
+	display_info.depth = pixel_size * 8;
+	display_info.pitch = line_pitch;
+	display_info.mode = video_mode;
+	strncpy(display_info.name, "control", sizeof(display_info.name));
+	display_info.fb_address = (unsigned long) frame_buffer + init->offset[color_mode];
+	display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr;
+	display_info.cmap_data_address = (unsigned long) &cmap_regs->lut;
+	display_info.disp_reg_address = (unsigned long) &disp_regs;
+}
+
+int
+control_setmode(struct vc_mode *mode, int doit)
+{
+	int cmode;
+
+	if (mode->mode <= 0 || mode->mode > VMODE_MAX
+	    || control_reg_init[mode->mode-1] == 0)
+		return -EINVAL;
+	switch (mode->depth) {
+	case 24:
+	case 32:
+		cmode = CMODE_32;
+		break;
+	case 16:
+		cmode = CMODE_16;
+		break;
+	case 8:
+	case 0:		/* (default) */
+		cmode = CMODE_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (control_vram_reqd(mode->mode, cmode) > total_vram)
+		return -EINVAL;
+	if (doit) {
+		video_mode = mode->mode;
+		color_mode = cmode;
+		control_init();
+	}
+	return 0;
+}
+
+void
+control_set_palette(unsigned char red[], unsigned char green[],
+		    unsigned char blue[], int index, int ncolors)
+{
+	int i;
+
+	for (i = 0; i < ncolors; ++i) {
+		cmap_regs->addr = index + i;	eieio();
+		cmap_regs->lut = red[i];	eieio();
+		cmap_regs->lut = green[i];	eieio();
+		cmap_regs->lut = blue[i];	eieio();
+	}
+}
+
+void
+control_set_blanking(int blank_mode)
+{
+	int ctrl;
+
+	ctrl = ld_le32(&disp_regs->ctrl.r) | 0x33;
+	if (blank_mode & VESA_VSYNC_SUSPEND)
+		ctrl &= ~3;
+	if (blank_mode & VESA_HSYNC_SUSPEND)
+		ctrl &= ~0x30;
+	out_le32(&disp_regs->ctrl.r, ctrl);
+}
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/control.h linux/drivers/macintosh/control.h
--- v2.1.50/linux/drivers/macintosh/control.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/control.h	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,17 @@
+/*
+ * Exported procedures for the "control" display driver on PowerMacs.
+ *
+ * Copyright (C) 1997 Paul Mackerras.
+ *	
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+extern void map_control_display(struct device_node *);
+extern void control_init(void);
+extern int control_setmode(struct vc_mode *mode, int doit);
+extern void control_set_palette(unsigned char red[], unsigned char green[],
+				unsigned char blue[], int index, int ncolors);
+extern void control_set_blanking(int blank_mode);
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/imstt.c linux/drivers/macintosh/imstt.c
--- v2.1.50/linux/drivers/macintosh/imstt.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/imstt.c	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,506 @@
+/*
+ * imstt.c: Console support for PowerMac "imstt" display adaptor.
+ *
+ * Copyright (C) 1997 Sigurdur Asgeirsson
+ *	
+ * 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.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/vc_ioctl.h>
+#include <linux/pci.h>
+#include <linux/bios32.h>
+#include <linux/nvram.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <linux/selection.h>
+#include <linux/vt_kern.h>
+#include "pmac-cons.h"
+#include "imstt.h"
+
+enum
+{
+  S1SA		=  0, /* 0x00 */
+  S2SA		=  1, /* 0x04 */
+  SP		=  2, /* 0x08 */
+  DSA		=  3, /* 0x0C */
+  CNT		=  4, /* 0x10 */
+  DP_OCTRL	=  5, /* 0x14 */
+  BLTCTL	= 10, /* 0x28 */
+		
+  //	Scan Timing Generator Registers
+  HES		= 12, /* 0x30 */
+  HEB		= 13, /* 0x34 */
+  HSB		= 14, /* 0x38 */
+  HT		= 15, /* 0x3C */
+  VES		= 16, /* 0x40 */
+  VEB		= 17, /* 0x44 */
+  VSB		= 18, /* 0x48 */
+  VT		= 19, /* 0x4C */
+  HCIV		= 20, /* 0x50 */
+  VCIV		= 21, /* 0x54 */
+  TCDR		= 22, /* 0x58 */
+  VIL		= 23, /* 0x5C */
+  STGCTL	= 24, /* 0x60 */
+	
+  //	Screen Refresh Generator Registers
+  SSR		= 25, /* 0x64 */
+  HRIR		= 26, /* 0x68 */
+  SPR		= 27, /* 0x6C */
+  CMR		= 28, /* 0x70 */
+  SRGCTL	= 29, /* 0x74 */
+		
+  //	RAM Refresh Generator Registers
+  RRCIV		= 30, /* 0x78 */
+  RRSC		= 31, /* 0x7C */
+  RRCR		= 34, /* 0x88 */
+		
+  //	System Registers
+  GIOE		= 32, /* 0x80 */
+  GIO		= 33, /* 0x84 */
+  SCR		= 35, /* 0x8C */
+  SSTATUS	= 36, /* 0x90 */
+  PRC		= 37, /* 0x94 */
+
+#if 0	
+  //	PCI Registers
+  DVID		= 0x00000000L,
+  SC		= 0x00000004L,
+  CCR		= 0x00000008L,
+  OG		= 0x0000000CL,
+  BARM		= 0x00000010L,
+  BARER		= 0x00000030L,
+#endif
+};
+
+enum
+{
+ PADDRW		= 0x00,
+ PDATA		= 0x04,
+ PPMASK		= 0x08,
+ PADDRR		= 0x0C,
+ PIDXLO		= 0x10,	
+ PIDXHI		= 0x14,	
+ PIDXDATA	= 0x18,
+ PIDXCTL	= 0x1C,
+
+ PPIXREP	= 0x0A,
+ PM0		= 0x20,
+ PN0		= 0x21,
+ PP0		= 0x22,
+ PC0		= 0x23
+};
+
+struct initvalues
+{
+  unsigned char	addr, value;
+};
+
+static struct initvalues initregs[] = 
+{
+ { 0x02, 0x21 },	/* (0x01) Miscellaneous Clock Control */
+ { 0x03, 0x00 },	/* (0x00) Sync Control */
+ { 0x04, 0x00 },	/* (0x00) Horizontal Sync Position */
+ { 0x05, 0x00 },	/* (0x00) Power Management */
+ { 0x06, 0x0B },	/* (0x02) DAC Operation */
+ { 0x07, 0x00 },	/* (0x00) Palette Control */
+ { 0x08, 0x01 },	/* (0x01) System Clock Control */
+ { 0x0B, 0x00 },	/* (U) 8 BPP Control */
+ { 0x0C, 0xC4 },	/* (U) 16 BPP Control */
+ { 0x0D, 0x00 },	/* (U) 24 BPP Packed Control */
+ { 0x0E, 0x03 },	/* (U) 32 BPP Control */
+ { 0x10, 0x05 },	/* (0x00) Pixel PLL Control 1 */
+ { 0x11, 0x00 },	/* (0x00) Pixel PLL Control 2 */
+ { 0x15, 0x08 },	/* (0x08) SYSCLK N (System PLL Reference Divider) */
+ { 0x16, 0x57 },	/* (0x41) SYSCLK M (System PLL VCO Divider) */
+ { 0x17, 0x00 },	/* (U) SYSCLK P */
+ { 0x18, 0x00 },	/* (U) SYSCLK C */
+ { 0x30, 0x00 },	/* (0x00) Cursor Control */
+ { 0x60, 0xFF },	/* (U) Border Color Red */
+ { 0x61, 0xFF },	/* (U) Border Color Green */
+ { 0x62, 0xFF },	/* (U) Border Color Blue */
+ { 0x70, 0x01 },	/* (0x00) Miscellaneous Control 1 */
+ { 0x71, 0x45 },	/* (0x00) Miscellaneous Control 2 */
+ { 0x72, 0x00 },	/* (0x00) Miscellaneous Control 3 */
+ { 0x78, 0x00 },	/* (0x00) Key Control/DB Operation */
+};
+
+static void set_imstt_clock(unsigned char *params);
+static int read_imstt_sense(void);
+static int imstt_vram_reqd(int vmode, int cmode);
+
+static int total_vram = 2 * 1024 * 1024;		/* total amount of video memory, bytes */
+static unsigned char *frame_buffer;
+static unsigned char *cmap_regs;
+static unsigned *dc_regs;
+
+
+/*
+ * Register initialization tables for the imstt display.
+ *
+ * Dot clock rate is 20MHz * (m + 1) / ((n + 1) * (p ? 2 * p : 1)
+ * where m = clk[0], n = clk[1], p = clk[2]
+ * clk[3] is c, charge pump bias which depends on the VCO frequency  
+ */
+struct imstt_regvals {
+	unsigned short		cfg[8];
+	unsigned char		clk[4];
+	unsigned long		pitch[3];
+} imsttmode;
+
+/* Register values for 1024x768, 75Hz mode (17) */
+static struct imstt_regvals imstt_reg_init_17 = {
+  { 0x0A, 0x1C, 0x9C, 0xA6, 0x0003, 0x0020, 0x0320, 0x0323 }, 
+  { 0x07, 0x00, 0x01, 0x02 },
+  { 0x0400, 0x0800, 0x1000 }
+};
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct imstt_regvals imstt_reg_init_13 = {
+  { 0x05, 0x20, 0x88, 0x90, 0x0003, 0x0028, 0x0298, 0x029B },
+  { 0x3E, 0x0A, 0x01, 0x02 },
+  { 832, 832 * 2, 832 * 4 }
+};
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct imstt_regvals imstt_reg_init_6 = {
+  { 0x08, 0x12, 0x62, 0x6C, 0x0003, 0x002A, 0x020A, 0x020C },
+  { 0x78, 0x13, 0x02, 0x02 },
+  { 640, 640 * 2, 640 * 4 }
+};
+
+static struct imstt_regvals *imstt_reg_init[20] = {
+	NULL, NULL, NULL, NULL,
+	&imstt_reg_init_6, // fake'm out
+	&imstt_reg_init_6,
+	NULL, NULL, NULL,
+	NULL, NULL, NULL,
+	&imstt_reg_init_13,
+	NULL, NULL, NULL,
+	&imstt_reg_init_17,
+	NULL, NULL, NULL
+};
+
+/*
+ * Get the monitor sense value.
+ * Note that this can be called before calibrate_delay,
+ * so we can't use udelay.
+ */
+static int
+read_imstt_sense()
+{
+#if 0
+	int sense;
+	unsigned gio, gioe;
+
+	gio = ld_le32(dc_regs + GIO) & ~0x0038;
+	gioe = ld_le32(dc_
+	
+	out_le32(dc_regs + GIOE, reg);	/* drive all lines high */
+	__delay(200);
+	out_le32(dc_regs + GIOE, 077);	/* turn off drivers */
+	__delay(2000);
+	sense = (in_le32(dc_regs + GIOE) & 0x1c0) << 2;
+
+	/* drive each sense line low in turn and collect the other 2 */
+	out_le32(dc_regs + GIOE, 033);	/* drive A low */
+	__delay(2000);
+	sense |= (in_le32(dc_regs + GIOE) & 0xc0) >> 2;
+	out_le32(dc_regs + GIOE, 055);	/* drive B low */
+	__delay(2000);
+	sense |= ((in_le32(dc_regs + GIOE) & 0x100) >> 5)
+		| ((in_le32(dc_regs + GIOE) & 0x40) >> 4);
+	out_le32(dc_regs + GIOE, 066);	/* drive C low */
+	__delay(2000);
+	sense |= (in_le32(dc_regs + GIOE) & 0x180) >> 7;
+
+	out_le32(dc_regs + GIOE, 077);	/* turn off drivers */
+	return sense;
+#else
+	return 0;
+#endif
+}
+
+static inline int imstt_vram_reqd(int vmode, int cmode)
+{
+	return vmode_attrs[vmode-1].vres
+		* imstt_reg_init[vmode-1]->pitch[cmode];
+}
+
+void
+map_imstt_display(struct device_node *dp)
+{
+	int i, sense;
+	unsigned long addr, size, tmp;
+	unsigned char bus, devfn;
+	unsigned short cmd;
+
+	if (dp->next != 0)
+		printk("Warning: only using first imstt display device\n");
+
+#if 1
+	printk("pmac_display_init: node = %p, addrs =", dp->node);
+	for (i = 0; i < dp->n_addrs; ++i)
+		printk(" %x(%x)", dp->addrs[i].address, dp->addrs[i].size);
+	printk(", intrs =");
+	for (i = 0; i < dp->n_intrs; ++i)
+		printk(" %x", dp->intrs[i]);
+	printk("\n");
+#endif
+
+	/* Map in frame buffer and registers */
+	for (i = 0; i < dp->n_addrs; ++i) {
+		addr = dp->addrs[i].address;
+		size = dp->addrs[i].size;
+		if (size >= 0x02000000) {
+			frame_buffer = ioremap(addr, size);
+			dc_regs = (unsigned*)(frame_buffer + 0x00800000);
+			cmap_regs = (unsigned char*)(frame_buffer + 0x00840000);
+
+			printk("mapped frame_buffer=%x(%x)", (unsigned)frame_buffer, (unsigned)size);
+			printk(" dc_regs=%x, cmap_regs=%x\n", (unsigned)dc_regs, (unsigned)cmap_regs);
+		}
+	}
+
+	/* enable memory-space accesses using config-space command register */
+	if (pci_device_loc(dp, &bus, &devfn) == 0) {
+	  pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
+	  
+	  printk("command word 0x%04X\n", cmd);
+	  
+	  if (cmd != 0xffff) {
+	    cmd |= PCI_COMMAND_MEMORY;
+	    pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
+	  }
+	}
+	else
+	  printk("unable to find pci device\n");
+
+	tmp = in_le32(dc_regs + SSTATUS);
+	printk("chip version %ld, ", (tmp & 0x0F00) >> 8);
+
+	tmp = in_le32(dc_regs + PRC);
+	total_vram = (tmp & 0x0004) ? 0x000400000L : 0x000200000L;
+	printk("VRAM size %ldM\n", total_vram / 0x000100000L);
+
+	sense = read_imstt_sense();
+	printk("Monitor sense value = 0x%x, ", sense);
+#if 0
+	if (video_mode == VMODE_NVRAM) {
+		video_mode = nvram_read_byte(NV_VMODE);
+		if (video_mode <= 0 || video_mode > VMODE_MAX
+		    || imstt_reg_init[video_mode-1] == 0)
+			video_mode = VMODE_CHOOSE;
+	}
+	if (video_mode == VMODE_CHOOSE)
+		video_mode = map_monitor_sense(sense);
+	if (imstt_reg_init[video_mode-1] == 0)
+		video_mode = VMODE_640_480_67;
+
+	/*
+	 * Reduce the pixel size if we don't have enough VRAM.
+	 */
+	if (color_mode == CMODE_NVRAM)
+		color_mode = nvram_read_byte(NV_CMODE);
+	if (color_mode < CMODE_8 || color_mode > CMODE_32)
+		color_mode = CMODE_8;
+	while (color_mode > CMODE_8
+	       && imstt_vram_reqd(video_mode, color_mode) > total_vram)
+		--color_mode;
+
+#endif
+
+	video_mode = VMODE_640_480_67;
+	color_mode = CMODE_8;
+}
+
+static void
+set_imstt_clock(unsigned char *params)
+{
+  cmap_regs[PIDXHI] = 0; eieio();
+  cmap_regs[PIDXLO] = PM0; eieio();
+  cmap_regs[PIDXDATA] = params[0]; eieio();
+
+  cmap_regs[PIDXLO] = PN0; eieio();
+  cmap_regs[PIDXDATA] = params[1]; eieio();
+
+  cmap_regs[PIDXLO] = PP0; eieio();
+  cmap_regs[PIDXDATA] = params[2]; eieio();
+	
+  cmap_regs[PIDXLO] = PC0; eieio();
+  cmap_regs[PIDXDATA] = params[3]; eieio();
+}
+
+void
+imstt_init()
+{
+  int	                 i, yoff, hres;
+  unsigned long	         ctl, pitch, tmp;
+  unsigned char	         pformat;
+  unsigned               *p;
+  struct imstt_regvals   *init;
+
+  if (video_mode <= 0 || video_mode > VMODE_MAX
+      || (init = imstt_reg_init[video_mode-1]) == 0)
+    panic("imstt: display mode %d not supported", video_mode);
+
+  n_scanlines = vmode_attrs[video_mode-1].vres;
+  hres = vmode_attrs[video_mode-1].hres;
+  pixel_size = 1 << color_mode;
+  line_pitch = init->pitch[color_mode];
+  row_pitch = line_pitch * 16;
+
+  /* initialize the card */
+  tmp = in_le32(dc_regs + STGCTL);
+  out_le32(dc_regs + STGCTL, tmp & ~0x1);
+#if 0
+  out_le32(dc_regs + SCR, 0);
+#endif
+
+  cmap_regs[PPMASK] = 0xFF;
+  /* set default values for DAC registers */ 
+  cmap_regs[PIDXHI] = 0; eieio();
+  for(i = 0; i < sizeof(initregs) / sizeof(*initregs); i++) {
+    cmap_regs[PIDXLO] = initregs[i].addr; eieio();
+    cmap_regs[PIDXDATA] = initregs[i].value; eieio();
+  }
+  set_imstt_clock(init->clk);
+
+  switch(color_mode) {
+  case CMODE_32:
+    ctl = 0x17b5;
+    pitch = init->pitch[2] / 4;
+    pformat = 0x06;
+    break;
+  case CMODE_16:
+    ctl = 0x17b3;
+    pitch = init->pitch[1] / 4;
+    pformat = 0x04;
+    break;
+  case CMODE_8:
+  default:
+    ctl = 0x17b1;
+    pitch = init->pitch[0] / 4;
+    pformat = 0x03;
+    break;
+  }
+
+  out_le32(&dc_regs[HES], init->cfg[0]);
+  out_le32(&dc_regs[HEB], init->cfg[1]);
+  out_le32(&dc_regs[HSB], init->cfg[2]);
+  out_le32(&dc_regs[HT], init->cfg[3]);
+  out_le32(&dc_regs[VES], init->cfg[4]);
+  out_le32(&dc_regs[VEB], init->cfg[5]);
+  out_le32(&dc_regs[VSB], init->cfg[6]);
+  out_le32(&dc_regs[VT], init->cfg[7]);
+  out_le32(&dc_regs[HCIV], 1);
+  out_le32(&dc_regs[VCIV], 1);
+  out_le32(&dc_regs[TCDR], 4);
+  out_le32(&dc_regs[VIL], 0);
+	
+  out_le32(&dc_regs[SSR], 0);
+  out_le32(&dc_regs[HRIR], 0x0200);
+  out_le32(&dc_regs[CMR], 0x01FF);
+  out_le32(&dc_regs[SRGCTL], 0x0003);
+  if(total_vram == 0x000200000)
+     out_le32(&dc_regs[SCR], 0x0059D);
+  else {
+    pitch /= 2;
+    out_le32(&dc_regs[SCR], 0x00D0DC);
+  }
+
+  out_le32(&dc_regs[SPR], pitch);
+
+  cmap_regs[PIDXLO] = PPIXREP; eieio();
+  cmap_regs[PIDXDATA] = pformat; eieio();
+
+
+  pmac_init_palette();	/* Initialize colormap */
+
+  out_le32(&dc_regs[STGCTL], ctl);
+
+  yoff = (n_scanlines % 16) / 2;
+  fb_start = frame_buffer + yoff * line_pitch;
+
+  /* Clear screen */
+  p = (unsigned *)frame_buffer;
+  for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
+    *p++ = 0;
+
+  display_info.height = n_scanlines;
+  display_info.width = hres;
+  display_info.depth = pixel_size * 8;
+  display_info.pitch = line_pitch;
+  display_info.mode = video_mode;
+  strncpy(display_info.name, "IMS,tt128mb", sizeof(display_info.name));
+  display_info.fb_address = (unsigned long) frame_buffer;
+  display_info.cmap_adr_address = (unsigned long) &cmap_regs[PADDRW];
+  display_info.cmap_data_address = (unsigned long) &cmap_regs[PDATA];
+  display_info.disp_reg_address = (unsigned long) NULL;
+}
+
+int
+imstt_setmode(struct vc_mode *mode, int doit)
+{
+	int cmode;
+
+	if (mode->mode <= 0 || mode->mode > VMODE_MAX
+	    || imstt_reg_init[mode->mode-1] == 0)
+		return -EINVAL;
+	switch (mode->depth) {
+	case 24:
+	case 32:
+		cmode = CMODE_32;
+		break;
+	case 16:
+		cmode = CMODE_16;
+		break;
+	case 8:
+	case 0:		/* (default) */
+		cmode = CMODE_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (imstt_vram_reqd(mode->mode, cmode) > total_vram)
+		return -EINVAL;
+	if (doit) {
+		video_mode = mode->mode;
+		color_mode = cmode;
+		imstt_init();
+	}
+	return 0;
+}
+
+void
+imstt_set_palette(unsigned char red[], unsigned char green[],
+		    unsigned char blue[], int index, int ncolors)
+{
+	int i;
+
+	for (i = 0; i < ncolors; ++i) {
+		cmap_regs[PADDRW] = index + i;	eieio();
+		cmap_regs[PDATA] = red[i];	eieio();
+		cmap_regs[PDATA] = green[i];	eieio();
+		cmap_regs[PDATA] = blue[i];	eieio();
+	}
+}
+
+void
+imstt_set_blanking(int blank_mode)
+{
+	long ctrl;
+
+	ctrl = ld_le32(dc_regs + STGCTL) | 0x0030;
+	if (blank_mode & VESA_VSYNC_SUSPEND)
+		ctrl &= ~0x0020;
+	if (blank_mode & VESA_HSYNC_SUSPEND)
+		ctrl &= ~0x0010;
+	out_le32(dc_regs + STGCTL, ctrl);
+}
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/imstt.h linux/drivers/macintosh/imstt.h
--- v2.1.50/linux/drivers/macintosh/imstt.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/imstt.h	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,18 @@
+/*
+ * Exported procedures for the "control" display driver on PowerMacs.
+ *
+ * Copyright (C) 1997 Paul Mackerras.
+ *	
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+extern void map_imstt_display(struct device_node *);
+extern void imstt_init(void);
+extern int imstt_setmode(struct vc_mode *mode, int doit);
+extern void imstt_set_palette(unsigned char red[], unsigned char green[],
+				unsigned char blue[], int index, int ncolors);
+extern void imstt_set_blanking(int blank_mode);
+
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c
--- v2.1.50/linux/drivers/macintosh/mac_keyb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/mac_keyb.c	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,343 @@
+/*
+ * drivers/char/mac_keyb.c
+ *
+ * Keyboard driver for Power Macintosh computers.
+ *
+ * Adapted from drivers/char/keyboard.c by Paul Mackerras
+ * (see that file for its authors and contributors).
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/ioport.h>
+
+#include <asm/keyboard.h>
+#include <asm/bitops.h>
+#include <asm/cuda.h>
+
+#include <linux/kbd_kern.h>
+#include <linux/kbd_ll.h>
+
+#define KEYB_KEYREG	0	/* register # for key up/down data */
+#define KEYB_LEDREG	2	/* register # for leds on ADB keyboard */
+#define MOUSE_DATAREG	0	/* reg# for movement/button codes from mouse */
+
+unsigned char kbd_read_mask = 0;	/* XXX */
+
+static void kbd_repeat(unsigned long);
+static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat };
+static int last_keycode;
+
+static void keyboard_input(unsigned char *, int, struct pt_regs *);
+static void input_keycode(int, int);
+static void leds_done(struct cuda_request *);
+
+extern struct kbd_struct kbd_table[];
+
+extern void handle_scancode(unsigned char);
+extern void put_queue(int);
+
+/* this map indicates which keys shouldn't autorepeat. */
+static unsigned char dont_repeat[128] = {
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,	/* esc...option */
+	0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* num lock */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, /* scroll lock */
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+int mackbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+	return -EINVAL;
+}
+
+int mackbd_getkeycode(unsigned int scancode)
+{
+	return -EINVAL;
+}
+
+int mackbd_pretranslate(unsigned char scancode, char raw_mode)
+{
+	return 1;
+}
+
+int mackbd_translate(unsigned char keycode, unsigned char *keycodep,
+		     char raw_mode)
+{
+	if (!raw_mode) {
+		/*
+		 * Convert R-shift/control/option to L version.
+		 * Remap keycode 0 (A) to the unused keycode 0x5a.
+		 * Other parts of the system assume 0 is not a valid keycode.
+		 */
+		switch (keycode) {
+		case 0x7b: keycode = 0x38; break; /* R-shift */
+		case 0x7c: keycode = 0x3a; break; /* R-option */
+		case 0x7d: keycode = 0x36; break; /* R-control */
+		case 0:	   keycode = 0x5a; break; /* A */
+		}
+	}
+	*keycodep = keycode;
+	return 1;
+}
+
+int mackbd_unexpected_up(unsigned char keycode)
+{
+	return 0x80;
+}
+
+static void
+keyboard_input(unsigned char *data, int nb, struct pt_regs *regs)
+{
+	/* first check this is from register 0 */
+	if (nb != 5 || (data[2] & 3) != KEYB_KEYREG)
+		return;		/* ignore it */
+	kbd_pt_regs = regs;
+	input_keycode(data[3], 0);
+	if (!(data[4] == 0xff || (data[4] == 0x7f && data[3] == 0x7f)))
+		input_keycode(data[4], 0);
+}
+
+static void
+input_keycode(int keycode, int repeat)
+{
+	struct kbd_struct *kbd;
+	int up_flag;
+
+ 	kbd = kbd_table + fg_console;
+	up_flag = (keycode & 0x80);
+        keycode &= 0x7f;
+	if (!repeat)
+		del_timer(&repeat_timer);
+
+	if (kbd->kbdmode != VC_RAW) {
+		if (!up_flag && !dont_repeat[keycode]) {
+			last_keycode = keycode;
+			repeat_timer.expires = jiffies + (repeat? HZ/15: HZ/2);
+			add_timer(&repeat_timer);
+		}
+
+		/*
+		 * XXX fix caps-lock behaviour by turning the key-up
+		 * transition into a key-down transition.
+		 */
+		if (keycode == 0x39 && up_flag && vc_kbd_led(kbd, VC_CAPSLOCK))
+			up_flag = 0;
+	}
+
+	handle_scancode(keycode + up_flag);
+}
+
+static void
+kbd_repeat(unsigned long xxx)
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	input_keycode(last_keycode, 1);
+	restore_flags(flags);
+}
+
+static void
+mouse_input(unsigned char *data, int nb, struct pt_regs *regs)
+{
+  /* [ACA:23-Mar-97] Three button mouse support.  This is designed to
+     function with MkLinux DR-2.1 style X servers.  It only works with
+     three-button mice that conform to Apple's multi-button mouse
+     protocol. */
+
+  /*
+    The X server for MkLinux DR2.1 uses the following unused keycodes to
+    read the mouse:
+
+    0x7e  This indicates that the next two keycodes should be interpreted
+          as mouse information.  The first following byte's high bit
+          represents the state of the left button.  The lower seven bits
+          represent the x-axis acceleration.  The lower seven bits of the
+          second byte represent y-axis acceleration.
+
+    0x3f  The x server interprets this keycode as a middle button
+          release.
+
+    0xbf  The x server interprets this keycode as a middle button
+          depress.
+
+    0x40  The x server interprets this keycode as a right button
+          release.
+
+    0xc0  The x server interprets this keycode as a right button
+          depress.
+
+    NOTES: There should be a better way of handling mice in the X server.
+    The MOUSE_ESCAPE code (0x7e) should be followed by three bytes instead
+    of two.  The three mouse buttons should then, in the X server, be read
+    as the high-bits of all three bytes.  The x and y motions can still be
+    in the first two bytes.  Maybe I'll do this...
+  */
+
+  /*
+    Handler 4 -- Apple Extended mouse protocol.
+
+    For Apple's 3-button mouse protocol the data array will contain the
+    following values:
+
+		BITS    COMMENTS
+    data[0] = 0000 0000 ADB packet identifer.
+    data[1] = 0100 0000 Extended protocol register.
+	      Bits 6-7 are the device id, which should be 1.
+	      Bits 4-5 are resolution which is in "units/inch".
+	      The Logitech MouseMan returns these bits clear but it has
+	      200/300cpi resolution.
+	      Bits 0-3 are unique vendor id.
+    data[2] = 0011 1100 Bits 0-1 should be zero for a mouse device.
+	      Bits 2-3 should be 8 + 4.
+		      Bits 4-7 should be 3 for a mouse device.
+    data[3] = bxxx xxxx Left button and x-axis motion.
+    data[4] = byyy yyyy Second button and y-axis motion.
+    data[5] = byyy bxxx Third button and fourth button.  Y is additional
+	      high bits of y-axis motion.  XY is additional
+	      high bits of x-axis motion.
+
+    NOTE: data[0] and data[2] are confirmed by the parent function and
+    need not be checked here.
+  */
+
+  /*
+    Handler 1 -- 100cpi original Apple mouse protocol.
+    Handler 2 -- 200cpi original Apple mouse protocol.
+
+    For Apple's standard one-button mouse protocol the data array will
+    contain the following values:
+
+                BITS    COMMENTS
+    data[0] = 0000 0000 ADB packet identifer.
+    data[1] = ???? ???? (?)
+    data[2] = ???? ??00 Bits 0-1 should be zero for a mouse device.
+    data[3] = bxxx xxxx First button and x-axis motion.
+    data[4] = byyy yyyy Second button and y-axis motion.
+
+    NOTE: data[0] is confirmed by the parent function and need not be
+    checked here.
+  */
+	struct kbd_struct *kbd;
+
+	kbd = kbd_table + fg_console;
+
+	/* Only send mouse codes when keyboard is in raw mode. */
+	if (kbd->kbdmode == VC_RAW) {
+		static unsigned char uch_ButtonStateSecond = 0;
+		unsigned char uchButtonSecond;
+
+		/* Send first button, second button and movement. */
+		put_queue( 0x7e );
+		put_queue( data[3] );
+		put_queue( data[4] );
+
+		/* [ACA: Are there any two-button ADB mice that use handler 1 or 2?] */
+
+		/* Store the button state. */
+		uchButtonSecond = (data[4] & 0x80);
+
+		/* Send second button. */
+		if (uchButtonSecond != uch_ButtonStateSecond) {
+			put_queue( 0x3f | uchButtonSecond );
+			uch_ButtonStateSecond = uchButtonSecond;
+		}
+
+		/* Macintosh 3-button mouse (handler 4). */
+		if ((nb == 6) && (data[1] & 0x40)) {
+			static unsigned char uch_ButtonStateThird = 0;
+			unsigned char uchButtonThird;
+
+			/* Store the button state for speed. */
+			uchButtonThird = (data[5] & 0x80);
+
+			/* Send third button. */
+			if (uchButtonThird != uch_ButtonStateThird) {
+				put_queue( 0x40 | uchButtonThird );
+				uch_ButtonStateThird = uchButtonThird;
+			}
+		}
+	}
+}
+
+/* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */
+static unsigned char mac_ledmap[8] = {
+    0,		/* none */
+    4,		/* scroll lock */
+    1,		/* num lock */
+    5,		/* scroll + num lock */
+    2,		/* caps lock */
+    6,		/* caps + scroll lock */
+    3,		/* caps + num lock */
+    7,		/* caps + num + scroll lock */
+};
+
+static struct cuda_request led_request;
+static int leds_pending;
+
+void mackbd_leds(unsigned char leds)
+{
+	if (led_request.got_reply) {
+		cuda_request(&led_request, leds_done, 4, ADB_PACKET,
+			     ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG),
+			     0xff, ~mac_ledmap[leds]);
+	} else
+		leds_pending = leds | 0x100;
+}
+
+static void leds_done(struct cuda_request *req)
+{
+	int leds;
+
+	if (leds_pending) {
+		leds = leds_pending & 0xff;
+		leds_pending = 0;
+		mackbd_leds(leds);
+	}
+}
+
+void mackbd_init_hw(void)
+{
+	struct cuda_request req;
+
+	adb_register(ADB_KEYBOARD, keyboard_input);
+	adb_register(ADB_MOUSE, mouse_input);
+
+	/* turn on ADB auto-polling in the CUDA */
+	cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1);
+	while (!req.got_reply)
+	    cuda_poll();
+
+	/* turn off all leds */
+	cuda_request(&req, NULL, 4, ADB_PACKET,
+		     ADB_WRITEREG(ADB_KEYBOARD, KEYB_LEDREG), 0xff, 0xff);
+	while (!req.got_reply)
+	    cuda_poll();
+
+	/* get the keyboard to send separate codes for
+	   left and right shift, control, option keys. */
+	cuda_request(&req, NULL, 4, ADB_PACKET,
+		     ADB_WRITEREG(ADB_KEYBOARD, 3), 0, 3);
+	while (!req.got_reply)
+	    cuda_poll();
+
+	led_request.got_reply = 1;
+
+	/* Try to switch the mouse (id 3) to handler 4, for three-button
+	   mode. (0x20 is Service Request Enable, 0x03 is Device ID). */
+	cuda_request(&req, NULL, 4, ADB_PACKET,
+		     ADB_WRITEREG(ADB_MOUSE, 3), 0x23, 4 );
+	while (!req.got_reply)
+		cuda_poll();
+}
+
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/mackeymap.c linux/drivers/macintosh/mackeymap.c
--- v2.1.50/linux/drivers/macintosh/mackeymap.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/mackeymap.c	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,262 @@
+/* Do not edit this file! It was automatically generated by   */
+/*    loadkeys --mktable defkeymap.map > defkeymap.c          */
+
+#include <linux/types.h>
+#include <linux/keyboard.h>
+#include <linux/kd.h>
+
+u_short plain_map[NR_KEYS] = {
+	0xf200,	0xfb73,	0xfb64,	0xfb66,	0xfb68,	0xfb67,	0xfb7a,	0xfb78,
+	0xfb63,	0xfb76,	0xf200,	0xfb62,	0xfb71,	0xfb77,	0xfb65,	0xfb72,
+	0xfb79,	0xfb74,	0xf031,	0xf032,	0xf033,	0xf034,	0xf036,	0xf035,
+	0xf03d,	0xf039,	0xf037,	0xf02d,	0xf038,	0xf030,	0xf05d,	0xfb6f,
+	0xfb75,	0xf05b,	0xfb69,	0xfb70,	0xf201,	0xfb6c,	0xfb6a,	0xf027,
+	0xfb6b,	0xf03b,	0xf05c,	0xf02c,	0xf02f,	0xfb6e,	0xfb6d,	0xf02e,
+	0xf009,	0xf020,	0xf060,	0xf07f,	0xf200,	0xf01b,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
+	0xf306,	0xf307,	0xfb61,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
+	0xf104,	0xf105,	0xf106,	0xf102,	0xf107,	0xf108,	0xf200,	0xf10a,
+	0xf200,	0xf10c,	0xf200,	0xf209,	0xf200,	0xf109,	0xf200,	0xf10b,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf103,	0xf117,
+	0xf101,	0xf119,	0xf100,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short shift_map[NR_KEYS] = {
+	0xf200,	0xfb53,	0xfb44,	0xfb46,	0xfb48,	0xfb47,	0xfb5a,	0xfb58,
+	0xfb43,	0xfb56,	0xf200,	0xfb42,	0xfb51,	0xfb57,	0xfb45,	0xfb52,
+	0xfb59,	0xfb54,	0xf021,	0xf040,	0xf023,	0xf024,	0xf05e,	0xf025,
+	0xf02b,	0xf028,	0xf026,	0xf05f,	0xf02a,	0xf029,	0xf07d,	0xfb4f,
+	0xfb55,	0xf07b,	0xfb49,	0xfb50,	0xf201,	0xfb4c,	0xfb4a,	0xf022,
+	0xfb4b,	0xf03a,	0xf07c,	0xf03c,	0xf03f,	0xfb4e,	0xfb4d,	0xf03e,
+	0xf009,	0xf020,	0xf07e,	0xf07f,	0xf200,	0xf01b,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
+	0xf306,	0xf307,	0xfb41,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
+	0xf10e,	0xf10f,	0xf110,	0xf10c,	0xf111,	0xf112,	0xf200,	0xf10a,
+	0xf200,	0xf10c,	0xf200,	0xf203,	0xf200,	0xf113,	0xf200,	0xf10b,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf20b,	0xf116,	0xf10d,	0xf117,
+	0xf10b,	0xf20a,	0xf10a,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short altgr_map[NR_KEYS] = {
+	0xf200,	0xfb73,	0xf917,	0xf919,	0xfb68,	0xfb67,	0xfb7a,	0xfb78,
+	0xf916,	0xfb76,	0xf200,	0xf915,	0xfb71,	0xfb77,	0xf918,	0xfb72,
+	0xfb79,	0xfb74,	0xf200,	0xf040,	0xf200,	0xf024,	0xf200,	0xf200,
+	0xf200,	0xf05d,	0xf07b,	0xf05c,	0xf05b,	0xf07d,	0xf07e,	0xfb6f,
+	0xfb75,	0xf200,	0xfb69,	0xfb70,	0xf201,	0xfb6c,	0xfb6a,	0xf200,
+	0xfb6b,	0xf200,	0xf200,	0xf200,	0xf200,	0xfb6e,	0xfb6d,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf90a,	0xf90b,	0xf90c,	0xf90d,	0xf90e,	0xf90f,
+	0xf910,	0xf911,	0xf914,	0xf912,	0xf913,	0xf200,	0xf200,	0xf200,
+	0xf510,	0xf511,	0xf512,	0xf50e,	0xf513,	0xf514,	0xf200,	0xf516,
+	0xf200,	0xf10c,	0xf200,	0xf202,	0xf200,	0xf515,	0xf200,	0xf517,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf50f,	0xf117,
+	0xf50d,	0xf119,	0xf50c,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short ctrl_map[NR_KEYS] = {
+	0xf200,	0xf013,	0xf004,	0xf006,	0xf008,	0xf007,	0xf01a,	0xf018,
+	0xf003,	0xf016,	0xf200,	0xf002,	0xf011,	0xf017,	0xf005,	0xf012,
+	0xf019,	0xf014,	0xf200,	0xf000,	0xf01b,	0xf01c,	0xf01e,	0xf01d,
+	0xf200,	0xf200,	0xf01f,	0xf01f,	0xf07f,	0xf200,	0xf01d,	0xf00f,
+	0xf015,	0xf01b,	0xf009,	0xf010,	0xf201,	0xf00c,	0xf00a,	0xf007,
+	0xf00b,	0xf200,	0xf01c,	0xf200,	0xf07f,	0xf00e,	0xf00d,	0xf20e,
+	0xf200,	0xf000,	0xf000,	0xf008,	0xf200,	0xf200,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
+	0xf306,	0xf307,	0xf001,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
+	0xf104,	0xf105,	0xf106,	0xf102,	0xf107,	0xf108,	0xf200,	0xf10a,
+	0xf200,	0xf10c,	0xf200,	0xf204,	0xf200,	0xf109,	0xf200,	0xf10b,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf103,	0xf117,
+	0xf101,	0xf119,	0xf100,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short shift_ctrl_map[NR_KEYS] = {
+	0xf200,	0xf013,	0xf004,	0xf006,	0xf008,	0xf007,	0xf01a,	0xf018,
+	0xf003,	0xf016,	0xf200,	0xf002,	0xf011,	0xf017,	0xf005,	0xf012,
+	0xf019,	0xf014,	0xf200,	0xf000,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf200,	0xf200,	0xf00f,
+	0xf015,	0xf200,	0xf009,	0xf010,	0xf201,	0xf00c,	0xf00a,	0xf200,
+	0xf00b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf00e,	0xf00d,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
+	0xf306,	0xf307,	0xf001,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf10c,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf200,	0xf117,
+	0xf200,	0xf119,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf20c,
+};
+
+u_short alt_map[NR_KEYS] = {
+	0xf200,	0xf873,	0xf864,	0xf866,	0xf868,	0xf867,	0xf87a,	0xf878,
+	0xf863,	0xf876,	0xf200,	0xf862,	0xf871,	0xf877,	0xf865,	0xf872,
+	0xf879,	0xf874,	0xf831,	0xf832,	0xf833,	0xf834,	0xf836,	0xf835,
+	0xf83d,	0xf839,	0xf837,	0xf82d,	0xf838,	0xf830,	0xf85d,	0xf86f,
+	0xf875,	0xf85b,	0xf869,	0xf870,	0xf80d,	0xf86c,	0xf86a,	0xf827,
+	0xf86b,	0xf83b,	0xf85c,	0xf82c,	0xf82f,	0xf86e,	0xf86d,	0xf82e,
+	0xf809,	0xf820,	0xf860,	0xf87f,	0xf200,	0xf81b,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf210,	0xf211,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf900,	0xf901,	0xf902,	0xf903,	0xf904,	0xf905,
+	0xf906,	0xf907,	0xf861,	0xf908,	0xf909,	0xf200,	0xf200,	0xf200,
+	0xf504,	0xf505,	0xf506,	0xf502,	0xf507,	0xf508,	0xf200,	0xf50a,
+	0xf200,	0xf10c,	0xf200,	0xf209,	0xf200,	0xf509,	0xf200,	0xf50b,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf503,	0xf117,
+	0xf501,	0xf119,	0xf500,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+u_short ctrl_alt_map[NR_KEYS] = {
+	0xf200,	0xf813,	0xf804,	0xf806,	0xf808,	0xf807,	0xf81a,	0xf818,
+	0xf803,	0xf816,	0xf200,	0xf802,	0xf811,	0xf817,	0xf805,	0xf812,
+	0xf819,	0xf814,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf80f,
+	0xf815,	0xf200,	0xf809,	0xf810,	0xf201,	0xf80c,	0xf80a,	0xf200,
+	0xf80b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf80e,	0xf80d,	0xf200,
+	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf702,	0xf703,
+	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
+	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
+	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
+	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
+	0xf306,	0xf307,	0xf801,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
+	0xf504,	0xf505,	0xf506,	0xf502,	0xf507,	0xf508,	0xf200,	0xf50a,
+	0xf200,	0xf10c,	0xf200,	0xf200,	0xf200,	0xf509,	0xf200,	0xf50b,
+	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf503,	0xf117,
+	0xf501,	0xf119,	0xf500,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
+};
+
+ushort *key_maps[MAX_NR_KEYMAPS] = {
+	plain_map, shift_map, altgr_map, 0,
+	ctrl_map, shift_ctrl_map, 0, 0,
+	alt_map, 0, 0, 0,
+	ctrl_alt_map,	0
+};
+
+unsigned int keymap_count = 7;
+
+/*
+ * Philosophy: most people do not define more strings, but they who do
+ * often want quite a lot of string space. So, we statically allocate
+ * the default and allocate dynamically in chunks of 512 bytes.
+ */
+
+char func_buf[] = {
+	'\033', '[', '[', 'A', 0, 
+	'\033', '[', '[', 'B', 0, 
+	'\033', '[', '[', 'C', 0, 
+	'\033', '[', '[', 'D', 0, 
+	'\033', '[', '[', 'E', 0, 
+	'\033', '[', '1', '7', '~', 0, 
+	'\033', '[', '1', '8', '~', 0, 
+	'\033', '[', '1', '9', '~', 0, 
+	'\033', '[', '2', '0', '~', 0, 
+	'\033', '[', '2', '1', '~', 0, 
+	'\033', '[', '2', '3', '~', 0, 
+	'\033', '[', '2', '4', '~', 0, 
+	'\033', '[', '2', '5', '~', 0, 
+	'\033', '[', '2', '6', '~', 0, 
+	'\033', '[', '2', '8', '~', 0, 
+	'\033', '[', '2', '9', '~', 0, 
+	'\033', '[', '3', '1', '~', 0, 
+	'\033', '[', '3', '2', '~', 0, 
+	'\033', '[', '3', '3', '~', 0, 
+	'\033', '[', '3', '4', '~', 0, 
+	'\033', '[', '1', '~', 0, 
+	'\033', '[', '2', '~', 0, 
+	'\033', '[', '3', '~', 0, 
+	'\033', '[', '4', '~', 0, 
+	'\033', '[', '5', '~', 0, 
+	'\033', '[', '6', '~', 0, 
+	'\033', '[', 'M', 0, 
+	'\033', '[', 'P', 0, 
+};
+
+char *funcbufptr = func_buf;
+int funcbufsize = sizeof(func_buf);
+int funcbufleft = 0;          /* space left */
+
+char *func_table[MAX_NR_FUNC] = {
+	func_buf + 0,
+	func_buf + 5,
+	func_buf + 10,
+	func_buf + 15,
+	func_buf + 20,
+	func_buf + 25,
+	func_buf + 31,
+	func_buf + 37,
+	func_buf + 43,
+	func_buf + 49,
+	func_buf + 55,
+	func_buf + 61,
+	func_buf + 67,
+	func_buf + 73,
+	func_buf + 79,
+	func_buf + 85,
+	func_buf + 91,
+	func_buf + 97,
+	func_buf + 103,
+	func_buf + 109,
+	func_buf + 115,
+	func_buf + 120,
+	func_buf + 125,
+	func_buf + 130,
+	func_buf + 135,
+	func_buf + 140,
+	func_buf + 145,
+	0,
+	0,
+	func_buf + 149,
+	0,
+};
+
+struct kbdiacr accent_table[MAX_DIACR] = {
+	{'`', 'A', '\300'},	{'`', 'a', '\340'},
+	{'\'', 'A', '\301'},	{'\'', 'a', '\341'},
+	{'^', 'A', '\302'},	{'^', 'a', '\342'},
+	{'~', 'A', '\303'},	{'~', 'a', '\343'},
+	{'"', 'A', '\304'},	{'"', 'a', '\344'},
+	{'O', 'A', '\305'},	{'o', 'a', '\345'},
+	{'0', 'A', '\305'},	{'0', 'a', '\345'},
+	{'A', 'A', '\305'},	{'a', 'a', '\345'},
+	{'A', 'E', '\306'},	{'a', 'e', '\346'},
+	{',', 'C', '\307'},	{',', 'c', '\347'},
+	{'`', 'E', '\310'},	{'`', 'e', '\350'},
+	{'\'', 'E', '\311'},	{'\'', 'e', '\351'},
+	{'^', 'E', '\312'},	{'^', 'e', '\352'},
+	{'"', 'E', '\313'},	{'"', 'e', '\353'},
+	{'`', 'I', '\314'},	{'`', 'i', '\354'},
+	{'\'', 'I', '\315'},	{'\'', 'i', '\355'},
+	{'^', 'I', '\316'},	{'^', 'i', '\356'},
+	{'"', 'I', '\317'},	{'"', 'i', '\357'},
+	{'-', 'D', '\320'},	{'-', 'd', '\360'},
+	{'~', 'N', '\321'},	{'~', 'n', '\361'},
+	{'`', 'O', '\322'},	{'`', 'o', '\362'},
+	{'\'', 'O', '\323'},	{'\'', 'o', '\363'},
+	{'^', 'O', '\324'},	{'^', 'o', '\364'},
+	{'~', 'O', '\325'},	{'~', 'o', '\365'},
+	{'"', 'O', '\326'},	{'"', 'o', '\366'},
+	{'/', 'O', '\330'},	{'/', 'o', '\370'},
+	{'`', 'U', '\331'},	{'`', 'u', '\371'},
+	{'\'', 'U', '\332'},	{'\'', 'u', '\372'},
+	{'^', 'U', '\333'},	{'^', 'u', '\373'},
+	{'"', 'U', '\334'},	{'"', 'u', '\374'},
+	{'\'', 'Y', '\335'},	{'\'', 'y', '\375'},
+	{'T', 'H', '\336'},	{'t', 'h', '\376'},
+	{'s', 's', '\337'},	{'"', 'y', '\377'},
+	{'s', 'z', '\337'},	{'i', 'j', '\377'},
+};
+
+unsigned int accent_table_size = 68;
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/mackeymap.map linux/drivers/macintosh/mackeymap.map
--- v2.1.50/linux/drivers/macintosh/mackeymap.map	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/mackeymap.map	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,346 @@
+# Kernel keymap for Macintoshes. This uses 7 modifier combinations.
+keymaps 0-2,4-5,8,12
+# We use the Command (pretzel) key as Alt, and the Option key as AltGr.
+#
+keycode 0x00 =
+keycode 0x01 = s               
+keycode 0x02 = d
+	altgr   keycode 0x02 = Hex_D   
+keycode 0x03 = f
+	altgr   keycode 0x03 = Hex_F               
+keycode 0x04 = h               
+keycode 0x05 = g  
+keycode 0x06 = z
+keycode 0x07 = x               
+keycode 0x08 = c
+	altgr   keycode 0x08 = Hex_C   
+keycode 0x09 = v
+keycode 0x0a =
+keycode 0x0b = b
+	altgr   keycode 0x0b = Hex_B
+keycode 0x0c = q               
+keycode 0x0d = w               
+keycode 0x0e = e
+	altgr   keycode 0x0e = Hex_E   
+keycode 0x0f = r               
+keycode 0x10 = y               
+keycode 0x11 = t               
+keycode 0x12 = one              exclam          
+	alt     keycode 0x12 = Meta_one        
+keycode 0x13 = two              at               at              
+	control	keycode 0x13 = nul             
+	shift	control	keycode 0x13 = nul             
+	alt	keycode 0x13 = Meta_two        
+keycode 0x14 = three            numbersign      
+	control keycode 0x14 = Escape          
+	alt     keycode 0x14 = Meta_three      
+keycode 0x15 = four             dollar           dollar          
+	control keycode 0x15 = Control_backslash
+	alt     keycode 0x15 = Meta_four       
+keycode 0x16 = six              asciicircum     
+	control keycode 0x16 = Control_asciicircum
+	alt     keycode 0x16 = Meta_six        
+keycode 0x17 = five             percent         
+	control keycode 0x17 = Control_bracketright
+	alt     keycode 0x17 = Meta_five       
+keycode 0x18 = equal            plus            
+	alt     keycode 0x18 = Meta_equal      
+keycode 0x19 = nine             parenleft        bracketright    
+	alt     keycode 0x19 = Meta_nine       
+keycode 0x1a = seven            ampersand        braceleft       
+	control keycode 0x1a = Control_underscore
+	alt     keycode 0x1a = Meta_seven      
+keycode 0x1b = minus            underscore       backslash       
+	control	keycode 0x1b = Control_underscore
+	shift	control	keycode 0x1b = Control_underscore
+	alt	keycode 0x1b = Meta_minus      
+keycode 0x1c = eight            asterisk         bracketleft     
+	control keycode 0x1c = Delete          
+	alt     keycode 0x1c = Meta_eight      
+keycode 0x1d = zero             parenright       braceright      
+	alt     keycode 0x1d = Meta_zero       
+keycode 0x1e = bracketright     braceright       asciitilde      
+	control keycode 0x1e = Control_bracketright
+	alt     keycode 0x1e = Meta_bracketright
+keycode 0x1f = o               
+keycode 0x20 = u               
+keycode 0x21 = bracketleft      braceleft       
+	control keycode 0x21 = Escape          
+	alt     keycode 0x21 = Meta_bracketleft
+keycode 0x22 = i               
+keycode 0x23 = p               
+keycode 0x24 = Return          
+	alt     keycode 0x24 = Meta_Control_m  
+keycode 0x25 = l               
+keycode 0x26 = j               
+keycode 0x27 = apostrophe       quotedbl        
+	control keycode 0x27 = Control_g       
+	alt     keycode 0x27 = Meta_apostrophe 
+keycode 0x28 = k               
+keycode 0x29 = semicolon        colon           
+	alt     keycode 0x29 = Meta_semicolon  
+keycode 0x2a = backslash        bar             
+	control keycode 0x2a = Control_backslash
+	alt     keycode 0x2a = Meta_backslash  
+keycode 0x2b = comma            less            
+	alt     keycode 0x2b = Meta_comma      
+keycode 0x2c = slash            question        
+	control keycode 0x2c = Delete          
+	alt     keycode 0x2c = Meta_slash      
+keycode 0x2d = n
+keycode 0x2e = m               
+keycode 0x2f = period           greater         
+	control keycode 0x2f = Compose         
+	alt     keycode 0x2f = Meta_period     
+keycode 0x30 = Tab              Tab             
+	alt     keycode 0x30 = Meta_Tab        
+keycode 0x31 = space            space           
+	control keycode 0x31 = nul             
+	alt     keycode 0x31 = Meta_space      
+keycode 0x32 = grave            asciitilde      
+	control keycode 0x32 = nul             
+	alt     keycode 0x32 = Meta_grave      
+keycode 0x33 = Delete           Delete          
+	control keycode 0x33 = BackSpace
+	alt     keycode 0x33 = Meta_Delete     
+keycode 0x34 =
+keycode 0x35 = Escape           Escape          
+	alt     keycode 0x35 = Meta_Escape     
+keycode 0x36 = Control         
+keycode 0x37 = Alt             
+keycode 0x38 = Shift
+keycode 0x39 = Caps_Lock       
+keycode 0x3a = AltGr           
+keycode 0x3b = Left            
+	alt     keycode 0x3b = Decr_Console
+keycode 0x3c = Right           
+	alt     keycode 0x3c = Incr_Console
+keycode 0x3d = Down            
+keycode 0x3e = Up              
+keycode 0x3f =
+keycode 0x40 =
+keycode 0x41 = KP_Period       
+keycode 0x42 =
+keycode 0x43 = KP_Multiply     
+keycode 0x44 =
+keycode 0x45 = KP_Add          
+keycode 0x46 =
+keycode 0x47 = Num_Lock
+#	shift   keycode 0x47 = Bare_Num_Lock
+keycode 0x48 =
+keycode 0x49 =
+keycode 0x4a =
+keycode 0x4b = KP_Divide       
+keycode 0x4c = KP_Enter        
+keycode 0x4d =
+keycode 0x4e = KP_Subtract     
+keycode 0x4f =
+keycode 0x50 =
+keycode 0x51 =
+#keycode 0x51 = KP_Equals
+keycode 0x52 = KP_0            
+	alt     keycode 0x52 = Ascii_0         
+	altgr   keycode 0x52 = Hex_0         
+keycode 0x53 = KP_1            
+	alt     keycode 0x53 = Ascii_1         
+	altgr   keycode 0x53 = Hex_1         
+keycode 0x54 = KP_2            
+	alt     keycode 0x54 = Ascii_2         
+	altgr   keycode 0x54 = Hex_2         
+keycode 0x55 = KP_3            
+	alt     keycode 0x55 = Ascii_3         
+	altgr   keycode 0x55 = Hex_3         
+keycode 0x56 = KP_4            
+	alt     keycode 0x56 = Ascii_4         
+	altgr   keycode 0x56 = Hex_4         
+keycode 0x57 = KP_5            
+	alt     keycode 0x57 = Ascii_5         
+	altgr   keycode 0x57 = Hex_5         
+keycode 0x58 = KP_6            
+	alt     keycode 0x58 = Ascii_6         
+	altgr   keycode 0x58 = Hex_6         
+keycode 0x59 = KP_7            
+	alt     keycode 0x59 = Ascii_7         
+	altgr   keycode 0x59 = Hex_7
+# keycode 0 (A) is remapped to here         
+keycode 0x5a = a
+	altgr   keycode 0x00 = Hex_A
+keycode 0x5b = KP_8            
+	alt     keycode 0x5b = Ascii_8         
+	altgr   keycode 0x5b = Hex_8         
+keycode 0x5c = KP_9            
+	alt     keycode 0x5c = Ascii_9         
+	altgr   keycode 0x5c = Hex_9         
+keycode 0x5d =
+keycode 0x5e =
+keycode 0x5f =
+keycode 0x60 = F5               F15              Console_17      
+	control keycode 0x60 = F5              
+	alt     keycode 0x60 = Console_5       
+	control alt     keycode 0x60 = Console_5       
+keycode 0x61 = F6               F16              Console_18      
+	control keycode 0x61 = F6              
+	alt     keycode 0x61 = Console_6       
+	control alt     keycode 0x61 = Console_6       
+keycode 0x62 = F7               F17              Console_19      
+	control keycode 0x62 = F7              
+	alt     keycode 0x62 = Console_7       
+	control alt     keycode 0x62 = Console_7       
+keycode 0x63 = F3               F13              Console_15      
+	control keycode 0x63 = F3              
+	alt     keycode 0x63 = Console_3       
+	control alt     keycode 0x63 = Console_3       
+keycode 0x64 = F8               F18              Console_20      
+	control keycode 0x64 = F8              
+	alt     keycode 0x64 = Console_8       
+	control alt     keycode 0x64 = Console_8       
+keycode 0x65 = F9               F19              Console_21      
+	control keycode 0x65 = F9              
+	alt     keycode 0x65 = Console_9       
+	control alt     keycode 0x65 = Console_9       
+keycode 0x66 =
+keycode 0x67 = F11              F11              Console_23      
+	control keycode 0x67 = F11             
+	alt     keycode 0x67 = Console_11      
+	control alt     keycode 0x67 = Console_11      
+keycode 0x68 =
+keycode 0x69 = F13             
+keycode 0x6a =
+keycode 0x6b = Scroll_Lock      Show_Memory      Show_Registers  
+	control keycode 0x6b = Show_State      
+	alt     keycode 0x6b = Scroll_Lock     
+keycode 0x6c =
+keycode 0x6d = F10              F20              Console_22      
+	control keycode 0x6d = F10             
+	alt     keycode 0x6d = Console_10      
+	control alt     keycode 0x6d = Console_10      
+keycode 0x6e =
+keycode 0x6f = F12              F12              Console_24      
+	control keycode 0x6f = F12             
+	alt     keycode 0x6f = Console_12      
+	control alt     keycode 0x6f = Console_12      
+keycode 0x70 =
+keycode 0x71 = Pause
+keycode 0x72 = Insert          
+keycode 0x73 = Home
+keycode 0x74 = Prior           
+	shift   keycode 0x74 = Scroll_Backward 
+keycode 0x75 = Remove          
+keycode 0x76 = F4               F14              Console_16      
+	control keycode 0x76 = F4              
+	alt     keycode 0x76 = Console_4       
+	control alt     keycode 0x76 = Console_4       
+keycode 0x77 = End
+keycode 0x78 = F2               F12              Console_14      
+	control keycode 0x78 = F2              
+	alt     keycode 0x78 = Console_2       
+	control alt     keycode 0x78 = Console_2       
+keycode 0x79 = Next            
+	shift   keycode 0x79 = Scroll_Forward  
+keycode 0x7a = F1               F11              Console_13      
+	control keycode 0x7a = F1              
+	alt     keycode 0x7a = Console_1       
+	control alt     keycode 0x7a = Console_1       
+keycode 0x7b = Shift
+keycode 0x7c = AltGr
+keycode 0x7d = Control
+keycode 0x7e =
+keycode 0x7f =
+#keycode 0x7f = Power
+	control shift   keycode 0x7f = Boot
+string F1 = "\033[[A"
+string F2 = "\033[[B"
+string F3 = "\033[[C"
+string F4 = "\033[[D"
+string F5 = "\033[[E"
+string F6 = "\033[17~"
+string F7 = "\033[18~"
+string F8 = "\033[19~"
+string F9 = "\033[20~"
+string F10 = "\033[21~"
+string F11 = "\033[23~"
+string F12 = "\033[24~"
+string F13 = "\033[25~"
+string F14 = "\033[26~"
+string F15 = "\033[28~"
+string F16 = "\033[29~"
+string F17 = "\033[31~"
+string F18 = "\033[32~"
+string F19 = "\033[33~"
+string F20 = "\033[34~"
+string Find = "\033[1~"
+string Insert = "\033[2~"
+string Remove = "\033[3~"
+string Select = "\033[4~"
+string Prior = "\033[5~"
+string Next = "\033[6~"
+string Macro = "\033[M"
+string Pause = "\033[P"
+compose '`' 'A' to 'À'
+compose '`' 'a' to 'à'
+compose '\'' 'A' to 'Á'
+compose '\'' 'a' to 'á'
+compose '^' 'A' to 'Â'
+compose '^' 'a' to 'â'
+compose '~' 'A' to 'Ã'
+compose '~' 'a' to 'ã'
+compose '"' 'A' to 'Ä'
+compose '"' 'a' to 'ä'
+compose 'O' 'A' to 'Å'
+compose 'o' 'a' to 'å'
+compose '0' 'A' to 'Å'
+compose '0' 'a' to 'å'
+compose 'A' 'A' to 'Å'
+compose 'a' 'a' to 'å'
+compose 'A' 'E' to 'Æ'
+compose 'a' 'e' to 'æ'
+compose ',' 'C' to 'Ç'
+compose ',' 'c' to 'ç'
+compose '`' 'E' to 'È'
+compose '`' 'e' to 'è'
+compose '\'' 'E' to 'É'
+compose '\'' 'e' to 'é'
+compose '^' 'E' to 'Ê'
+compose '^' 'e' to 'ê'
+compose '"' 'E' to 'Ë'
+compose '"' 'e' to 'ë'
+compose '`' 'I' to 'Ì'
+compose '`' 'i' to 'ì'
+compose '\'' 'I' to 'Í'
+compose '\'' 'i' to 'í'
+compose '^' 'I' to 'Î'
+compose '^' 'i' to 'î'
+compose '"' 'I' to 'Ï'
+compose '"' 'i' to 'ï'
+compose '-' 'D' to 'Ð'
+compose '-' 'd' to 'ð'
+compose '~' 'N' to 'Ñ'
+compose '~' 'n' to 'ñ'
+compose '`' 'O' to 'Ò'
+compose '`' 'o' to 'ò'
+compose '\'' 'O' to 'Ó'
+compose '\'' 'o' to 'ó'
+compose '^' 'O' to 'Ô'
+compose '^' 'o' to 'ô'
+compose '~' 'O' to 'Õ'
+compose '~' 'o' to 'õ'
+compose '"' 'O' to 'Ö'
+compose '"' 'o' to 'ö'
+compose '/' 'O' to 'Ø'
+compose '/' 'o' to 'ø'
+compose '`' 'U' to 'Ù'
+compose '`' 'u' to 'ù'
+compose '\'' 'U' to 'Ú'
+compose '\'' 'u' to 'ú'
+compose '^' 'U' to 'Û'
+compose '^' 'u' to 'û'
+compose '"' 'U' to 'Ü'
+compose '"' 'u' to 'ü'
+compose '\'' 'Y' to 'Ý'
+compose '\'' 'y' to 'ý'
+compose 'T' 'H' to 'Þ'
+compose 't' 'h' to 'þ'
+compose 's' 's' to 'ß'
+compose '"' 'y' to 'ÿ'
+compose 's' 'z' to 'ß'
+compose 'i' 'j' to 'ÿ'
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
--- v2.1.50/linux/drivers/macintosh/macserial.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/macserial.c	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,1923 @@
+/*
+ * macserial.c: Serial port driver for Power Macintoshes.
+ *
+ * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+
+#include "macserial.h"
+
+/*
+ * It would be nice to dynamically allocate everything that
+ * depends on NUM_SERIAL, so we could support any number of
+ * Z8530s, but for now...
+ */
+#define NUM_SERIAL	2		/* Max number of ZS chips supported */
+#define NUM_CHANNELS	(NUM_SERIAL * 2)	/* 2 channels per chip */
+
+/* On PowerMacs, the hardware takes care of the SCC recovery time,
+   but we need the eieio to make sure that the accesses occur
+   in the order we want. */
+#define RECOVERY_DELAY	eieio()
+
+struct mac_zschannel *zs_kgdbchan;
+struct mac_zschannel zs_channels[NUM_CHANNELS];
+
+struct mac_serial zs_soft[NUM_CHANNELS];
+int zs_channels_found;
+struct mac_serial *zs_chain;	/* list of all channels */
+
+struct tty_struct zs_ttys[NUM_CHANNELS];
+/** struct tty_struct *zs_constty; **/
+
+/* Console hooks... */
+static int zs_cons_chan = 0;
+struct mac_serial *zs_consinfo = 0;
+struct mac_zschannel *zs_conschan;
+
+/*
+ * Initialization values for when a channel is used for
+ * kernel gdb support.
+ */
+static unsigned char kgdb_regs[16] = {
+	0, 0, 0,		/* write 0, 1, 2 */
+	(Rx8 | RxENABLE),	/* write 3 */
+	(X16CLK | SB1),		/* write 4 */
+	(Tx8 | TxENAB | RTS),	/* write 5 */
+	0, 0, 0,		/* write 6, 7, 8 */
+	(NV),			/* write 9 */
+	(NRZ),			/* write 10 */
+	(TCBR | RCBR),		/* write 11 */
+	1, 0,			/* 38400 baud divisor, write 12 + 13 */
+	(BRENABL),		/* write 14 */
+	(DCDIE)			/* write 15 */
+};
+
+#define ZS_CLOCK         3686400 	/* Z8530 RTxC input clock rate */
+
+DECLARE_TASK_QUEUE(tq_serial);
+
+struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* serial subtype definitions */
+#define SERIAL_TYPE_NORMAL	1
+#define SERIAL_TYPE_CALLOUT	2
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/* Debugging... DEBUG_INTR is bad to use when one of the zs
+ * lines is your console ;(
+ */
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+
+#define RS_STROBE_TIME 10
+#define RS_ISR_PASS_LIMIT 256
+
+#define _INLINE_ inline
+
+static void probe_sccs(void);
+static void change_speed(struct mac_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];
+
+#ifndef MIN
+#define MIN(a,b)	((a) < (b) ? (a) : (b))
+#endif
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the copy_from_user blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char tmp_buf[4096]; /* This is cheating */
+static struct semaphore tmp_buf_sem = MUTEX;
+
+static inline int serial_paranoia_check(struct mac_serial *info,
+					dev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+	static const char *badmagic =
+		"Warning: bad magic number for serial struct (%d, %d) in %s\n";
+	static const char *badinfo =
+		"Warning: null mac_serial for (%d, %d) in %s\n";
+
+	if (!info) {
+		printk(badinfo, MAJOR(device), MINOR(device), routine);
+		return 1;
+	}
+	if (info->magic != SERIAL_MAGIC) {
+		printk(badmagic, MAJOR(device), MINOR(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts
+ */
+static int baud_table[] = {
+	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+	9600, 19200, 38400, 57600, 115200, 230400, 0 };
+
+/* 
+ * Reading and writing Z8530 registers.
+ */
+static inline unsigned char read_zsreg(struct mac_zschannel *channel,
+				       unsigned char reg)
+{
+	unsigned char retval;
+
+	if (reg != 0) {
+		*channel->control = reg;
+		RECOVERY_DELAY;
+	}
+	retval = *channel->control;
+	RECOVERY_DELAY;
+	return retval;
+}
+
+static inline void write_zsreg(struct mac_zschannel *channel,
+			       unsigned char reg, unsigned char value)
+{
+	if (reg != 0) {
+		*channel->control = reg;
+		RECOVERY_DELAY;
+	}
+	*channel->control = value;
+	RECOVERY_DELAY;
+	return;
+}
+
+static inline unsigned char read_zsdata(struct mac_zschannel *channel)
+{
+	unsigned char retval;
+
+	retval = *channel->data;
+	RECOVERY_DELAY;
+	return retval;
+}
+
+static inline void write_zsdata(struct mac_zschannel *channel,
+				unsigned char value)
+{
+	*channel->data = value;
+	RECOVERY_DELAY;
+	return;
+}
+
+static inline void load_zsregs(struct mac_zschannel *channel,
+			       unsigned char *regs)
+{
+	ZS_CLEARERR(channel);
+	ZS_CLEARFIFO(channel);
+	/* Load 'em up */
+	write_zsreg(channel, R4, regs[R4]);
+	write_zsreg(channel, R10, regs[R10]);
+	write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
+	write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+	write_zsreg(channel, R1, regs[R1]);
+	write_zsreg(channel, R9, regs[R9]);
+	write_zsreg(channel, R11, regs[R11]);
+	write_zsreg(channel, R12, regs[R12]);
+	write_zsreg(channel, R13, regs[R13]);
+	write_zsreg(channel, R14, regs[R14]);
+	write_zsreg(channel, R15, regs[R15]);
+	write_zsreg(channel, R3, regs[R3]);
+	write_zsreg(channel, R5, regs[R5]);
+	return;
+}
+
+/* Sets or clears DTR/RTS on the requested line */
+static inline void zs_rtsdtr(struct mac_serial *ss, int set)
+{
+	if (set)
+		ss->curregs[5] |= (RTS | DTR);
+	else
+		ss->curregs[5] &= ~(RTS | DTR);
+	write_zsreg(ss->zs_channel, 5, ss->curregs[5]);
+	return;
+}
+
+static inline void kgdb_chaninit(struct mac_serial *ss, int intson, int bps)
+{
+	int brg;
+
+	if (intson) {
+		kgdb_regs[R1] = INT_ALL_Rx;
+		kgdb_regs[R9] |= MIE;
+	} else {
+		kgdb_regs[R1] = 0;
+		kgdb_regs[R9] &= ~MIE;
+	}
+	brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
+	kgdb_regs[R12] = brg;
+	kgdb_regs[R13] = brg >> 8;
+	load_zsregs(ss->zs_channel, kgdb_regs);
+}
+
+/* Utility routines for the Zilog */
+static inline int get_zsbaud(struct mac_serial *ss)
+{
+	struct mac_zschannel *channel = ss->zs_channel;
+	int brg;
+
+	if ((ss->curregs[R11] & TCBR) == 0) {
+		/* higher rates don't use the baud rate generator */
+		return (ss->curregs[R4] & X32CLK)? ZS_CLOCK/32: ZS_CLOCK/16;
+	}
+	/* 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) << 8);
+	brg |= read_zsreg(channel, 12);
+	return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor)));
+}
+
+/* On receive, this clears errors and the receiver interrupts */
+static inline void rs_recv_clear(struct mac_zschannel *zsc)
+{
+	write_zsreg(zsc, 0, ERR_RES);
+	write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static _INLINE_ void rs_sched_event(struct mac_serial *info,
+				  int event)
+{
+	info->event |= 1 << event;
+	queue_task(&info->tqueue, &tq_serial);
+	mark_bh(SERIAL_BH);
+}
+
+extern void breakpoint(void);  /* For the KGDB frame character */
+
+static _INLINE_ void receive_chars(struct mac_serial *info,
+				   struct pt_regs *regs)
+{
+	struct tty_struct *tty = info->tty;
+	unsigned char ch, stat, flag;
+
+	while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) != 0) {
+
+		stat = read_zsreg(info->zs_channel, R1);
+		ch = read_zsdata(info->zs_channel);
+
+#if 0	/* KGDB not yet supported */
+		/* Look for kgdb 'stop' character, consult the gdb documentation
+		 * for remote target debugging and arch/sparc/kernel/sparc-stub.c
+		 * to see how all this works.
+		 */
+		if ((info->kgdb_channel) && (ch =='\003')) {
+			breakpoint();
+			continue;
+		}
+#endif
+
+		if (!tty)
+			continue;
+		queue_task(&tty->flip.tqueue, &tq_timer);
+
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+			static int flip_buf_ovf;
+			++flip_buf_ovf;
+			continue;
+		}
+		tty->flip.count++;
+		{
+			static int flip_max_cnt;
+			if (flip_max_cnt < tty->flip.count)
+				flip_max_cnt = tty->flip.count;
+		}
+		if (stat & Rx_OVR) {
+			flag = TTY_OVERRUN;
+			/* reset the error indication */
+			write_zsreg(info->zs_channel, 0, ERR_RES);
+		} else if (stat & FRM_ERR) {
+			/* this error is not sticky */
+			flag = TTY_FRAME;
+		} else if (stat & PAR_ERR) {
+			flag = TTY_PARITY;
+			/* reset the error indication */
+			write_zsreg(info->zs_channel, 0, ERR_RES);
+		} else
+			flag = 0;
+		*tty->flip.flag_buf_ptr++ = flag;
+		*tty->flip.char_buf_ptr++ = ch;
+	}
+}
+
+static void transmit_chars(struct mac_serial *info)
+{
+	if ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0)
+		return;
+	info->tx_active = 0;
+
+	if (info->x_char) {
+		/* Send next char */
+		write_zsdata(info->zs_channel, info->x_char);
+		info->x_char = 0;
+		info->tx_active = 1;
+		return;
+	}
+
+	if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped) {
+		write_zsreg(info->zs_channel, 0, RES_Tx_P);
+		return;
+	}
+
+	/* Send char */
+	write_zsdata(info->zs_channel, info->xmit_buf[info->xmit_tail++]);
+	info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+	info->xmit_cnt--;
+	info->tx_active = 1;
+
+	if (info->xmit_cnt < WAKEUP_CHARS)
+		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+}
+
+static _INLINE_ void status_handle(struct mac_serial *info)
+{
+	unsigned char status;
+
+	/* Get status from Read Register 0 */
+	status = read_zsreg(info->zs_channel, 0);
+
+	/* Check for DCD transitions */
+	if (((status ^ info->read_reg_zero) & DCD) != 0
+	    && info->tty && !C_CLOCAL(info->tty)) {
+		if (status & DCD) {
+			wake_up_interruptible(&info->open_wait);
+		} else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) {
+			queue_task(&info->tqueue_hangup, &tq_scheduler);
+		}
+	}
+
+	/* Check for CTS transitions */
+	if (info->tty && C_CRTSCTS(info->tty)) {
+		/*
+		 * For some reason, on the Power Macintosh,
+		 * it seems that the CTS bit is 1 when CTS is
+		 * *negated* and 0 when it is asserted.
+		 * The DCD bit doesn't seem to be inverted
+		 * like this.
+		 */
+		if ((status & CTS) == 0) {
+			if (info->tx_stopped) {
+				info->tx_stopped = 0;
+				if (!info->tx_active)
+					transmit_chars(info);
+			}
+		} else {
+			info->tx_stopped = 1;
+		}
+	}
+
+	/* Clear status condition... */
+	write_zsreg(info->zs_channel, 0, RES_EXT_INT);
+	info->read_reg_zero = status;
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct mac_serial *info = (struct mac_serial *) dev_id;
+	unsigned char zs_intreg;
+	int shift;
+
+	/* 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_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
+
+	if (info->zs_chan_a == info->zs_channel)
+		shift = 3;	/* Channel A */
+	else
+		shift = 0;	/* Channel B */
+
+	for (;;) {
+		zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift;
+		if ((zs_intreg & CHAN_IRQMASK) == 0)
+			break;
+
+		if (zs_intreg & CHBRxIP)
+			receive_chars(info, regs);
+		if (zs_intreg & CHBTxIP)
+			transmit_chars(info);
+		if (zs_intreg & CHBEXT)
+			status_handle(info);
+	}
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * ------------------------------------------------------------
+ */
+static void rs_stop(struct tty_struct *tty)
+{
+	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+
+	if (serial_paranoia_check(info, tty->device, "rs_stop"))
+		return;
+	
+#if 0
+	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);
+#endif
+}
+
+static void rs_start(struct tty_struct *tty)
+{
+	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+	unsigned long flags;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_start"))
+		return;
+	
+	save_flags(flags); cli();
+#if 0
+	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]);
+	}
+#else
+	if (info->xmit_cnt && info->xmit_buf && !info->tx_active) {
+		transmit_chars(info);
+	}
+#endif
+	restore_flags(flags);
+}
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh(void)
+{
+	run_task_queue(&tq_serial);
+}
+
+static void do_softint(void *private_)
+{
+	struct mac_serial	*info = (struct mac_serial *) private_;
+	struct tty_struct	*tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+	}
+}
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred.  The path of
+ * hangup processing is:
+ *
+ * 	serial interrupt routine -> (scheduler tqueue) ->
+ * 	do_serial_hangup() -> tty->hangup() -> rs_hangup()
+ * 
+ */
+static void do_serial_hangup(void *private_)
+{
+	struct mac_serial	*info = (struct mac_serial *) private_;
+	struct tty_struct	*tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	tty_hangup(tty);
+}
+
+static void rs_timer(void)
+{
+}
+
+static int startup(struct mac_serial * info)
+{
+	unsigned long flags;
+
+	if (info->flags & ZILOG_INITIALIZED)
+		return 0;
+
+	if (!info->xmit_buf) {
+		info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL);
+		if (!info->xmit_buf)
+			return -ENOMEM;
+	}
+
+	save_flags(flags); cli();
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("starting up ttyS%d (irq %d)...", info->line, info->irq);
+#endif
+
+	/*
+	 * Clear the receive FIFO.
+	 */
+	ZS_CLEARFIFO(info->zs_channel);
+	info->xmit_fifo_size = 1;
+
+	/*
+	 * Clear the interrupt registers.
+	 */
+	write_zsreg(info->zs_channel, 0, ERR_RES);
+	write_zsreg(info->zs_channel, 0, RES_H_IUS);
+
+	/*
+	 * Turn on RTS and DTR.
+	 */
+	zs_rtsdtr(info, 1);
+
+	/*
+	 * Finally, enable sequencing and interrupts
+	 */
+	info->curregs[1] = (info->curregs[1] & ~0x18) | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
+	info->pendregs[1] = info->curregs[1];
+	info->curregs[3] |= (RxENABLE | Rx8);
+	info->pendregs[3] = info->curregs[3];
+	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]);
+
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+	/*
+	 * Set the speed of the serial port
+	 */
+	change_speed(info);
+
+	/* Save the current value of RR0 */
+	info->read_reg_zero = read_zsreg(info->zs_channel, 0);
+
+	info->flags |= ZILOG_INITIALIZED;
+	restore_flags(flags);
+	return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct mac_serial * info)
+{
+	unsigned long	flags;
+
+	if (!(info->flags & ZILOG_INITIALIZED))
+		return;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("Shutting down serial port %d (irq %d)....", info->line,
+	       info->irq);
+#endif
+	
+	save_flags(flags); cli(); /* Disable interrupts */
+	
+	if (info->xmit_buf) {
+		free_page((unsigned long) info->xmit_buf);
+		info->xmit_buf = 0;
+	}
+
+	info->pendregs[1] = info->curregs[1] = 0;
+	write_zsreg(info->zs_channel, 1, 0);	/* no interrupts */
+
+	info->curregs[3] &= ~RxENABLE;
+	info->pendregs[3] = info->curregs[3];
+	write_zsreg(info->zs_channel, 3, info->curregs[3]);
+
+	info->curregs[5] &= ~TxENAB;
+	if (!info->tty || C_HUPCL(info->tty))
+		info->curregs[5] &= ~(DTR | RTS);
+	info->pendregs[5] = info->curregs[5];
+	write_zsreg(info->zs_channel, 5, info->curregs[5]);
+
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	info->flags &= ~ZILOG_INITIALIZED;
+	restore_flags(flags);
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(struct mac_serial *info)
+{
+	unsigned short port;
+	unsigned cflag;
+	int	i;
+	int	brg;
+	unsigned long flags;
+
+	if (!info->tty || !info->tty->termios)
+		return;
+	cflag = info->tty->termios->c_cflag;
+	if (!(port = info->port))
+		return;
+	i = cflag & CBAUD;
+
+	save_flags(flags); cli();
+	info->zs_baud = baud_table[i];
+	info->clk_divisor = 16;
+
+	switch (info->zs_baud) {
+	case ZS_CLOCK/16:	/* 230400 */
+		info->curregs[4] = X16CLK;
+		info->curregs[11] = 0;
+		break;
+	case ZS_CLOCK/32:	/* 115200 */
+		info->curregs[4] = X32CLK;
+		info->curregs[11] = 0;
+		break;
+	default:
+		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] = BRENABL;
+	}
+
+	/* byte size and parity */
+	info->curregs[3] &= ~RxNBITS_MASK;
+	info->curregs[5] &= ~TxNBITS_MASK;
+	switch (cflag & CSIZE) {
+	case CS5:
+		info->curregs[3] |= Rx5;
+		info->curregs[5] |= Tx5;
+		break;
+	case CS6:
+		info->curregs[3] |= Rx6;
+		info->curregs[5] |= Tx6;
+		break;
+	case CS7:
+		info->curregs[3] |= Rx7;
+		info->curregs[5] |= Tx7;
+		break;
+	case CS8:
+	default: /* defaults to 8 bits */
+		info->curregs[3] |= Rx8;
+		info->curregs[5] |= Tx8;
+		break;
+	}
+	info->pendregs[3] = info->curregs[3];
+	info->pendregs[5] = info->curregs[5];
+
+	info->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
+	if (cflag & CSTOPB) {
+		info->curregs[4] |= SB2;
+	} else {
+		info->curregs[4] |= SB1;
+	}
+	if (cflag & PARENB) {
+		info->curregs[4] |= PAR_ENA;
+	}
+	if (!(cflag & PARODD)) {
+		info->curregs[4] |= PAR_EVEN;
+	}
+	info->pendregs[4] = info->curregs[4];
+
+	if (!(cflag & CLOCAL)) {
+		if (!(info->curregs[15] & DCDIE))
+			info->read_reg_zero = read_zsreg(info->zs_channel, 0);
+		info->curregs[15] |= DCDIE;
+	} else
+		info->curregs[15] &= ~DCDIE;
+	if (cflag & CRTSCTS) {
+		info->curregs[15] |= CTSIE;
+		if ((read_zsreg(info->zs_channel, 0) & CTS) != 0)
+			info->tx_stopped = 1;
+	} else {
+		info->curregs[15] &= ~CTSIE;
+		info->tx_stopped = 0;
+	}
+	info->pendregs[15] = info->curregs[15];
+
+	/* Load up the new values */
+	load_zsregs(info->zs_channel, info->curregs);
+
+	restore_flags(flags);
+}
+
+/* This is for console output over ttya/ttyb */
+static void rs_put_char(char ch)
+{
+	struct mac_zschannel *chan = zs_conschan;
+	int loops = 0;
+	unsigned long flags;
+
+	if(!chan)
+		return;
+
+	save_flags(flags); cli();
+	while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
+		if (++loops >= 1000000)
+			break;
+	write_zsdata(chan, ch);
+	restore_flags(flags);
+}
+
+/* These are for receiving and sending characters under the kgdb
+ * source level kernel debugger.
+ */
+void putDebugChar(char kgdb_char)
+{
+	struct mac_zschannel *chan = zs_kgdbchan;
+
+	while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
+		udelay(5);
+	write_zsdata(chan, kgdb_char);
+}
+
+char getDebugChar(void)
+{
+	struct mac_zschannel *chan = zs_kgdbchan;
+
+	while ((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
+		udelay(5);
+	return read_zsdata(chan);
+}
+
+/*
+ * Fair output driver allows a process to speak.
+ */
+static void rs_fair_output(void)
+{
+	int left;		/* Output no more than that */
+	unsigned long flags;
+	struct mac_serial *info = zs_consinfo;
+	char c;
+
+	if (info == 0) return;
+	if (info->xmit_buf == 0) return;
+
+	save_flags(flags);  cli();
+	left = info->xmit_cnt;
+	while (left != 0) {
+		c = info->xmit_buf[info->xmit_tail];
+		info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
+		info->xmit_cnt--;
+		restore_flags(flags);
+
+		rs_put_char(c);
+
+		save_flags(flags);  cli();
+		left = MIN(info->xmit_cnt, left-1);
+	}
+
+	restore_flags(flags);
+	return;
+}
+
+/*
+ * zs_console_print is registered for printk.
+ */
+static void zs_console_print(const char *p)
+{
+	char c;
+
+	while ((c = *(p++)) != 0) {
+		if (c == '\n')
+			rs_put_char('\r');
+		rs_put_char(c);
+	}
+
+	/* Comment this if you want to have a strict interrupt-driven output */
+	rs_fair_output();
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+		return;
+
+	if (info->xmit_cnt <= 0 || tty->stopped || info->tx_stopped ||
+	    !info->xmit_buf)
+		return;
+
+	/* Enable transmitter */
+	save_flags(flags); cli();
+	transmit_chars(info);
+	restore_flags(flags);
+}
+
+static int rs_write(struct tty_struct * tty, int from_user,
+		    const unsigned char *buf, int count)
+{
+	int	c, total = 0;
+	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_write"))
+		return 0;
+
+	if (!tty || !info->xmit_buf)
+		return 0;
+
+	save_flags(flags);
+	while (1) {
+		cli();		
+		c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				   SERIAL_XMIT_SIZE - info->xmit_head));
+		if (c <= 0)
+			break;
+
+		if (from_user) {
+			down(&tmp_buf_sem);
+			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);
+			up(&tmp_buf_sem);
+		} else
+			memcpy(info->xmit_buf + info->xmit_head, buf, c);
+		info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+		info->xmit_cnt += c;
+		restore_flags(flags);
+		buf += c;
+		count -= c;
+		total += c;
+	}
+	if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
+	    && !info->tx_active)
+		transmit_chars(info);
+	restore_flags(flags);
+	return total;
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+	int	ret;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+		return 0;
+	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+	if (ret < 0)
+		ret = 0;
+	return ret;
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+		return 0;
+	return info->xmit_cnt;
+}
+
+static void rs_flush_buffer(struct tty_struct *tty)
+{
+	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+		return;
+	cli();
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+	sti();
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_throttle(struct tty_struct * tty)
+{
+	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+	unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("throttle %s: %d....\n", _tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+		return;
+	
+	if (I_IXOFF(tty)) {
+		save_flags(flags); cli();
+		info->x_char = STOP_CHAR(tty);
+		if (!info->tx_active)
+			transmit_chars(info);
+		restore_flags(flags);
+	}
+
+	if (C_CRTSCTS(tty)) {
+		/*
+		 * Here we want to turn off the RTS line.  On Macintoshes,
+		 * we only get the DTR line, which goes to both DTR and
+		 * RTS on the modem.  RTS doesn't go out to the serial
+		 * port socket.  So you should make sure your modem is
+		 * set to ignore DTR if you're using CRTSCTS.
+		 */
+		save_flags(flags); cli();
+		info->curregs[5] &= ~(DTR | RTS);
+		info->pendregs[5] &= ~(DTR | RTS);
+		write_zsreg(info->zs_channel, 5, info->curregs[5]);
+		restore_flags(flags);
+	}
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+	unsigned long flags;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+		return;
+	
+	if (I_IXOFF(tty)) {
+		save_flags(flags); cli();
+		if (info->x_char)
+			info->x_char = 0;
+		else {
+			info->x_char = START_CHAR(tty);
+			if (!info->tx_active)
+				transmit_chars(info);
+		}
+		restore_flags(flags);
+	}
+
+	if (C_CRTSCTS(tty)) {
+		/* Assert RTS and DTR lines */
+		save_flags(flags); cli();
+		info->curregs[5] |= DTR | RTS;
+		info->pendregs[5] |= DTR | RTS;
+		write_zsreg(info->zs_channel, 5, info->curregs[5]);
+		restore_flags(flags);
+	}
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct mac_serial * info,
+			   struct serial_struct * retinfo)
+{
+	struct serial_struct tmp;
+  
+	if (!retinfo)
+		return -EFAULT;
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.type = info->type;
+	tmp.line = info->line;
+	tmp.port = info->port;
+	tmp.irq = info->irq;
+	tmp.flags = info->flags;
+	tmp.baud_base = info->baud_base;
+	tmp.close_delay = info->close_delay;
+	tmp.closing_wait = info->closing_wait;
+	tmp.custom_divisor = info->custom_divisor;
+	return copy_to_user(retinfo,&tmp,sizeof(*retinfo));
+}
+
+static int set_serial_info(struct mac_serial * info,
+			   struct serial_struct * new_info)
+{
+	struct serial_struct new_serial;
+	struct mac_serial old_info;
+	int 			retval = 0;
+
+	if (!new_info)
+		return -EFAULT;
+	copy_from_user(&new_serial,new_info,sizeof(new_serial));
+	old_info = *info;
+
+	if (!suser()) {
+		if ((new_serial.baud_base != info->baud_base) ||
+		    (new_serial.type != info->type) ||
+		    (new_serial.close_delay != info->close_delay) ||
+		    ((new_serial.flags & ~ZILOG_USR_MASK) !=
+		     (info->flags & ~ZILOG_USR_MASK)))
+			return -EPERM;
+		info->flags = ((info->flags & ~ZILOG_USR_MASK) |
+			       (new_serial.flags & ZILOG_USR_MASK));
+		info->custom_divisor = new_serial.custom_divisor;
+		goto check_and_exit;
+	}
+
+	if (info->count > 1)
+		return -EBUSY;
+
+	/*
+	 * OK, past this point, all the error checking has been done.
+	 * At this point, we start making changes.....
+	 */
+
+	info->baud_base = new_serial.baud_base;
+	info->flags = ((info->flags & ~ZILOG_FLAGS) |
+			(new_serial.flags & ZILOG_FLAGS));
+	info->type = new_serial.type;
+	info->close_delay = new_serial.close_delay;
+	info->closing_wait = new_serial.closing_wait;
+
+check_and_exit:
+	retval = startup(info);
+	return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * 	    is emptied.  On bus types like RS485, the transmitter must
+ * 	    release the bus after transmitting. This must be done when
+ * 	    the transmit shift register is empty, not be done when the
+ * 	    transmit holding register is empty.  This functionality
+ * 	    allows an RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct mac_serial * info, unsigned int *value)
+{
+	unsigned char status;
+
+	cli();
+	status = read_zsreg(info->zs_channel, 0);
+	sti();
+	put_user(status,value);
+	return 0;
+}
+
+static int get_modem_info(struct mac_serial *info, unsigned int *value)
+{
+	unsigned char control, status;
+	unsigned int result;
+
+	cli();
+	control = info->curregs[5];
+	status = read_zsreg(info->zs_channel, 0);
+	sti();
+	result =  ((control & RTS) ? TIOCM_RTS: 0)
+		| ((control & DTR) ? TIOCM_DTR: 0)
+		| ((status  & DCD) ? TIOCM_CAR: 0)
+		| ((status  & CTS) ? 0: TIOCM_CTS);
+	put_user(result,value);
+	return 0;
+}
+
+static int set_modem_info(struct mac_serial *info, unsigned int cmd,
+			  unsigned int *value)
+{
+	int error;
+	unsigned int arg, bits;
+
+	error = verify_area(VERIFY_READ, value, sizeof(int));
+	if (error)
+		return error;
+	get_user(arg, value);
+	bits = (arg & TIOCM_RTS? RTS: 0) + (arg & TIOCM_DTR? DTR: 0);
+	cli();
+	switch (cmd) {
+	case TIOCMBIS:
+		info->curregs[5] |= bits;
+		break;
+	case TIOCMBIC:
+		info->curregs[5] &= ~bits;
+		break;
+	case TIOCMSET:
+		info->curregs[5] = (info->curregs[5] & ~(DTR | RTS)) | bits;
+		break;
+	default:
+		sti();
+		return -EINVAL;
+	}
+	info->pendregs[5] = info->curregs[5];
+	write_zsreg(info->zs_channel, 5, info->curregs[5]);
+	sti();
+	return 0;
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void send_break(	struct mac_serial * info, int duration)
+{
+	if (!info->port)
+		return;
+	current->state = TASK_INTERRUPTIBLE;
+	current->timeout = jiffies + duration;
+	cli();
+	info->curregs[5] |= SND_BRK;
+	write_zsreg(info->zs_channel, 5, info->curregs[5]);
+	schedule();
+	info->curregs[5] &= ~SND_BRK;
+	write_zsreg(info->zs_channel, 5, info->curregs[5]);
+	sti();
+}
+
+static int rs_ioctl(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg)
+{
+	int error;
+	struct mac_serial * info = (struct mac_serial *)tty->driver_data;
+	int retval;
+
+	if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+		return -ENODEV;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
+	    (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+		    return -EIO;
+	}
+	
+	switch (cmd) {
+		case TCSBRK:	/* SVID version: non-zero arg --> no break */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			if (!arg)
+				send_break(info, HZ/4);	/* 1/4 second */
+			return 0;
+		case TCSBRKP:	/* support for POSIX tcsendbreak() */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			send_break(info, arg ? arg*(HZ/10) : HZ/4);
+			return 0;
+		case TIOCGSOFTCAR:
+			return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg);
+		case TIOCSSOFTCAR:
+			error = get_user(arg, (int *) arg);
+			if (error)
+				return error;
+			tty->termios->c_cflag =
+				((tty->termios->c_cflag & ~CLOCAL) |
+				 (arg ? CLOCAL : 0));
+			return 0;
+		case TIOCMGET:
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+				sizeof(unsigned int));
+			if (error)
+				return error;
+			return get_modem_info(info, (unsigned int *) arg);
+		case TIOCMBIS:
+		case TIOCMBIC:
+		case TIOCMSET:
+			return set_modem_info(info, cmd, (unsigned int *) arg);
+		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);
+
+		case TIOCSERGSTRUCT:
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+						sizeof(struct mac_serial));
+			if (error)
+				return error;
+			copy_from_user((struct mac_serial *) arg,
+				       info, sizeof(struct mac_serial));
+			return 0;
+			
+		default:
+			return -ENOIOCTLCMD;
+		}
+	return 0;
+}
+
+static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	struct mac_serial *info = (struct mac_serial *)tty->driver_data;
+	int was_stopped;
+
+	if (tty->termios->c_cflag == old_termios->c_cflag)
+		return;
+	was_stopped = info->tx_stopped;
+
+	change_speed(info);
+
+	if (was_stopped && !info->tx_stopped)
+		rs_start(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ * 
+ * This routine is called when the serial port gets closed.
+ * Wait for the last remaining data to be sent.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+	struct mac_serial * info = (struct mac_serial *)tty->driver_data;
+	unsigned long flags;
+	unsigned long timeout;
+
+	if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+		return;
+	
+	save_flags(flags); cli();
+	
+	if (tty_hung_up_p(filp)) {
+		restore_flags(flags);
+		return;
+	}
+	
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_close ttys%d, count = %d\n", info->line, info->count);
+#endif
+	if ((tty->count == 1) && (info->count != 1)) {
+		/*
+		 * Uh, oh.  tty->count is 1, which means that the tty
+		 * structure will be freed.  Info->count should always
+		 * be one in these conditions.  If it's greater than
+		 * one, we've got real problems, since it means the
+		 * serial port won't be shutdown.
+		 */
+		printk("rs_close: bad serial port count; tty->count is 1, "
+		       "info->count is %d\n", info->count);
+		info->count = 1;
+	}
+	if (--info->count < 0) {
+		printk("rs_close: bad serial port count for ttys%d: %d\n",
+		       info->line, info->count);
+		info->count = 0;
+	}
+	if (info->count) {
+		restore_flags(flags);
+		return;
+	}
+	info->flags |= ZILOG_CLOSING;
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ZILOG_NORMAL_ACTIVE)
+		info->normal_termios = *tty->termios;
+	if (info->flags & ZILOG_CALLOUT_ACTIVE)
+		info->callout_termios = *tty->termios;
+	/*
+	 * Now we wait for the transmit buffer to clear; and we notify 
+	 * the line discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->closing_wait);
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receiver and receive interrupts.
+	 */
+	/** if (!info->iscons) ... **/
+	info->curregs[3] &= ~RxENABLE;
+	info->pendregs[3] = info->curregs[3];
+	write_zsreg(info->zs_channel, 3, info->curregs[3]);
+	info->curregs[1] &= ~(0x18);	/* disable any rx ints */
+	info->pendregs[1] = info->curregs[1];
+	write_zsreg(info->zs_channel, 1, info->curregs[1]);
+	ZS_CLEARFIFO(info->zs_channel);
+	if (info->flags & ZILOG_INITIALIZED) {
+		/*
+		 * Before we drop DTR, make sure the SCC transmitter
+		 * has completely drained.
+		 */
+		timeout = jiffies+HZ;
+		while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + info->timeout;
+			schedule();
+			if (jiffies > timeout)
+				break;
+		}
+	}
+
+	shutdown(info);
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	if (tty->ldisc.num != ldiscs[N_TTY].num) {
+		if (tty->ldisc.close)
+			(tty->ldisc.close)(tty);
+		tty->ldisc = ldiscs[N_TTY];
+		tty->termios->c_line = N_TTY;
+		if (tty->ldisc.open)
+			(tty->ldisc.open)(tty);
+	}
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			current->state = TASK_INTERRUPTIBLE;
+			current->timeout = jiffies + info->close_delay;
+			schedule();
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
+			 ZILOG_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	restore_flags(flags);
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+void rs_hangup(struct tty_struct *tty)
+{
+	struct mac_serial * info = (struct mac_serial *)tty->driver_data;
+
+	if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+		return;
+
+	rs_flush_buffer(tty);
+	shutdown(info);
+	info->event = 0;
+	info->count = 0;
+	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE);
+	info->tty = 0;
+	wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+			   struct mac_serial *info)
+{
+	struct wait_queue wait = { current, NULL };
+	int		retval;
+	int		do_clocal = 0;
+
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (info->flags & ZILOG_CLOSING) {
+		interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		if (info->flags & ZILOG_HUP_NOTIFY)
+			return -EAGAIN;
+		else
+			return -ERESTARTSYS;
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * If this is a callout device, then just make sure the normal
+	 * device isn't being used.
+	 */
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		if (info->flags & ZILOG_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
+		    (info->flags & ZILOG_SESSION_LOCKOUT) &&
+		    (info->session != current->session))
+		    return -EBUSY;
+		if ((info->flags & ZILOG_CALLOUT_ACTIVE) &&
+		    (info->flags & ZILOG_PGRP_LOCKOUT) &&
+		    (info->pgrp != current->pgrp))
+		    return -EBUSY;
+		info->flags |= ZILOG_CALLOUT_ACTIVE;
+		return 0;
+	}
+	
+	/*
+	 * If non-blocking mode is set, or the port is not enabled,
+	 * then make the check up front and then exit.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+	    (tty->flags & (1 << TTY_IO_ERROR))) {
+		if (info->flags & ZILOG_CALLOUT_ACTIVE)
+			return -EBUSY;
+		info->flags |= ZILOG_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (info->flags & ZILOG_CALLOUT_ACTIVE) {
+		if (info->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	} else {
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+	
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, info->count is dropped by one, so that
+	 * rs_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	retval = 0;
+	add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready before block: ttys%d, count = %d\n",
+	       info->line, info->count);
+#endif
+	cli();
+	if (!tty_hung_up_p(filp)) 
+		info->count--;
+	sti();
+	info->blocked_open++;
+	while (1) {
+		cli();
+		if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
+		    (tty->termios->c_cflag & CBAUD))
+			zs_rtsdtr(info, 1);
+		sti();
+		current->state = TASK_INTERRUPTIBLE;
+		if (tty_hung_up_p(filp) ||
+		    !(info->flags & ZILOG_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+			if (info->flags & ZILOG_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;	
+#else
+			retval = -EAGAIN;
+#endif
+			break;
+		}
+		if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
+		    !(info->flags & ZILOG_CLOSING) &&
+		    (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD)))
+			break;
+		if (current->signal & ~current->blocked) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+#ifdef SERIAL_DEBUG_OPEN
+		printk("block_til_ready blocking: ttys%d, count = %d\n",
+		       info->line, info->count);
+#endif
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&info->open_wait, &wait);
+	if (!tty_hung_up_p(filp))
+		info->count++;
+	info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready after blocking: ttys%d, count = %d\n",
+	       info->line, info->count);
+#endif
+	if (retval)
+		return retval;
+	info->flags |= ZILOG_NORMAL_ACTIVE;
+	return 0;
+}	
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its ZILOG structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+int rs_open(struct tty_struct *tty, struct file * filp)
+{
+	struct mac_serial	*info;
+	int 			retval, line;
+
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= zs_channels_found))
+		return -ENODEV;
+	info = zs_soft + line;
+
+	/* Is the kgdb running over this line? */
+	if (info->kgdb_channel)
+		return -ENODEV;
+	if (serial_paranoia_check(info, tty->device, "rs_open"))
+		return -ENODEV;
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+	       info->count);
+#endif
+
+	info->count++;
+	tty->driver_data = info;
+	info->tty = tty;
+
+	/*
+	 * Start up serial port
+	 */
+	retval = startup(info);
+	if (retval)
+		return retval;
+
+	retval = block_til_ready(tty, filp, info);
+	if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+		printk("rs_open returning after block_til_ready with %d\n",
+		       retval);
+#endif
+		return retval;
+	}
+
+	if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = info->normal_termios;
+		else 
+			*tty->termios = info->callout_termios;
+		change_speed(info);
+	}
+
+	info->session = current->session;
+	info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_open ttys%d successful...", info->line);
+#endif
+	return 0;
+}
+
+/* Finally, routines used to initialize the serial driver. */
+
+static void show_serial_version(void)
+{
+	printk("PowerMac Z8530 serial driver version 1.00\n");
+}
+
+/* Ask the PROM how many Z8530s we have and initialize their zs_channels */
+static void
+probe_sccs()
+{
+	struct device_node *dev, *ch;
+	struct mac_serial **pp;
+	int n;
+
+	n = 0;
+	pp = &zs_chain;
+	for (dev = find_devices("escc"); dev != 0; dev = dev->next) {
+		if (n >= NUM_CHANNELS) {
+			printk("Sorry, can't use %s: no more channels\n",
+			       dev->full_name);
+			continue;
+		}
+		for (ch = dev->child; ch != 0; ch = ch->sibling) {
+			if (ch->n_addrs < 1 || ch ->n_intrs < 1) {
+				printk("Can't use %s: %d addrs %d intrs\n",
+				      ch->full_name, ch->n_addrs, ch->n_intrs);
+				continue;
+			}
+			zs_channels[n].control = (volatile unsigned char *)
+				ch->addrs[0].address;
+			zs_channels[n].data = zs_channels[n].control
+				+ ch->addrs[0].size / 2;
+			zs_soft[n].zs_channel = &zs_channels[n];
+			zs_soft[n].irq = ch->intrs[0];
+			if (request_irq(ch->intrs[0], rs_interrupt, 0,
+					"SCC", &zs_soft[n]))
+				panic("macserial: can't get irq %d",
+				      ch->intrs[0]);
+			/* XXX this assumes the prom puts chan A before B */
+			if (n & 1)
+				zs_soft[n].zs_chan_a = &zs_channels[n-1];
+			else
+				zs_soft[n].zs_chan_a = &zs_channels[n];
+
+			*pp = &zs_soft[n];
+			pp = &zs_soft[n].zs_next;
+			++n;
+		}
+	}
+	*pp = 0;
+	zs_channels_found = n;
+}
+
+/* rs_init inits the driver */
+int rs_init(void)
+{
+	int channel, i;
+	unsigned long flags;
+	struct mac_serial *info;
+
+	/* Setup base handler, and timer table. */
+	init_bh(SERIAL_BH, do_serial_bh);
+	timer_table[RS_TIMER].fn = rs_timer;
+	timer_table[RS_TIMER].expires = 0;
+
+	/* Find out how many Z8530 SCCs we have */
+	if (zs_chain == 0)
+		probe_sccs();
+
+	show_serial_version();
+
+	/* Initialize the tty_driver structure */
+	/* Not all of this is exactly right for us. */
+
+	memset(&serial_driver, 0, sizeof(struct tty_driver));
+	serial_driver.magic = TTY_DRIVER_MAGIC;
+	serial_driver.name = "ttyS";
+	serial_driver.major = TTY_MAJOR;
+	serial_driver.minor_start = 64;
+	serial_driver.num = zs_channels_found;
+	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	serial_driver.subtype = SERIAL_TYPE_NORMAL;
+	serial_driver.init_termios = tty_std_termios;
+
+	serial_driver.init_termios.c_cflag =
+		B38400 | CS8 | CREAD | HUPCL | CLOCAL;
+	serial_driver.flags = TTY_DRIVER_REAL_RAW;
+	serial_driver.refcount = &serial_refcount;
+	serial_driver.table = serial_table;
+	serial_driver.termios = serial_termios;
+	serial_driver.termios_locked = serial_termios_locked;
+
+	serial_driver.open = rs_open;
+	serial_driver.close = rs_close;
+	serial_driver.write = rs_write;
+	serial_driver.flush_chars = rs_flush_chars;
+	serial_driver.write_room = rs_write_room;
+	serial_driver.chars_in_buffer = rs_chars_in_buffer;
+	serial_driver.flush_buffer = rs_flush_buffer;
+	serial_driver.ioctl = rs_ioctl;
+	serial_driver.throttle = rs_throttle;
+	serial_driver.unthrottle = rs_unthrottle;
+	serial_driver.set_termios = rs_set_termios;
+	serial_driver.stop = rs_stop;
+	serial_driver.start = rs_start;
+	serial_driver.hangup = rs_hangup;
+
+	/*
+	 * The callout device is just like normal device except for
+	 * major number and the subtype code.
+	 */
+	callout_driver = serial_driver;
+	callout_driver.name = "cua";
+	callout_driver.major = TTYAUX_MAJOR;
+	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+	if (tty_register_driver(&serial_driver))
+		panic("Couldn't register serial driver\n");
+	if (tty_register_driver(&callout_driver))
+		panic("Couldn't register callout driver\n");
+
+	save_flags(flags); cli();
+
+	for (channel = 0; channel < zs_channels_found; ++channel) {
+		zs_soft[channel].clk_divisor = 16;
+		zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+
+		/* If console serial line, then enable interrupts. */
+		if (zs_soft[channel].is_cons) {
+			write_zsreg(zs_soft[channel].zs_channel, R1,
+				    (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));
+			write_zsreg(zs_soft[channel].zs_channel, R9,
+				    (NV | MIE));
+		}
+		/* 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);
+	}
+
+	for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
+	{
+		info->magic = SERIAL_MAGIC;
+		info->port = (int) info->zs_channel->control;
+		info->line = i;
+		info->tty = 0;
+		info->custom_divisor = 16;
+		info->close_delay = 50;
+		info->closing_wait = 3000;
+		info->x_char = 0;
+		info->event = 0;
+		info->count = 0;
+		info->blocked_open = 0;
+		info->tqueue.routine = do_softint;
+		info->tqueue.data = info;
+		info->tqueue_hangup.routine = do_serial_hangup;
+		info->tqueue_hangup.data = info;
+		info->callout_termios =callout_driver.init_termios;
+		info->normal_termios = serial_driver.init_termios;
+		info->open_wait = 0;
+		info->close_wait = 0;
+		printk("tty%02d at 0x%08x (irq = %d)", info->line, 
+		       info->port, info->irq);
+		printk(" is a Z8530 ESCC\n");
+	}
+
+	restore_flags(flags);
+
+	return 0;
+}
+
+/*
+ * register_serial and unregister_serial allows for serial ports to be
+ * configured at run-time, to support PCMCIA modems.
+ */
+/* PowerMac: Unused at this time, just here to make things link. */
+int register_serial(struct serial_struct *req)
+{
+	return -1;
+}
+
+void unregister_serial(int line)
+{
+	return;
+}
+
+extern void register_console(void (*proc)(const char *));
+
+/*
+ * Initialization values for when a channel is used for
+ * a serial console.
+ */
+static unsigned char cons_init_regs[16] = {
+	0, 0, 0,		/* write 0, 1, 2 */
+	(Rx8 | RxENABLE),	/* write 3 */
+	(X16CLK | SB1),		/* write 4 */
+	(Tx8 | TxENAB | RTS),	/* write 5 */
+	0, 0, 0,		/* write 6, 7, 8 */
+	0,			/* write 9 */
+	(NRZ),			/* write 10 */
+	(TCBR | RCBR),		/* write 11 */
+	1, 0,			/* 38400 baud divisor, write 12 + 13 */
+	(BRENABL),		/* write 14 */
+	0			/* write 15 */
+};
+
+/*
+ * Hooks for running a serial console.  con_init() calls this if the
+ * console is being run over one of the serial ports.
+ * 'channel' is decoded as 1=modem, 2=printer.
+ */
+void
+rs_cons_hook(int chip, int out, int channel)
+{
+	int brg;
+
+	if (!out)
+		return;
+	if (zs_consinfo != 0) {
+		printk("rs_cons_hook called twice?\n");
+		return;
+	}
+	if (zs_chain == 0)
+		probe_sccs();
+	--channel;
+	if (channel < 0 || channel >= zs_channels_found) {
+		printk("rs_cons_hook: channel = %d?\n", channel);
+		return;
+	}
+
+	zs_cons_chan = channel;
+	zs_consinfo = &zs_soft[channel];
+	zs_conschan = zs_consinfo->zs_channel;
+	zs_consinfo->clk_divisor = 16;
+	zs_consinfo->zs_baud = 38400;
+	zs_consinfo->is_cons = 1;
+
+	memcpy(zs_consinfo->curregs, cons_init_regs, sizeof(cons_init_regs));
+	brg = BPS_TO_BRG(zs_consinfo->zs_baud, ZS_CLOCK/16);
+	zs_consinfo->curregs[R12] = brg;
+	zs_consinfo->curregs[R13] = brg >> 8;
+	load_zsregs(zs_conschan, zs_consinfo->curregs);
+
+	register_console(zs_console_print);
+	printk("zs%d: console I/O\n", channel);
+}
+
+/* This is called at boot time to prime the kgdb serial debugging
+ * serial line.  The 'tty_num' argument is 0 for /dev/ttyS0 and 1
+ * for /dev/ttyS1 which is determined in setup_arch() from the
+ * boot command line flags.
+ */
+void
+rs_kgdb_hook(int tty_num)
+{
+	if (zs_chain == 0)
+		probe_sccs();
+	zs_kgdbchan = zs_soft[tty_num].zs_channel;
+	zs_soft[tty_num].clk_divisor = 16;
+	zs_soft[tty_num].zs_baud = get_zsbaud(&zs_soft[tty_num]);
+	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);
+	ZS_CLEARFIFO(zs_kgdbchan);
+}
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/macserial.h linux/drivers/macintosh/macserial.h
--- v2.1.50/linux/drivers/macintosh/macserial.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/macserial.h	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,407 @@
+/*
+ * macserial.h: Definitions for the Macintosh Z8530 serial driver.
+ *
+ * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+#ifndef _MACSERIAL_H
+#define _MACSERIAL_H
+
+#define NUM_ZSREGS    16
+
+struct serial_struct {
+	int	type;
+	int	line;
+	int	port;
+	int	irq;
+	int	flags;
+	int	xmit_fifo_size;
+	int	custom_divisor;
+	int	baud_base;
+	unsigned short	close_delay;
+	char	reserved_char[2];
+	int	hub6;
+	unsigned short	closing_wait; /* time to wait before closing */
+	unsigned short	closing_wait2; /* no longer used... */
+	int	reserved[4];
+};
+
+/*
+ * For the close wait times, 0 means wait forever for serial port to
+ * flush its output.  65535 means don't wait at all.
+ */
+#define ZILOG_CLOSING_WAIT_INF	0
+#define ZILOG_CLOSING_WAIT_NONE	65535
+
+/*
+ * Definitions for ZILOG_struct (and serial_struct) flags field
+ */
+#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
+				   on the callout port */
+#define ZILOG_FOURPORT  0x0002	/* Set OU1, OUT2 per AST Fourport settings */
+#define ZILOG_SAK	0x0004	/* Secure Attention Key (Orange book) */
+#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define ZILOG_SPD_MASK	0x0030
+#define ZILOG_SPD_HI	0x0010	/* Use 56000 instead of 38400 bps */
+
+#define ZILOG_SPD_VHI	0x0020  /* Use 115200 instead of 38400 bps */
+#define ZILOG_SPD_CUST	0x0030  /* Use user-specified divisor */
+
+#define ZILOG_SKIP_TEST	0x0040 /* Skip UART test during autoconfiguration */
+#define ZILOG_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
+#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define ZILOG_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
+#define ZILOG_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
+
+#define ZILOG_FLAGS	0x0FFF	/* Possible legal ZILOG flags */
+#define ZILOG_USR_MASK 0x0430	/* Legal flags that non-privileged
+				 * users can set or reset */
+
+/* Internal flags used only by kernel/chr_drv/serial.c */
+#define ZILOG_INITIALIZED	0x80000000 /* Serial port was initialized */
+#define ZILOG_CALLOUT_ACTIVE	0x40000000 /* Call out device is active */
+#define ZILOG_NORMAL_ACTIVE	0x20000000 /* Normal device is active */
+#define ZILOG_BOOT_AUTOCONF	0x10000000 /* Autoconfigure port on bootup */
+#define ZILOG_CLOSING		0x08000000 /* Serial port is closing */
+#define ZILOG_CTS_FLOW		0x04000000 /* Do CTS flow control */
+#define ZILOG_CHECK_CD		0x02000000 /* i.e., CLOCAL */
+
+/* Software state per channel */
+
+#ifdef __KERNEL__
+/*
+ * This is our internal structure for each serial port's state.
+ * 
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+struct mac_zschannel {
+	volatile unsigned char *control;
+	volatile unsigned char *data;
+};
+
+struct mac_serial {
+	struct mac_serial *zs_next;	/* For IRQ servicing chain */
+	struct mac_zschannel *zs_channel; /* Channel registers */
+	struct mac_zschannel *zs_chan_a;	/* A side registers */
+	unsigned char read_reg_zero;
+
+	char soft_carrier;  /* Use soft carrier on this channel */
+	char break_abort;   /* Is serial console in, so process brk/abrt */
+	char kgdb_channel;  /* Kgdb is running on this channel */
+	char is_cons;       /* Is this our console. */
+	unsigned char tx_active; /* character is being xmitted */
+	unsigned char tx_stopped; /* output is suspended */
+
+	/* We need to know the current clock divisor
+	 * to read the bps rate the chip has currently
+	 * loaded.
+	 */
+	unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
+	int zs_baud;
+
+	/* 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;
+	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;
+	int			timeout;
+	int			xmit_fifo_size;
+	int			custom_divisor;
+	int			x_char;	/* xon/xoff character */
+	int			close_delay;
+	unsigned short		closing_wait;
+	unsigned short		closing_wait2;
+	unsigned long		event;
+	unsigned long		last_active;
+	int			line;
+	int			count;	    /* # of fd on device */
+	int			blocked_open; /* # of blocked opens */
+	long			session; /* Session of opening process */
+	long			pgrp; /* pgrp of opening process */
+	unsigned char 		*xmit_buf;
+	int			xmit_head;
+	int			xmit_tail;
+	int			xmit_cnt;
+	struct tq_struct	tqueue;
+	struct tq_struct	tqueue_hangup;
+	struct termios		normal_termios;
+	struct termios		callout_termios;
+	struct wait_queue	*open_wait;
+	struct wait_queue	*close_wait;
+};
+
+
+#define SERIAL_MAGIC 0x5301
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define SERIAL_XMIT_SIZE 4096
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP	0
+
+#endif /* __KERNEL__ */
+
+/* Conversion routines to/from brg time constants from/to bits
+ * per second.
+ */
+#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/* The Zilog register set */
+
+#define	FLAG	0x7e
+
+/* Write Register 0 */
+#define	R0	0		/* Register selects */
+#define	R1	1
+#define	R2	2
+#define	R3	3
+#define	R4	4
+#define	R5	5
+#define	R6	6
+#define	R7	7
+#define	R8	8
+#define	R9	9
+#define	R10	10
+#define	R11	11
+#define	R12	12
+#define	R13	13
+#define	R14	14
+#define	R15	15
+
+#define	NULLCODE	0	/* Null Code */
+#define	POINT_HIGH	0x8	/* Select upper half of registers */
+#define	RES_EXT_INT	0x10	/* Reset Ext. Status Interrupts */
+#define	SEND_ABORT	0x18	/* HDLC Abort */
+#define	RES_RxINT_FC	0x20	/* Reset RxINT on First Character */
+#define	RES_Tx_P	0x28	/* Reset TxINT Pending */
+#define	ERR_RES		0x30	/* Error Reset */
+#define	RES_H_IUS	0x38	/* Reset highest IUS */
+
+#define	RES_Rx_CRC	0x40	/* Reset Rx CRC Checker */
+#define	RES_Tx_CRC	0x80	/* Reset Tx CRC Checker */
+#define	RES_EOM_L	0xC0	/* Reset EOM latch */
+
+/* Write Register 1 */
+
+#define	EXT_INT_ENAB	0x1	/* Ext Int Enable */
+#define	TxINT_ENAB	0x2	/* Tx Int Enable */
+#define	PAR_SPEC	0x4	/* Parity is special condition */
+
+#define	RxINT_DISAB	0	/* Rx Int Disable */
+#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	WT_RDY_RT	0x20	/* Wait/Ready on R/T */
+#define	WT_FN_RDYFN	0x40	/* Wait/FN/Ready FN */
+#define	WT_RDY_ENAB	0x80	/* Wait/Ready Enable */
+
+/* Write Register #2 (Interrupt Vector) */
+
+/* Write Register 3 */
+
+#define	RxENABLE	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 */
+#define	ENT_HM		0x10	/* Enter Hunt Mode */
+#define	AUTO_ENAB	0x20	/* Auto Enables */
+#define	Rx5		0x0	/* Rx 5 Bits/Character */
+#define	Rx7		0x40	/* Rx 7 Bits/Character */
+#define	Rx6		0x80	/* Rx 6 Bits/Character */
+#define	Rx8		0xc0	/* Rx 8 Bits/Character */
+#define RxNBITS_MASK	0xc0
+
+/* Write Register 4 */
+
+#define	PAR_ENA		0x1	/* Parity Enable */
+#define	PAR_EVEN	0x2	/* Parity Even/Odd* */
+
+#define	SYNC_ENAB	0	/* Sync Modes Enable */
+#define	SB1		0x4	/* 1 stop bit/char */
+#define	SB15		0x8	/* 1.5 stop bits/char */
+#define	SB2		0xc	/* 2 stop bits/char */
+#define SB_MASK		0xc
+
+#define	MONSYNC		0	/* 8 Bit Sync character */
+#define	BISYNC		0x10	/* 16 bit sync character */
+#define	SDLC		0x20	/* SDLC Mode (01111110 Sync Flag) */
+#define	EXTSYNC		0x30	/* External Sync Mode */
+
+#define	X1CLK		0x0	/* x1 clock mode */
+#define	X16CLK		0x40	/* x16 clock mode */
+#define	X32CLK		0x80	/* x32 clock mode */
+#define	X64CLK		0xC0	/* x64 clock mode */
+#define XCLK_MASK	0xC0
+
+/* Write Register 5 */
+
+#define	TxCRC_ENAB	0x1	/* Tx CRC Enable */
+#define	RTS		0x2	/* RTS */
+#define	SDLC_CRC	0x4	/* SDLC/CRC-16 */
+#define	TxENAB		0x8	/* Tx Enable */
+#define	SND_BRK		0x10	/* Send Break */
+#define	Tx5		0x0	/* Tx 5 bits (or less)/character */
+#define	Tx7		0x20	/* Tx 7 bits/character */
+#define	Tx6		0x40	/* Tx 6 bits/character */
+#define	Tx8		0x60	/* Tx 8 bits/character */
+#define TxNBITS_MASK	0x60
+#define	DTR		0x80	/* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (transmit buffer) */
+
+/* Write Register 9 (Master interrupt control) */
+#define	VIS	1	/* Vector Includes Status */
+#define	NV	2	/* No Vector */
+#define	DLC	4	/* Disable Lower Chain */
+#define	MIE	8	/* Master Interrupt Enable */
+#define	STATHI	0x10	/* Status high */
+#define	NORESET	0	/* No reset on write to R9 */
+#define	CHRB	0x40	/* Reset channel B */
+#define	CHRA	0x80	/* Reset channel A */
+#define	FHWRES	0xc0	/* Force hardware reset */
+
+/* Write Register 10 (misc control bits) */
+#define	BIT6	1	/* 6 bit/8bit sync */
+#define	LOOPMODE 2	/* SDLC Loop mode */
+#define	ABUNDER	4	/* Abort/flag on SDLC xmit underrun */
+#define	MARKIDLE 8	/* Mark/flag on idle */
+#define	GAOP	0x10	/* Go active on poll */
+#define	NRZ	0	/* NRZ mode */
+#define	NRZI	0x20	/* NRZI mode */
+#define	FM1	0x40	/* FM1 (transition = 1) */
+#define	FM0	0x60	/* FM0 (transition = 0) */
+#define	CRCPS	0x80	/* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode control) */
+#define	TRxCXT	0	/* TRxC = Xtal output */
+#define	TRxCTC	1	/* TRxC = Transmit clock */
+#define	TRxCBR	2	/* TRxC = BR Generator Output */
+#define	TRxCDP	3	/* TRxC = DPLL output */
+#define	TRxCOI	4	/* TRxC O/I */
+#define	TCRTxCP	0	/* Transmit clock = RTxC pin */
+#define	TCTRxCP	8	/* Transmit clock = TRxC pin */
+#define	TCBR	0x10	/* Transmit clock = BR Generator output */
+#define	TCDPLL	0x18	/* Transmit clock = DPLL output */
+#define	RCRTxCP	0	/* Receive clock = RTxC pin */
+#define	RCTRxCP	0x20	/* Receive clock = TRxC pin */
+#define	RCBR	0x40	/* Receive clock = BR Generator output */
+#define	RCDPLL	0x60	/* Receive clock = DPLL output */
+#define	RTxCX	0x80	/* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (lower byte of baud rate generator time constant) */
+
+/* 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	BRSRC	2	/* Baud rate generator source */
+#define	DTRREQ	4	/* DTR/Request function */
+#define	AUTOECHO 8	/* Auto Echo */
+#define	LOOPBAK	0x10	/* Local loopback */
+#define	SEARCH	0x20	/* Enter search mode */
+#define	RMC	0x40	/* Reset missing clock */
+#define	DISDPLL	0x60	/* Disable DPLL */
+#define	SSBR	0x80	/* Set DPLL source = BR generator */
+#define	SSRTxC	0xa0	/* Set DPLL source = RTxC */
+#define	SFMM	0xc0	/* Set FM mode */
+#define	SNRZI	0xe0	/* Set NRZI mode */
+
+/* Write Register 15 (external/status interrupt control) */
+#define	ZCIE	2	/* Zero count IE */
+#define	DCDIE	8	/* DCD IE */
+#define	SYNCIE	0x10	/* Sync/hunt IE */
+#define	CTSIE	0x20	/* CTS IE */
+#define	TxUIE	0x40	/* Tx Underrun/EOM IE */
+#define	BRKIE	0x80	/* Break/Abort IE */
+
+
+/* Read Register 0 */
+#define	Rx_CH_AV	0x1	/* Rx Character Available */
+#define	ZCOUNT		0x2	/* Zero count */
+#define	Tx_BUF_EMP	0x4	/* Tx Buffer empty */
+#define	DCD		0x8	/* DCD */
+#define	SYNC_HUNT	0x10	/* Sync/hunt */
+#define	CTS		0x20	/* CTS */
+#define	TxEOM		0x40	/* Tx underrun */
+#define	BRK_ABRT	0x80	/* Break/Abort */
+
+/* Read Register 1 */
+#define	ALL_SNT		0x1	/* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define	RES3		0x8	/* 0/3 */
+#define	RES4		0x4	/* 0/4 */
+#define	RES5		0xc	/* 0/5 */
+#define	RES6		0x2	/* 0/6 */
+#define	RES7		0xa	/* 0/7 */
+#define	RES8		0x6	/* 0/8 */
+#define	RES18		0xe	/* 1/8 */
+#define	RES28		0x0	/* 2/8 */
+/* Special Rx Condition Interrupts */
+#define	PAR_ERR		0x10	/* Parity error */
+#define	Rx_OVR		0x20	/* Rx Overrun Error */
+#define	FRM_ERR		0x40	/* CRC/Framing Error */
+#define	END_FR		0x80	/* End of Frame (SDLC) */
+
+/* Read Register 2 (channel b only) - Interrupt vector */
+
+/* Read Register 3 (interrupt pending register) ch a only */
+#define	CHBEXT	0x1		/* Channel B Ext/Stat IP */
+#define	CHBTxIP	0x2		/* Channel B Tx IP */
+#define	CHBRxIP	0x4		/* Channel B Rx IP */
+#define	CHAEXT	0x8		/* Channel A Ext/Stat IP */
+#define	CHATxIP	0x10		/* Channel A Tx IP */
+#define	CHARxIP	0x20		/* Channel A Rx IP */
+
+/* Read Register 8 (receive data register) */
+
+/* Read Register 10  (misc status bits) */
+#define	ONLOOP	2		/* On loop */
+#define	LOOPSEND 0x10		/* Loop sending */
+#define	CLK2MIS	0x40		/* Two clocks missing */
+#define	CLK1MIS	0x80		/* One clock missing */
+
+/* Read Register 12 (lower byte of baud rate generator constant) */
+
+/* Read Register 13 (upper byte of baud rate generator constant) */
+
+/* Read Register 15 (value of WR 15) */
+
+/* Misc macros */
+#define ZS_CLEARERR(channel)    (write_zsreg(channel, 0, ERR_RES))
+#define ZS_CLEARFIFO(channel)   do { volatile unsigned char garbage; \
+				     garbage = read_zsdata(channel); \
+				     garbage = read_zsdata(channel); \
+				     garbage = read_zsdata(channel); \
+				} while(0)
+
+#endif /* !(_MACSERIAL_H) */
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/nvram.c linux/drivers/macintosh/nvram.c
--- v2.1.50/linux/drivers/macintosh/nvram.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/nvram.c	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,87 @@
+/*
+ * /dev/nvram driver for Power Macintosh.
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/fcntl.h>
+#include <linux/nvram.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+
+#define NVRAM_SIZE	8192
+
+static long long nvram_llseek(struct inode *inode, struct file *file,
+			      loff_t offset, int origin)
+{
+	switch (origin) {
+	case 1:
+		offset += file->f_pos;
+		break;
+	case 2:
+		offset += NVRAM_SIZE;
+		break;
+	}
+	if (offset < 0)
+		return -EINVAL;
+	file->f_pos = offset;
+	return file->f_pos;
+}
+
+static long read_nvram(struct inode *inode, struct file *file,
+	char *buf, unsigned long count)
+{
+	unsigned int i = file->f_pos;
+	char *p = buf;
+
+	for (; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count)
+		put_user(nvram_read_byte(i), p);
+	file->f_pos = i;
+	return p - buf;
+}
+
+static long write_nvram(struct inode *inode, struct file *file,
+	const char *buf, unsigned long count)
+{
+	unsigned int i = file->f_pos;
+	const char *p = buf;
+	char c;
+
+	for (; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count) {
+		get_user(c, p);
+		nvram_write_byte(i, c);
+	}
+	file->f_pos = i;
+	return p - buf;
+}
+
+static int nvram_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+struct file_operations nvram_fops = {
+	nvram_llseek,
+	read_nvram,
+	write_nvram,
+	NULL,		/* nvram_readdir */
+	NULL,		/* nvram_select */
+	NULL,		/* nvram_ioctl */
+	NULL,		/* nvram_mmap */
+	nvram_open,
+	NULL,		/* no special release code */
+	NULL		/* fsync */
+};
+
+static struct miscdevice nvram_dev = {
+	NVRAM_MINOR,
+	"nvram",
+	&nvram_fops
+};
+
+__initfunc(int nvram_init(void))
+{
+	misc_register(&nvram_dev);
+	return 0;
+}
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/platinum.c linux/drivers/macintosh/platinum.c
--- v2.1.50/linux/drivers/macintosh/platinum.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/platinum.c	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,623 @@
+/*
+ * platinum.c: Console support for PowerMac "platinum" display adaptor.
+ *
+ * Copyright (C) 1996 Paul Mackerras and Mark Abene.
+ *	
+ * 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.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/vc_ioctl.h>
+#include <linux/nvram.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <linux/selection.h>
+#include "pmac-cons.h"
+#include "platinum.h"
+
+/*
+ * Structure of the registers for the DACula colormap device.
+ */
+struct cmap_regs {
+	unsigned char addr;
+	char pad1[15];
+	unsigned char d1;
+	char pad2[15];
+	unsigned char d2;
+	char pad3[15];
+	unsigned char lut;
+	char pad4[15];
+};
+
+/*
+ * Structure of the registers for the "platinum" display adaptor".
+ */
+#define PAD(x)	char x[12]
+
+struct preg {			/* padded register */
+	unsigned r;
+	char pad[12];
+};
+
+struct platinum_regs {
+	struct preg reg[128];
+};
+
+static void set_platinum_clock(unsigned char *clksel);
+static int read_platinum_sense(void);
+static int platinum_vram_reqd(int vmode, int cmode);
+
+static int total_vram;		/* total amount of video memory, bytes */
+static unsigned char *frame_buffer;
+static unsigned char *base_frame_buffer;
+static struct cmap_regs *cmap_regs;
+static volatile struct platinum_regs *plat_regs;
+
+/*
+ * Register initialization tables for the platinum display.
+ *
+ * It seems that there are two different types of platinum display
+ * out there.  Older ones use the values in clocksel[1], for which
+ * the formula for the clock frequency seems to be
+ *	F = 14.3MHz * c0 / (c1 & 0x1f) / (1 << (c1 >> 5))
+ * Newer ones use the values in clocksel[0], for which the formula
+ * seems to be
+ *	F = 15MHz * c0 / ((c1 & 0x1f) + 2) / (1 << (c1 >> 5))
+ */
+struct plat_regvals {
+	int	fb_offset;
+	int	pitch[3];
+	unsigned regs[26];
+	unsigned char plat_offset[3];
+	unsigned char mode[3];
+	unsigned char dacula_ctrl[3];
+	unsigned char clocksel[2][2];
+};
+
+#define DIV2	0x20
+#define DIV4	0x40
+#define DIV8	0x60
+#define DIV16	0x80
+
+/* 1280x1024, 75Hz (20) */
+static struct plat_regvals platinum_reg_init_20 = {
+	0x5c00,
+	{ 1312, 2592, 2592 },
+	{ 0xffc, 4, 0, 0, 0, 0, 0x428, 0,
+	  0, 0xb3, 0xd3, 0x12, 0x1a5, 0x23, 0x28, 0x2d,
+	  0x5e, 0x19e, 0x1a4, 0x854, 0x852, 4, 9, 0x50,
+	  0x850, 0x851 }, { 0x58, 0x5d, 0x5d },
+	{ 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 },
+	{{ 45, 3 }, { 66, 7 }}
+};
+
+/* 1280x960, 75Hz (19) */
+static struct plat_regvals platinum_reg_init_19 = {
+	0x5c00,
+	{ 1312, 2592, 2592 },
+	{ 0xffc, 4, 0, 0, 0, 0, 0x428, 0,
+	  0, 0xb2, 0xd2, 0x12, 0x1a3, 0x23, 0x28, 0x2d,
+	  0x5c, 0x19c, 0x1a2, 0x7d0, 0x7ce, 4, 9, 0x4c,
+	  0x7cc, 0x7cd }, { 0x56, 0x5b, 0x5b },
+	{ 0, 0xff, 0xff }, { 0x51, 0x55, 0x55 },
+	{{ 42, 3 }, { 44, 5 }}
+};
+
+/* 1152x870, 75Hz (18) */
+static struct plat_regvals platinum_reg_init_18 = {
+	0x11b0,
+	{ 1184, 2336, 4640 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x38f, 0,
+	  0, 0x294, 0x16c, 0x20, 0x2d7, 0x3f, 0x49, 0x53,
+	  0x82, 0x2c2, 0x2d6, 0x726, 0x724, 4, 9, 0x52,
+	  0x71e, 0x722 }, { 0x74, 0x7c, 0x81 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 26, 0 + DIV2 }, { 42, 6 }}
+};
+
+/* 1024x768, 75Hz (17) */
+static struct plat_regvals platinum_reg_init_17 = {
+	0x10b0,
+	{ 1056, 2080, 4128 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x254, 0x14b, 0x18, 0x295, 0x2f, 0x32, 0x3b,
+	  0x80, 0x280, 0x296, 0x648, 0x646, 4, 9, 0x40,
+	  0x640, 0x644 }, { 0x72, 0x7a, 0x7f },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 54, 3 + DIV2 }, { 67, 12 }}
+};
+
+/* 1024x768, 75Hz (16) */
+static struct plat_regvals platinum_reg_init_16 = {
+	0x10b0,
+	{ 1056, 2080, 4128 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x250, 0x147, 0x17, 0x28f, 0x2f, 0x35, 0x47,
+	  0x82, 0x282, 0x28e, 0x640, 0x63e, 4, 9, 0x3c,
+	  0x63c, 0x63d }, { 0x74, 0x7c, 0x81 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 20, 0 + DIV2 }, { 11, 2 }}
+};
+
+/* 1024x768, 70Hz (15) */
+static struct plat_regvals platinum_reg_init_15 = {
+	0x10b0,
+	{ 1056, 2080, 4128 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x254, 0x14b, 0x22, 0x297, 0x43, 0x49, 0x5b,
+	  0x86, 0x286, 0x296, 0x64c, 0x64a, 0xa, 0xf, 0x44,
+	  0x644, 0x646 }, { 0x78, 0x80, 0x85 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 19, 0 + DIV2 }, { 110, 21 }}
+};
+
+/* 1024x768, 60Hz (14) */
+static struct plat_regvals platinum_reg_init_14 = {
+	0x10b0,
+	{ 1056, 2080, 4128 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x25a, 0x14f, 0x22, 0x29f, 0x43, 0x49, 0x5b,
+	  0x8e, 0x28e, 0x29e, 0x64c, 0x64a, 0xa, 0xf, 0x44,
+	  0x644, 0x646 }, { 0x80, 0x88, 0x8d },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 71, 6 + DIV2 }, { 118, 13 + DIV2 }}
+};
+
+/* 832x624, 75Hz (13) */
+static struct plat_regvals platinum_reg_init_13 = {
+	0x70,
+	{ 864, 1680, 3360 },	/* MacOS does 1680 instead of 1696 to fit 16bpp in 1MB */
+	{ 0xff0, 4, 0, 0, 0, 0, 0x299, 0,
+	  0, 0x21e, 0x120, 0x10, 0x23f, 0x1f, 0x25, 0x37,
+	  0x8a, 0x22a, 0x23e, 0x536, 0x534, 4, 9, 0x52,
+	  0x532, 0x533 }, { 0x7c, 0x84, 0x89 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }}
+};
+
+/* 800x600, 75Hz (12) */
+static struct plat_regvals platinum_reg_init_12 = {
+	0x1010,
+	{ 832, 1632, 3232 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x1ce, 0x108, 0x14, 0x20f, 0x27, 0x30, 0x39,
+	  0x72, 0x202, 0x20e, 0x4e2, 0x4e0, 4, 9, 0x2e,
+	  0x4de, 0x4df }, { 0x64, 0x6c, 0x71 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 122, 7 + DIV4 }, { 62, 9 + DIV2 }}
+};
+
+/* 800x600, 72Hz (11) */
+static struct plat_regvals platinum_reg_init_11 = {
+	0x1010,
+	{ 832, 1632, 3232 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x1ca, 0x104, 0x1e, 0x207, 0x3b, 0x44, 0x4d,
+	  0x56, 0x1e6, 0x206, 0x534, 0x532, 0xa, 0xe, 0x38,
+	  0x4e8, 0x4ec }, { 0x48, 0x50, 0x55 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 26, 0 + DIV4 }, { 42, 6 + DIV2 }}
+};
+
+/* 800x600, 60Hz (10) */
+static struct plat_regvals platinum_reg_init_10 = {
+	0x1010,
+	{ 832, 1632, 3232 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d,
+	  0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34,
+	  0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 54, 3 + DIV4 }, { 95, 1 + DIV8 }}
+};
+
+/* 800x600, 56Hz (9) --unsupported? copy of mode 10 for now... */
+static struct plat_regvals platinum_reg_init_9 = {
+	0x1010,
+	{ 832, 1632, 3232 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x1ce, 0x108, 0x20, 0x20f, 0x3f, 0x45, 0x5d,
+	  0x66, 0x1f6, 0x20e, 0x4e8, 0x4e6, 6, 0xa, 0x34,
+	  0x4e4, 0x4e5 }, { 0x58, 0x60, 0x65 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 54, 3 + DIV4 }, { 88, 1 + DIV8 }}
+};
+
+/* 768x576, 50Hz Interlaced-PAL (8) */
+static struct plat_regvals platinum_reg_init_8 = {
+	0x1010,
+	{ 800, 1568, 3104 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36,
+	  0x47, 0x1c7, 0x1d6, 0x271, 0x270, 4, 9, 0x27,
+	  0x267, 0x26b }, { 0x39, 0x41, 0x46 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }}
+};
+
+/* 640x870, 75Hz Portrait (7) */
+static struct plat_regvals platinum_reg_init_7 = {
+	0xb10,
+	{ 672, 1312, 2592 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x176, 0xd0, 0x14, 0x19f, 0x27, 0x2d, 0x3f,
+	  0x4a, 0x18a, 0x19e, 0x72c, 0x72a, 4, 9, 0x58,
+	  0x724, 0x72a }, { 0x3c, 0x44, 0x49 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 30, 0 + DIV4 }, { 56, 7 + DIV2 }}
+};
+
+/* 640x480, 67Hz (6) */
+static struct plat_regvals platinum_reg_init_6 = {
+	0x1010,
+	{ 672, 1312, 2592 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x209, 0,
+	  0, 0x18e, 0xd8, 0x10, 0x1af, 0x1f, 0x25, 0x37,
+	  0x4a, 0x18a, 0x1ae, 0x41a, 0x418, 4, 9, 0x52,
+	  0x412, 0x416 }, { 0x3c, 0x44, 0x49 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 99, 4 + DIV8 }, { 42, 5 + DIV4 }}
+};
+
+/* 640x480, 60Hz (5) */
+static struct plat_regvals platinum_reg_init_5 = {
+	0x1010,
+	{ 672, 1312, 2592 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x15e, 0xc8, 0x18, 0x18f, 0x2f, 0x35, 0x3e,
+	  0x42, 0x182, 0x18e, 0x41a, 0x418, 2, 7, 0x44,
+	  0x404, 0x408 }, { 0x34, 0x3c, 0x41 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 26, 0 + DIV8 }, { 14, 2 + DIV4 }}
+};
+
+/* 640x480, 60Hz Interlaced-NTSC (4) */
+static struct plat_regvals platinum_reg_init_4 = {
+	0x1010,
+	{ 672, 1312, 2592 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30,
+	  0x37, 0x177, 0x184, 0x20d, 0x20c, 5, 0xb, 0x23,
+	  0x203, 0x206 }, { 0x29, 0x31, 0x36 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }}
+};
+
+/* 640x480, 50Hz Interlaced-PAL (3) */
+static struct plat_regvals platinum_reg_init_3 = {
+	0x1010,
+	{ 672, 1312, 2592 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0xc8, 0xec, 0x11, 0x1d7, 0x22, 0x25, 0x36,
+	  0x67, 0x1a7, 0x1d6, 0x271, 0x270, 4, 9, 0x57,
+	  0x237, 0x26b }, { 0x59, 0x61, 0x66 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 31, 0 + DIV16 }, { 74, 9 + DIV8 }}
+};
+
+/* 512x384, 60Hz (2) */
+static struct plat_regvals platinum_reg_init_2 = {
+	0x1010,
+	{ 544, 1056, 2080 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0x25c, 0x140, 0x10, 0x27f, 0x1f, 0x2b, 0x4f,
+	  0x68, 0x268, 0x27e, 0x32e, 0x32c, 4, 9, 0x2a,
+	  0x32a, 0x32b }, { 0x5a, 0x62, 0x67 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 33, 2 + DIV8 }, { 79, 9 + DIV8 }}
+};
+
+/* 512x384, 60Hz Interlaced-NTSC (1) */
+static struct plat_regvals platinum_reg_init_1 = {
+	0x1010,
+	{ 544, 1056, 2080 },
+	{ 0xff0, 4, 0, 0, 0, 0, 0x320, 0,
+	  0, 0xa5, 0xc3, 0xe, 0x185, 0x1c, 0x1f, 0x30,
+	  0x57, 0x157, 0x184, 0x20d, 0x20c, 5, 0xb, 0x53,
+	  0x1d3, 0x206 }, { 0x49, 0x51, 0x56 },
+	{ 2, 0, 0xff }, { 0x11, 0x15, 0x19 },
+	{{ 94, 5 + DIV16 }, { 48, 7 + DIV8 }}
+};
+
+static struct plat_regvals *platinum_reg_init[VMODE_MAX] = {
+	&platinum_reg_init_1,
+	&platinum_reg_init_2,
+	&platinum_reg_init_3,
+	&platinum_reg_init_4,
+	&platinum_reg_init_5,
+	&platinum_reg_init_6,
+	&platinum_reg_init_7,
+	&platinum_reg_init_8,
+	&platinum_reg_init_9,
+	&platinum_reg_init_10,
+	&platinum_reg_init_11,
+	&platinum_reg_init_12,
+	&platinum_reg_init_13,
+	&platinum_reg_init_14,
+	&platinum_reg_init_15,
+	&platinum_reg_init_16,
+	&platinum_reg_init_17,
+	&platinum_reg_init_18,
+	&platinum_reg_init_19,
+	&platinum_reg_init_20
+};
+
+/*
+ * Get the monitor sense value.
+ */
+static int
+read_platinum_sense()
+{
+	int sense;
+
+	plat_regs->reg[23].r = 7;	/* turn off drivers */
+	eieio(); __delay(2000);
+	sense = (~plat_regs->reg[23].r & 7) << 8;
+
+	/* drive each sense line low in turn and collect the other 2 */
+	plat_regs->reg[23].r = 3;	/* drive A low */
+	eieio(); __delay(2000);
+	sense |= (~plat_regs->reg[23].r & 3) << 4;
+	eieio();
+	plat_regs->reg[23].r = 5;	/* drive B low */
+	eieio(); __delay(2000);
+	sense |= (~plat_regs->reg[23].r & 4) << 1;
+	sense |= (~plat_regs->reg[23].r & 1) << 2;
+	eieio();
+	plat_regs->reg[23].r = 6;	/* drive C low */
+	eieio(); __delay(2000);
+	sense |= (~plat_regs->reg[23].r & 6) >> 1;
+	eieio();
+
+	plat_regs->reg[23].r = 7;	/* turn off drivers */
+	return sense;
+}
+
+static inline int platinum_vram_reqd(int vmode, int cmode)
+{
+        return vmode_attrs[vmode-1].vres
+                * platinum_reg_init[vmode-1]->pitch[cmode];
+}
+
+void
+map_platinum(struct device_node *dp)
+{
+	int i, sense;
+	unsigned long addr, size;
+	int bank0, bank1, bank2, bank3;
+
+	if (dp->next != 0)
+		printk("Warning: only using first platinum display device\n");
+	if (dp->n_addrs != 2)
+		panic("expecting 2 addresses for platinum (got %d)",
+		      dp->n_addrs);
+
+	/* Map in frame buffer and registers */
+	for (i = 0; i < dp->n_addrs; ++i) {
+		addr = dp->addrs[i].address;
+		size = dp->addrs[i].size;
+		if (size >= 0x400000) {
+			/* frame buffer - map only 4MB */
+			frame_buffer = ioremap(addr, 0x400000);
+			base_frame_buffer = frame_buffer;
+		} else {
+			/* registers */
+			plat_regs = ioremap(addr, size);
+		}
+	}
+	cmap_regs = ioremap(0xf301b000, 0x1000);	/* XXX not in prom? */
+
+	/* Grok total video ram */
+	plat_regs->reg[16].r = (unsigned)frame_buffer;
+	plat_regs->reg[20].r = 0x1011;	/* select max vram */
+	plat_regs->reg[24].r = 0;	/* switch in vram */
+	eieio();
+	frame_buffer[0x100000] = 0x34;
+	frame_buffer[0x200000] = 0x56;
+	frame_buffer[0x300000] = 0x78;
+	eieio();
+	bank0 = 1; /* builtin 1MB vram, always there */
+	bank1 = frame_buffer[0x100000] == 0x34;
+	bank2 = frame_buffer[0x200000] == 0x56;
+	bank3 = frame_buffer[0x300000] == 0x78;
+	total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000;
+	printk("Total VRAM = %dMB\n", total_vram / 1024 / 1024);
+
+	sense = read_platinum_sense();
+	if (video_mode == VMODE_NVRAM) {
+		video_mode = nvram_read_byte(NV_VMODE);
+		if (video_mode <= 0 || video_mode > VMODE_MAX
+		    || platinum_reg_init[video_mode-1] == 0)
+			video_mode = VMODE_CHOOSE;
+	}
+	if (video_mode == VMODE_CHOOSE)
+		video_mode = map_monitor_sense(sense);
+	if (platinum_reg_init[video_mode-1] == 0)
+		video_mode = VMODE_640_480_60;
+	printk("Monitor sense value = 0x%x, ", sense);
+
+	if (color_mode == CMODE_NVRAM)
+                color_mode = nvram_read_byte(NV_CMODE);
+        if (color_mode < CMODE_8 || color_mode > CMODE_32)
+                color_mode = CMODE_8;
+	/*
+	 * Reduce the pixel size if we don't have enough VRAM.
+	 */
+	while (color_mode > CMODE_8
+	       && platinum_vram_reqd(video_mode, color_mode) > total_vram)
+		--color_mode;
+	/*
+	 * Reduce the video mode if we don't have enough VRAM.
+	 */
+	while (platinum_vram_reqd(video_mode, color_mode) > total_vram)
+		--video_mode;
+}
+
+#define STORE_D2(a, v) { \
+	out_8(&cmap_regs->addr, (a+32)); \
+	out_8(&cmap_regs->d2, (v)); \
+}
+
+static void
+set_platinum_clock(unsigned char *clksel)
+{
+	STORE_D2(6, 0xc6);
+	out_8(&cmap_regs->addr, 3+32);
+	if (cmap_regs->d2 == 2) {
+		STORE_D2(7, clksel[0]);
+		STORE_D2(8, clksel[1]);
+		STORE_D2(3, 3);
+	} else {
+		STORE_D2(4, clksel[0]);
+		STORE_D2(5, clksel[1]);
+		STORE_D2(3, 2);
+	}
+	__delay(5000);
+	STORE_D2(9, 0xa6);
+}
+
+void
+platinum_init()
+{
+	int i, yoff, width, clkmode, dtype;
+	struct plat_regvals *init;
+	unsigned *p;
+	int one_mb = 0;
+
+	if (total_vram == 0x100000) one_mb=1;
+
+	if (video_mode <= 0 || video_mode > VMODE_MAX
+	    || (init = platinum_reg_init[video_mode-1]) == 0)
+		panic("platinum: video mode %d not supported", video_mode);
+
+	frame_buffer = base_frame_buffer + init->fb_offset;
+	/* printk("Frame buffer start address is %p\n", frame_buffer); */
+
+	pixel_size = 1 << color_mode;
+	line_pitch = init->pitch[color_mode];
+	width = vmode_attrs[video_mode-1].hres;
+	n_scanlines = vmode_attrs[video_mode-1].vres;
+	row_pitch = line_pitch * 16;
+
+	/* Initialize display timing registers */
+	out_be32(&plat_regs->reg[24].r, 7);	/* turn display off */
+
+	for (i = 0; i < 26; ++i)
+		plat_regs->reg[i+32].r = init->regs[i];
+	plat_regs->reg[26+32].r = (one_mb ? init->plat_offset[color_mode] + 4 - color_mode : init->plat_offset[color_mode]);
+	plat_regs->reg[16].r = (unsigned) frame_buffer;
+	plat_regs->reg[18].r = line_pitch;
+	plat_regs->reg[19].r = (one_mb ? init->mode[color_mode+1] : init->mode[color_mode]);
+	plat_regs->reg[20].r = (one_mb ? 0x11 : 0x1011);
+	plat_regs->reg[21].r = 0x100;
+	plat_regs->reg[22].r = 1;
+	plat_regs->reg[23].r = 1;
+	plat_regs->reg[26].r = 0xc00;
+	plat_regs->reg[27].r = 0x235;
+	/* plat_regs->reg[27].r = 0x2aa; */
+
+	STORE_D2(0, (one_mb ? init->dacula_ctrl[color_mode] & 0xf : init->dacula_ctrl[color_mode]));
+	STORE_D2(1, 4);
+	STORE_D2(2, 0);
+	/*
+	 * Try to determine whether we have an old or a new DACula.
+	 */
+	out_8(&cmap_regs->addr, 0x40);
+	dtype = cmap_regs->d2;
+	switch (dtype) {
+	case 0x3c:
+		clkmode = 1;
+		break;
+	case 0x84:
+		clkmode = 0;
+		break;
+	default:
+		clkmode = 0;
+		printk("Unknown DACula type: %x\n", cmap_regs->d2);
+	}
+	set_platinum_clock(init->clocksel[clkmode]);
+
+	out_be32(&plat_regs->reg[24].r, 0);	/* turn display on */
+
+	pmac_init_palette();
+
+	yoff = (n_scanlines % 16) / 2;
+	fb_start = frame_buffer + yoff * line_pitch + 0x10;
+
+	/* Clear screen */
+	p = (unsigned *) (frame_buffer + 0x10);
+	for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
+		*p++ = 0;
+
+	display_info.height = n_scanlines;
+	display_info.width = width;
+	display_info.depth = 8 * pixel_size;
+	display_info.pitch = line_pitch;
+	display_info.mode = video_mode;
+	strncpy(display_info.name, "platinum", sizeof(display_info.name));
+	display_info.fb_address = (unsigned long) frame_buffer + 0x10;
+	display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr;
+	display_info.cmap_data_address = (unsigned long) &cmap_regs->lut;
+	display_info.disp_reg_address = (unsigned long) &plat_regs;
+}
+
+int
+platinum_setmode(struct vc_mode *mode, int doit)
+{
+	int cmode;
+
+	if (mode->mode <= 0 || mode->mode > VMODE_MAX
+	    || platinum_reg_init[mode->mode-1] == 0)
+		return -EINVAL;
+	if (mode->depth != 8 && mode->depth != 16 && mode->depth != 24 && mode->depth != 32)
+		return -EINVAL;
+
+	switch (mode->depth) {
+        case 24:
+        case 32:
+                cmode = CMODE_32;
+                break;
+        case 16:
+                cmode = CMODE_16;
+                break;
+        case 8:
+                cmode = CMODE_8;
+                break;
+        default:
+                return -EINVAL;
+        }
+
+	if (platinum_vram_reqd(mode->mode, cmode) > total_vram)
+		return -EINVAL;
+
+	if (doit) {
+		video_mode = mode->mode;
+		color_mode = cmode;
+		platinum_init();
+	}
+	return 0;
+}
+
+void
+platinum_set_palette(unsigned char red[], unsigned char green[],
+		     unsigned char blue[], int index, int ncolors)
+{
+	int i;
+
+	for (i = 0; i < ncolors; ++i) {
+		cmap_regs->addr = index + i;	eieio();
+		cmap_regs->lut = red[i];	eieio();
+		cmap_regs->lut = green[i];	eieio();
+		cmap_regs->lut = blue[i];	eieio();
+	}
+}
+
+void
+platinum_set_blanking(int blank_mode)
+{
+}
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/platinum.h linux/drivers/macintosh/platinum.h
--- v2.1.50/linux/drivers/macintosh/platinum.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/platinum.h	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,17 @@
+/*
+ * Exported procedures for the PowerMac "platinum" display adaptor.
+ *
+ * Copyright (C) 1996 Paul Mackerras and Mark Abene.
+ *	
+ * 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.
+ */
+
+extern void map_platinum(struct device_node *);
+extern void platinum_init(void);
+extern int platinum_setmode(struct vc_mode *mode, int doit);
+extern void platinum_set_palette(unsigned char red[], unsigned char green[],
+				 unsigned char blue[], int index, int ncolors);
+extern void platinum_set_blanking(int blank_mode);
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/pmac-cons.c linux/drivers/macintosh/pmac-cons.c
--- v2.1.50/linux/drivers/macintosh/pmac-cons.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/pmac-cons.c	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,1312 @@
+/*
+ * pmac-cons.c: Console support for PowerMac (PCI-based).
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ * 7200/Platinum code hacked by Mark Abene.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/vc_ioctl.h>
+#include <linux/kd.h>
+#include <linux/version.h>
+#include <asm/processor.h>
+#include <asm/prom.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/cuda.h>
+#include <asm/linux_logo.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
+#include <linux/vt_kern.h>
+#include "pmac-cons.h"
+#include "control.h"
+#include "platinum.h"
+#include "valkyrie.h"
+#ifdef CONFIG_ATY_VIDEO
+#include "aty.h"
+#endif
+#ifdef CONFIG_IMSTT_VIDEO
+#include "imstt.h"
+#endif
+
+int video_mode = VMODE_NVRAM;
+int color_mode = CMODE_NVRAM;
+
+/*
+ * The format of "screen_info" is strange, and due to early
+ * i386-setup code. This is just enough to make the console
+ * code think we're on a EGA+ colour display.
+ */
+struct screen_info screen_info = {
+	0, 0,			/* orig-x, orig-y */
+	{0, 0},			/* unused1 */
+	0,			/* orig-video-page */
+	0,			/* orig-video-mode */
+	80,			/* orig-video-cols */
+	0,			/* unused [short] */
+	0,			/* ega_bx */
+	0,			/* unused [short] */
+	25,			/* orig-video-lines */
+	0,			/* isVGA */
+	16			/* video points */
+};
+
+/*
+ * We allocate enough character+attribute memory for the largest
+ * screen resolution supported.
+ */
+#define MAX_TEXT_COLS	(1280/8)
+#define MAX_TEXT_ROWS	(1024/16)
+
+/*
+ * We get a sense value from the monitor and use it to choose
+ * what resolution to use.  This structure maps sense values
+ * to display mode values (which determine the resolution and
+ * frequencies).
+ */
+struct mon_map {
+	int	sense;
+	int	vmode;
+} monitor_map [] = {
+	{0x000, VMODE_1280_1024_75},	/* 21" RGB */
+	{0x114, VMODE_640_870_75P},	/* Portrait Monochrome */
+	{0x221, VMODE_512_384_60},	/* 12" RGB*/
+	{0x331, VMODE_1280_1024_75},	/* 21" RGB (Radius) */
+	{0x334, VMODE_1280_1024_75},	/* 21" mono (Radius) */
+	{0x335, VMODE_1280_1024_75},	/* 21" mono */
+	{0x40A, VMODE_640_480_60I},	/* NTSC */
+	{0x51E, VMODE_640_870_75P},	/* Portrait RGB */
+	{0x603, VMODE_832_624_75},	/* 12"-16" multiscan */
+	{0x60b, VMODE_1024_768_70},	/* 13"-19" multiscan */
+	{0x623, VMODE_1152_870_75},	/* 13"-21" multiscan */
+	{0x62b, VMODE_640_480_67},	/* 13"/14" RGB */
+	{0x700, VMODE_640_480_50I},	/* PAL */
+	{0x714, VMODE_640_480_60I},	/* NTSC */
+	{0x717, VMODE_800_600_75},	/* VGA */
+	{0x72d, VMODE_832_624_75},	/* 16" RGB (Goldfish) */
+	{0x730, VMODE_768_576_50I},	/* PAL (Alternate) */
+	{0x73a, VMODE_1152_870_75},	/* 3rd party 19" */
+	{-1,	VMODE_640_480_60},	/* catch-all, must be last */
+};
+
+int
+map_monitor_sense(int sense)
+{
+	struct mon_map *map;
+
+	for (map = monitor_map; map->sense >= 0; ++map)
+		if (map->sense == sense)
+			break;
+	return map->vmode;
+}
+
+/*
+ * Horizontal and vertical resolution for each mode.
+ */
+struct vmode_attr vmode_attrs[VMODE_MAX] = {
+	{512, 384, 60, 1},
+	{512, 384, 60},
+	{640, 480, 50, 1},
+	{640, 480, 60, 1},
+	{640, 480, 60},
+	{640, 480, 67},
+	{640, 870, 75},
+	{768, 576, 50, 1},
+	{800, 600, 56},
+	{800, 600, 60},
+	{800, 600, 72},
+	{800, 600, 75},
+	{832, 624, 75},
+	{1024, 768, 60},
+	{1024, 768, 72},
+	{1024, 768, 75},
+	{1024, 768, 75},
+	{1152, 870, 75},
+	{1280, 960, 75},
+	{1280, 1024, 75}
+};
+
+static void invert_cursor(int);
+static int map_unknown(struct device_node *);
+static void unknown_init(void);
+
+struct display_interface {
+	char *name;
+	void (*map_interface)(struct device_node *);
+	void (*init_interface)(void);
+	int  (*setmode)(struct vc_mode *, int);
+	void (*set_palette)(unsigned char red[], unsigned char green[],
+			    unsigned char blue[], int index, int ncolors);
+	void (*set_blanking)(int blank_mode);
+} displays[] = {
+	{ "control", map_control_display, control_init,
+	  control_setmode, control_set_palette, control_set_blanking },
+	{ "platinum", map_platinum, platinum_init,
+	  platinum_setmode, platinum_set_palette, platinum_set_blanking },
+	{ "valkyrie", map_valkyrie_display, valkyrie_init,
+	  valkyrie_setmode, valkyrie_set_palette, valkyrie_set_blanking },
+#ifdef CONFIG_ATY_VIDEO
+	{ "ATY,mach64", map_aty_display, aty_init,
+	  aty_setmode, aty_set_palette, aty_set_blanking },
+	{ "ATY,XCLAIM", map_aty_display, aty_init,
+	  aty_setmode, aty_set_palette, aty_set_blanking },
+	{ "ATY,264VT", map_aty_display, aty_init,
+	  aty_setmode, aty_set_palette, aty_set_blanking },
+	{ "ATY,mach64ii", map_aty_display, aty_init,
+	  aty_setmode, aty_set_palette, aty_set_blanking },
+#if 0	/* not right for 3D mach64 yet */
+	{ "ATY,264GT-B", map_aty_display, aty_init,
+	  aty_setmode, aty_set_palette, aty_set_blanking },
+	{ "ATY,mach64_3D_pcc", map_aty_display, aty_init,
+	  aty_setmode, aty_set_palette },
+#endif
+#endif
+#ifdef CONFIG_IMSTT_VIDEO
+	{ "IMS,tt128mb", map_imstt_display, imstt_init, 
+	  imstt_setmode, imstt_set_palette, imstt_set_blanking },
+#endif
+	{ NULL }
+};
+
+struct display_interface unknown_display = {
+	"unknown", NULL, unknown_init, NULL, NULL
+};
+
+static struct display_interface *current_display;
+
+static int cursor_pos = -1;
+static unsigned *cursor_fb;	/* address of cursor pos in frame buffer */
+static unsigned cursor_bits;	/* bits changed to turn cursor on */
+
+int pixel_size;			/* in bytes */
+int n_scanlines;		/* # of scan lines */
+int line_pitch;			/* # bytes in 1 scan line */
+int row_pitch;			/* # bytes in 1 row of characters */
+unsigned char *fb_start;	/* addr of top left pixel of top left char */
+struct vc_mode display_info;
+
+extern int screen_initialized;	/* in arch/ppc/pmac/prom.c */
+
+#define cmapsz	(16*256)
+extern unsigned char vga_font[cmapsz];
+
+static inline unsigned pixel32(int currcons, int cidx)
+{
+	cidx *= 3;
+	return (palette[cidx] << 16) | (palette[cidx + 1] << 8)
+		| palette[cidx + 2];
+}
+
+static inline unsigned pixel16(int currcons, int cidx)
+{
+	unsigned p;
+
+	p = ((cidx << 10) & 0x7c00) + ((cidx << 5) & 0x03e0)
+		+ (cidx & 0x1f);
+	return (p << 16) | p;
+}
+
+void
+__set_origin(unsigned short offset)
+{
+}
+
+static void
+invert_cursor(int cpos)
+{
+	int row, col;
+	int l, c, nw;
+	unsigned *fb, mask;
+	int currcons = fg_console;	/* for `color', which is a macro */
+
+	if (cpos == -1) {
+		/* turning cursor off */
+		fb = cursor_fb;
+		mask = cursor_bits;
+	} else {
+		row = cpos / video_num_columns;
+		col = cpos - row * video_num_columns;
+		fb = (unsigned *) (fb_start + row * row_pitch
+				   + col * pixel_size * 8);
+		switch (color_mode) {
+		case CMODE_16:
+			mask = pixel16(currcons, foreground)
+				^ pixel16(currcons, background >> 4);
+			break;
+		default:
+			mask = (color ^ (color >> 4)) & 0xf;
+			mask |= mask << 8;
+			mask |= mask << 16;
+			break;
+		}
+		cursor_fb = fb;
+		cursor_bits = mask;
+	}
+	nw = pixel_size * 2;	/* pixel_size * 8 (char width) / 4 */
+	for (l = 0; l < 16; ++l) {
+		for (c = 0; c < nw; ++c)
+			fb[c] ^= mask;
+		fb = (unsigned *) ((char *)fb + line_pitch);
+	}
+}
+
+void
+hide_cursor()
+{
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	if (cursor_pos != -1) {
+		invert_cursor(-1);
+		cursor_pos = -1;
+	}
+	restore_flags(flags);
+}
+
+void
+set_cursor(int currcons)
+{
+	unsigned long flags;
+	int old_cursor;
+
+	if (currcons != fg_console || console_blanked)
+		return;
+
+	save_flags(flags);
+	cli();
+	if (!deccm) {
+		hide_cursor();
+	} else {
+		old_cursor = cursor_pos;
+		cursor_pos = (pos - video_mem_base) >> 1;
+		if (old_cursor != -1)
+			invert_cursor(-1);
+		invert_cursor(cursor_pos);
+	}
+	restore_flags(flags);
+}
+
+/*
+ * NOTE: get_scrmem() and set_scrmem() are here only because
+ * the VGA version of set_scrmem() has some direct VGA references.
+ */
+void
+get_scrmem(int currcons)
+{
+	memcpyw((unsigned short *)vc_scrbuf[currcons],
+		(unsigned short *)origin, video_screen_size);
+	origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
+	scr_end = video_mem_end = video_mem_start + video_screen_size;
+	pos = origin + y*video_size_row + (x<<1);
+}
+
+void
+set_scrmem(int currcons, long offset)
+{
+	if (video_mem_term - video_mem_base < offset + video_screen_size)
+		offset = 0;
+	memcpyw((unsigned short *)(video_mem_base + offset),
+		(unsigned short *) origin, video_screen_size);
+	video_mem_start = video_mem_base;
+	video_mem_end = video_mem_term;
+	origin = video_mem_base + offset;
+	scr_end = origin + video_screen_size;
+	pos = origin + y*video_size_row + (x<<1);
+}
+
+int
+set_get_cmap(unsigned char *p, int set)
+{
+	int i, j, err;
+
+	err = verify_area(set? VERIFY_READ: VERIFY_WRITE, p, 48);
+	if (err)
+		return err;
+
+	for (i = 0; i < 16; ++i) {
+		if (set) {
+			get_user(default_red[i], p++);
+			get_user(default_grn[i], p++);
+			get_user(default_blu[i], p++);
+		} else {
+			put_user(default_red[i], p++);
+			put_user(default_grn[i], p++);
+			put_user(default_blu[i], p++);
+		}
+	}
+
+	if (set) {
+		for (j = 0; j < MAX_NR_CONSOLES; ++j) {
+			if (!vc_cons_allocated(j))
+				continue;
+			for (i = 0; i < 16; ++i) {
+				vc_cons[j].d->vc_palette[3*i+0] = default_red[i];
+				vc_cons[j].d->vc_palette[3*i+1] = default_grn[i];
+				vc_cons[j].d->vc_palette[3*i+2] = default_blu[i];
+			}
+		}
+		set_palette();
+	}
+
+	return 0;
+}
+
+int
+set_get_font(char *p, int set, int ch512)
+{
+	return 0;
+}
+
+void
+set_palette()
+{
+	int i, j, n;
+	unsigned char red[16], green[16], blue[16];
+
+	if (console_blanked || current_display == NULL
+	    || current_display->set_palette == NULL
+	    || vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
+		return;
+
+	for (i = j = 0; i < 16; ++i) {
+		n = color_table[i] & 0xf;
+		red[n] = vc_cons[fg_console].d->vc_palette[j++];
+		green[n] = vc_cons[fg_console].d->vc_palette[j++];
+		blue[n] = vc_cons[fg_console].d->vc_palette[j++];
+	}
+	(*current_display->set_palette)(red, green, blue, 0, 16);
+}
+
+void
+pmac_init_palette()
+{
+	int i, n;
+	unsigned char red[16], green[16], blue[16];
+
+	for (i = 0; i < 16; ++i) {
+		n = color_table[i] & 0xf;
+		red[n] = default_red[i];
+		green[n] = default_grn[i];
+		blue[n] = default_blu[i];
+	}
+	(*current_display->set_palette)(red, green, blue, 0, 16);
+}
+
+static int vesa_blanking_mode;
+static int vesa_blanked;
+
+void
+vesa_blank()
+{
+	if (vesa_blanking_mode == 0 || vesa_blanked
+	    || current_display == NULL
+	    || current_display->set_blanking == NULL)
+		return;
+	(*current_display->set_blanking)(vesa_blanking_mode);
+	vesa_blanked = vesa_blanking_mode;
+}
+
+void
+vesa_unblank()
+{
+	if (vesa_blanked == 0
+	    || current_display == NULL
+	    || current_display->set_blanking == NULL)
+		return;
+	(*current_display->set_blanking)(VESA_NO_BLANKING);
+	vesa_blanked = VESA_NO_BLANKING;
+}
+
+void
+set_vesa_blanking(const unsigned long arg)
+{
+	unsigned char *argp = (unsigned char *)(arg + 1);
+	unsigned int mode;
+
+	if (verify_area(VERIFY_READ, argp, 1))
+		return;
+
+	get_user(mode, argp);
+	vesa_blanking_mode = (mode <= VESA_POWERDOWN)? mode: \
+		DEFAULT_VESA_BLANKING_MODE;
+}
+
+void
+vesa_powerdown()
+{
+	if (vesa_blanked == 0 || vesa_blanked == VESA_POWERDOWN
+	    || current_display == NULL
+	    || current_display->set_blanking == NULL)
+		return;
+	(*current_display->set_blanking)(VESA_POWERDOWN);
+	vesa_blanked = VESA_POWERDOWN;
+}
+
+void
+memsetw(unsigned short *p, unsigned short c, unsigned count)
+{
+	count /= 2;
+	if ((unsigned long)(p + count) > video_mem_base
+	    && (unsigned long)p < video_mem_term) {
+		for (; p < (unsigned short *) video_mem_base && count != 0; --count)
+			*p++ = c;
+		for (; p < (unsigned short *) video_mem_term && count != 0; --count) {
+			if (*p != c) {
+				*p = c;
+				pmac_blitc(c, (unsigned long)p);
+			}
+			++p;
+		}
+	}
+	for (; count != 0; --count)
+		*p++ = c;
+}
+
+void
+memcpyw(unsigned short *to, unsigned short *from, unsigned count)
+{
+	unsigned short c;
+
+	count /= 2;
+	if ((unsigned long)(to + count) > video_mem_base
+	    && (unsigned long)to < video_mem_term) {
+		for (; to < (unsigned short *) video_mem_base && count != 0; --count)
+			*to++ = *from++;
+		for (; to < (unsigned short *) video_mem_term && count != 0; --count) {
+			c = *from++;
+			if (*to != c) {
+				*to = c;
+				pmac_blitc(c, (unsigned long)to);
+			}
+			++to;
+		}
+	}
+	for (; count != 0; --count)
+		*to++ = *from++;
+}
+
+void
+pmac_find_display()
+{
+	struct display_interface *disp;
+	struct device_node *dp;
+	struct vmode_attr *ap;
+
+	current_display = NULL;
+	if (serial_console) 
+		return;
+	for (disp = displays; disp->name != NULL; ++disp) {
+		dp = find_devices(disp->name);
+		if (dp == 0)
+			continue;
+		current_display = disp;
+		disp->map_interface(dp);
+		break;
+	}
+
+	if (current_display == NULL) {
+		/*
+		 * We haven't found a display that we know about,
+		 * but if there is a display with sufficient prom support,
+		 * we may be able to use it in a limited fashion.
+		 * If there is, it has already been opened in prom_init().
+		 */
+		if (prom_display_path[0] != 0) {
+			dp = find_path_device(prom_display_path);
+			if (dp != 0 && map_unknown(dp))
+				current_display = &unknown_display;
+			else
+				printk(KERN_INFO "Can't use %s for display\n",
+				       prom_display_path);
+		}
+	}
+
+	if (current_display == NULL
+	    || video_mode <= 0 || video_mode > VMODE_MAX) {
+		printk(KERN_INFO "No usable display device found"
+		       "- using serial console\n");
+		serial_console = 1;	/* no screen - fall back to serial */
+		return;
+	}
+	ap = &vmode_attrs[video_mode - 1];
+	screen_info.orig_video_cols = ap->hres / 8;
+	screen_info.orig_video_lines = ap->vres / 16;
+	printk("using video mode %d (%dx%d at %dHz%s), %d bits/pixel\n",
+	       video_mode, ap->hres, ap->vres, ap->vfreq,
+	       ap->interlaced? " interlaced": "",
+	       (color_mode + 1) * 8);
+}
+
+int
+pmac_display_supported(const char *name)
+{
+	struct display_interface *disp;
+
+	for (disp = displays; disp->name != NULL; ++disp)
+		if (strcmp(name, disp->name) == 0)
+			return 1;
+	return 0;
+}
+
+int
+console_getmode(struct vc_mode *mode)
+{
+	*mode = display_info;
+	return 0;
+}
+
+int
+console_setmode(struct vc_mode *mode, int doit)
+{
+	int err;
+
+	if (current_display == NULL || current_display->setmode == NULL)
+		return -EINVAL;
+	err = (*current_display->setmode)(mode, doit);
+	if (doit && err == 0)
+		memset((void *)video_mem_base, 0, video_screen_size);
+	return err;
+}
+
+int
+console_powermode(int mode)
+{
+	if (mode == VC_POWERMODE_INQUIRY)
+		return vesa_blanked;
+	if (mode < VESA_NO_BLANKING || mode > VESA_POWERDOWN)
+		return -EINVAL;
+	if (current_display == NULL || current_display->set_blanking == NULL)
+		return -ENXIO;
+	(*current_display->set_blanking)(mode);
+	vesa_blanked = mode;
+	return 0;
+}
+
+void
+pmac_cons_setup(char *str, int *ints)
+{
+	if (strcmp(str, "ttya") == 0 || strcmp(str, "modem") == 0)
+		serial_console = 1;
+	else if (strcmp(str, "ttyb") == 0 || strcmp(str, "printer") == 0)
+		serial_console = 2;
+}
+
+void
+pmac_vmode_setup(char *str, int *ints)
+{
+	if (ints[0] >= 1)
+		video_mode = ints[1];
+	if (ints[0] >= 2)
+		color_mode = ints[2];
+}
+
+unsigned long
+con_type_init(unsigned long mem_start, const char **type_p)
+{
+	if (current_display == NULL)
+		panic("no display available");
+	current_display->init_interface();
+	screen_initialized = 1;		/* inhibits prom_print */
+	can_do_color = 1;
+	video_type = VIDEO_TYPE_PMAC;
+	*type_p = display_info.name;
+	video_mem_base = mem_start;
+	mem_start += MAX_TEXT_COLS * MAX_TEXT_ROWS * 2;
+	video_mem_term = mem_start;
+	memset((char *) video_mem_base, 0, video_screen_size);
+	return mem_start;
+}
+
+static __inline__ void
+draw_logo_8(void)
+{
+	unsigned char *fb = fb_start;
+	unsigned char *p = linux_logo;
+	int yy;
+
+	(*current_display->set_palette)
+		(linux_logo_red, linux_logo_green, linux_logo_blue,
+		 32, LINUX_LOGO_COLORS);
+
+	for (yy = 0; yy < LINUX_LOGO_HEIGHT; ++yy) {
+		memcpy(fb, p, LINUX_LOGO_WIDTH);
+		fb += line_pitch;
+		p += LINUX_LOGO_WIDTH;
+	}
+}
+
+static __inline__ void
+draw_logo_15(void)
+{
+	unsigned short *fb;
+	unsigned char *row = fb_start;
+	unsigned char *p = linux_logo;
+	int i, xx, yy;
+	unsigned char grey[16];
+
+	/*
+	 * For 15-bit mode, treat the screen as a 4/4/4 TrueColor.
+	 */
+	for (i = 0; i < 16; ++i)
+		grey[i] = i << 4;
+	(*current_display->set_palette)(grey, grey, grey, 16, 16);
+
+	for (yy = 0; yy < LINUX_LOGO_HEIGHT; ++yy) {
+		fb = (unsigned short *) row;
+		for (xx = 0; xx < LINUX_LOGO_WIDTH; ++xx) {
+			i = *p++ - 32;
+			*fb++ = 0x4210
+				+ ((linux_logo_red[i] & 0xf0) << 6)
+				+ ((linux_logo_green[i] & 0xf0) << 1)
+				+ (linux_logo_blue[i] >> 4);
+		}
+		row += line_pitch;
+	}
+}
+
+static __inline__ void
+draw_logo_24(void)
+{
+	unsigned long *fb;
+	unsigned char *row = fb_start;
+	unsigned char *p = linux_logo;
+	int xx, yy, v;
+
+	(*current_display->set_palette)
+		(linux_logo_red, linux_logo_green, linux_logo_blue,
+		 32, LINUX_LOGO_COLORS);
+
+	for (yy = 0; yy < LINUX_LOGO_HEIGHT; ++yy) {
+		fb = (unsigned long *) row;
+		for (xx = 0; xx < LINUX_LOGO_WIDTH; ++xx) {
+			v = *p++;
+			v |= v << 8;
+			v |= v << 16;
+			*fb++ = v;
+		}
+		row += line_pitch;
+	}
+}
+
+void
+con_type_init_finish(void)
+{
+	char *p;
+	int c;
+	unsigned short *addr;
+	char xy[2];
+	int currcons = 0;	/* for `attr', which is a macro */
+
+	if (current_display == NULL
+	    || current_display->set_palette == NULL)
+		return;
+
+	switch (color_mode) {
+	case CMODE_8:
+		draw_logo_8();
+		break;
+
+	case CMODE_16:
+		draw_logo_15();
+		break;
+
+	case CMODE_32:
+		draw_logo_24();
+		break;
+	}
+	xy[0] = 0;
+	xy[1] = (LINUX_LOGO_HEIGHT + 16) / 16;
+	putconsxy(0, xy);
+
+	p = "PowerMac/Linux " UTS_RELEASE;
+	addr = (unsigned short *) video_mem_base + 2 * video_num_columns
+		+ LINUX_LOGO_WIDTH / 8 + 8;
+	for (; *p; ++p) {
+		c = (attr << 8) + *p;
+		scr_writew(c, addr);
+		++addr;
+	}
+}
+
+int
+con_adjust_height(unsigned long height)
+{
+	return -EINVAL;
+}
+
+static unsigned long expand_bits_8[16] = {
+	0x00000000,
+	0x000000ff,
+	0x0000ff00,
+	0x0000ffff,
+	0x00ff0000,
+	0x00ff00ff,
+	0x00ffff00,
+	0x00ffffff,
+	0xff000000,
+	0xff0000ff,
+	0xff00ff00,
+	0xff00ffff,
+	0xffff0000,
+	0xffff00ff,
+	0xffffff00,
+	0xffffffff
+};
+
+static unsigned long expand_bits_16[4] = {
+	0x00000000,
+	0x0000ffff,
+	0xffff0000,
+	0xffffffff
+};
+
+void
+pmac_blitc(unsigned charattr, unsigned long addr)
+{
+	int col, row, fg, bg, l, bits;
+	unsigned char *fp;
+	unsigned long *fb;
+	static int cached_row_start, cached_row_end = -1;
+	static unsigned char *cached_fb;
+	static int cached_attr = -1;
+	static unsigned long cached_fg, cached_bg;
+
+	col = (addr - video_mem_base) / 2;
+	if (cursor_pos == col)
+		cursor_pos = -1;
+	if (!(col >= cached_row_start && col < cached_row_end)) {
+		row = col / video_num_columns;
+		cached_row_start = row * video_num_columns;
+		cached_row_end = cached_row_start + video_num_columns;
+		cached_fb = fb_start + row * row_pitch;
+	}
+	fb = (unsigned long *)
+		(cached_fb + (col - cached_row_start) * pixel_size * 8);
+
+	if ((charattr & 0xff00) != cached_attr) {
+		fg = (charattr >> 8) & 0xf;
+		bg = (charattr >> 12) & 0xf;
+		switch (color_mode) {
+		case CMODE_16:
+			fg = pixel16(fg_console, fg);
+			bg = pixel16(fg_console, bg);
+			break;
+		default:
+			fg += fg << 8;
+			fg += fg << 16;
+			bg += bg << 8;
+			bg += bg << 16;
+		}
+		fg ^= bg;
+		cached_fg = fg;
+		cached_bg = bg;
+	} else {
+		fg = cached_fg;
+		bg = cached_bg;
+	}
+
+	fp = &vga_font[(charattr & 0xff) * 16];
+	switch (color_mode) {
+	case CMODE_32:
+		for (l = 0; l < 16; ++l) {
+			bits = *fp++;
+			fb[0] = (-(bits >> 7) & fg) ^ bg;
+			fb[1] = (-((bits >> 6) & 1) & fg) ^ bg;
+			fb[2] = (-((bits >> 5) & 1) & fg) ^ bg;
+			fb[3] = (-((bits >> 4) & 1) & fg) ^ bg;
+			fb[4] = (-((bits >> 3) & 1) & fg) ^ bg;
+			fb[5] = (-((bits >> 2) & 1) & fg) ^ bg;
+			fb[6] = (-((bits >> 1) & 1) & fg) ^ bg;
+			fb[7] = (-(bits & 1) & fg) ^ bg;
+			fb = (unsigned long *) ((char *)fb + line_pitch);
+		}
+		break;
+	case CMODE_16:
+		for (l = 0; l < 16; ++l) {
+			bits = *fp++;
+			fb[0] = (expand_bits_16[bits >> 6] & fg) ^ bg;
+			fb[1] = (expand_bits_16[(bits >> 4) & 3] & fg) ^ bg;
+			fb[2] = (expand_bits_16[(bits >> 2) & 3] & fg) ^ bg;
+			fb[3] = (expand_bits_16[bits & 3] & fg) ^ bg;
+			fb = (unsigned long *) ((char *)fb + line_pitch);
+		}
+		break;
+	default:
+		for (l = 0; l < 16; ++l) {
+			bits = *fp++;
+			fb[0] = (expand_bits_8[bits >> 4] & fg) ^ bg;
+			fb[1] = (expand_bits_8[bits & 0xf] & fg) ^ bg;
+			fb = (unsigned long *) ((char *)fb + line_pitch);
+		}
+	}
+}
+
+
+/*
+ * The following provides a very basic screen driver for displays
+ * that we basically don't know anything about, but which we can
+ * initialize by using their Open Firmware "open" method.
+ */
+
+static int unknown_modes[] = {
+	VMODE_512_384_60,
+	VMODE_640_480_60,
+	VMODE_800_600_60,
+	VMODE_832_624_75,
+	VMODE_1024_768_60,
+	VMODE_1152_870_75,
+	VMODE_1280_960_75,
+	VMODE_1280_1024_75,
+	0
+};
+
+static unsigned char *frame_buffer;
+
+static int map_unknown(struct device_node *dp)
+{
+	int i, mode;
+	int width;
+	int *pp, len;
+	unsigned *up, address;
+
+	printk("map_unknown(%p), name = %s\n", dp, dp->full_name);
+
+	/* check the depth */
+	if ((pp = (int *) get_property(dp, "depth", &len)) != NULL
+	    && len == sizeof(int) && *pp != 8) {
+		printk("%s: can't use depth = %d\n", dp->full_name, *pp);
+		return 0;
+	}
+
+	width = 640;		/* default values */
+	n_scanlines = 480;
+	if ((pp = (int *) get_property(dp, "width", &len)) != NULL
+	    && len == sizeof(int))
+		width = *pp;
+	if ((pp = (int *) get_property(dp, "height", &len)) != NULL
+	    && len == sizeof(int))
+		n_scanlines = *pp;
+	line_pitch = width;
+	if ((pp = (int *) get_property(dp, "linebytes", &len)) != NULL
+	    && len == sizeof(int))
+		line_pitch = *pp;
+	printk(KERN_INFO "width=%d height=%d pitch=%d\n",
+	       width, n_scanlines, line_pitch);
+
+	len = n_scanlines * line_pitch;
+	if ((up = (unsigned *) get_property(dp, "address", &len)) != NULL
+	    && len == sizeof(unsigned)) {
+		address = *up;
+	} else {
+		for (i = 0; i < dp->n_addrs; ++i)
+			if (dp->addrs[i].size >= len)
+				break;
+		if (i >= dp->n_addrs) {
+			printk("no framebuffer address found for %s\n",
+			       dp->full_name);
+			return 0;
+		}
+		address = dp->addrs[i].address;
+		/* temporary kludge for valkyrie */
+		if (strcmp(dp->name, "valkyrie") == 0)
+			address += 0x1000;
+	}
+	printk(KERN_INFO "%s: using address %x\n", dp->full_name, address);
+	frame_buffer = ioremap(address, len);
+
+	video_mode = 0;
+	color_mode = CMODE_8;
+	pixel_size = 1;
+
+	for (i = 0; (mode = unknown_modes[i]) != 0; ++i) {
+		if (vmode_attrs[mode-1].hres <= width
+		    && vmode_attrs[mode-1].vres <= n_scanlines)
+			video_mode = mode;
+	}
+	if (video_mode == 0) {
+		printk(KERN_INFO "%s: no mode found for %d x %d\n",
+		       dp->full_name, width, n_scanlines);
+		return 0;
+	}
+
+	display_info.height = n_scanlines;
+	display_info.width = width;
+	display_info.depth = 8;
+	display_info.pitch = line_pitch;
+	display_info.mode = video_mode;
+	strncpy(display_info.name, dp->name, sizeof(display_info.name));
+	display_info.fb_address = (unsigned long) frame_buffer;
+	display_info.cmap_adr_address = 0;
+	display_info.cmap_data_address = 0;
+	display_info.disp_reg_address = 0;
+
+	return 1;
+}
+
+static void
+unknown_init()
+{
+	unsigned *p;
+	int i;
+
+	row_pitch = line_pitch * 16;
+	fb_start = frame_buffer;
+
+	/* Clear screen */
+	p = (unsigned *) frame_buffer;
+	for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
+		*p++ = 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, 
+};
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/pmac-cons.h linux/drivers/macintosh/pmac-cons.h
--- v2.1.50/linux/drivers/macintosh/pmac-cons.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/pmac-cons.h	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,90 @@
+/*
+ * Definitions for display drivers for console use on PowerMacs.
+ *
+ * Copyright (C) 1997 Paul Mackerras.
+ *	
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+extern int serial_console;	/* set to use serial port as console */
+
+/*
+ * Video mode values.
+ * These are supposed to be the same as the values that
+ * Apple uses in MacOS.
+ */
+#define VMODE_NVRAM		0	/* use value stored in nvram */
+#define VMODE_512_384_60I	1	/* 512x384, 60Hz interlaced (NTSC) */
+#define VMODE_512_384_60	2	/* 512x384, 60Hz */
+#define VMODE_640_480_50I	3	/* 640x480, 50Hz interlaced (PAL) */
+#define VMODE_640_480_60I	4	/* 640x480, 60Hz interlaced (NTSC) */
+#define VMODE_640_480_60	5	/* 640x480, 60Hz (VGA) */
+#define VMODE_640_480_67	6	/* 640x480, 67Hz */
+#define VMODE_640_870_75P	7	/* 640x870, 75Hz (portrait) */
+#define VMODE_768_576_50I	8	/* 768x576, 50Hz (PAL full frame) */
+#define VMODE_800_600_56	9	/* 800x600, 56Hz */
+#define VMODE_800_600_60	10	/* 800x600, 60Hz */
+#define VMODE_800_600_72	11	/* 800x600, 72Hz */
+#define VMODE_800_600_75	12	/* 800x600, 75Hz */
+#define VMODE_832_624_75	13	/* 832x624, 75Hz */
+#define VMODE_1024_768_60	14	/* 1024x768, 60Hz */
+#define VMODE_1024_768_70	15	/* 1024x768, 70Hz (or 72Hz?) */
+#define VMODE_1024_768_75V	16	/* 1024x768, 75Hz (VESA) */
+#define VMODE_1024_768_75	17	/* 1024x768, 75Hz */
+#define VMODE_1152_870_75	18	/* 1152x870, 75Hz */
+#define VMODE_1280_960_75	19	/* 1280x960, 75Hz */
+#define VMODE_1280_1024_75	20	/* 1280x1024, 75Hz */
+#define VMODE_MAX		20
+#define VMODE_CHOOSE		99	/* choose based on monitor sense */
+
+/*
+ * Color mode values, used to select number of bits/pixel.
+ */
+#define CMODE_NVRAM		-1	/* use value stored in nvram */
+#define CMODE_8			0	/* 8 bits/pixel */
+#define CMODE_16		1	/* 16 (actually 15) bits/pixel */
+#define CMODE_32		2	/* 32 (actually 24) bits/pixel */
+
+extern int video_mode;
+extern int color_mode;
+
+/*
+ * Addresses in NVRAM where video mode and pixel size are stored.
+ */
+#define NV_VMODE	0x140f
+#define NV_CMODE	0x1410
+
+/*
+ * Horizontal and vertical resolution information.
+ */
+extern struct vmode_attr {
+	int	hres;
+	int	vres;
+	int	vfreq;
+	int	interlaced;
+} vmode_attrs[VMODE_MAX];
+
+extern struct vc_mode display_info;
+
+#define DEFAULT_VESA_BLANKING_MODE	VESA_NO_BLANKING
+
+extern int pixel_size;		/* in bytes */
+extern int n_scanlines;		/* # of scan lines */
+extern int line_pitch;		/* # bytes in 1 scan line */
+extern int row_pitch;		/* # bytes in 1 row of characters */
+extern unsigned char *fb_start;	/* addr of top left pixel of top left char */
+
+/* map monitor sense value to video mode */
+extern int map_monitor_sense(int sense);
+
+void set_palette(void);
+void pmac_find_display(void);
+void vesa_blank(void);
+void vesa_unblank(void);
+void set_vesa_blanking(const unsigned long);
+void vesa_powerdown(void);
+void hide_cursor(void);
+void pmac_init_palette(void);
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/valkyrie.c linux/drivers/macintosh/valkyrie.c
--- v2.1.50/linux/drivers/macintosh/valkyrie.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/valkyrie.c	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,321 @@
+/*
+ * valkyrie.c: Console support for PowerMac "valkyrie" display adaptor.
+ *
+ * Copyright (C) 1997 Paul Mackerras.
+ *	
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/vc_ioctl.h>
+#include <linux/nvram.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/cuda.h>
+#include <linux/selection.h>
+#include "pmac-cons.h"
+#include "valkyrie.h"
+
+/*
+ * Structure of the registers for the Valkyrie colormap registers.
+ */
+struct cmap_regs {
+	unsigned char addr;
+	char pad1[7];
+	unsigned char lut;
+};
+
+/*
+ * Structure of the registers for the "valkyrie" display adaptor.
+ */
+#define PAD(x)	char x[7]
+
+struct valkyrie_regs {
+	unsigned char mode;
+	PAD(pad0);
+	unsigned char depth;
+	PAD(pad1);
+	unsigned char status;
+	PAD(pad2);
+	unsigned char reg3;
+	PAD(pad3);
+	unsigned char intr;
+	PAD(pad4);
+	unsigned char reg5;
+	PAD(pad5);
+	unsigned char intr_enb;
+	PAD(pad6);
+	unsigned char msense;
+	PAD(pad7);
+};
+
+static void set_valkyrie_clock(unsigned char *params);
+static int read_valkyrie_sense(void);
+
+static unsigned char *frame_buffer;
+static struct cmap_regs *cmap_regs;
+static struct valkyrie_regs *disp_regs;
+
+/*
+ * Register initialization tables for the valkyrie display.
+ *
+ * Dot clock rate is
+ * 3.9064MHz * 2**clock_params[2] * clock_params[1] / clock_params[0].
+ */
+struct valkyrie_regvals {
+	unsigned char mode;
+	unsigned char clock_params[3];
+	int	pitch[2];		/* bytes/line, indexed by color_mode */
+};
+
+/* Register values for 1024x768, 72Hz mode (15) */
+static struct valkyrie_regvals valkyrie_reg_init_15 = {
+	15,
+	{ 12, 30, 3 },	/* pixel clock = 78.12MHz for V=72.12Hz */
+	{ 1024, 0 }
+};
+
+/* Register values for 1024x768, 60Hz mode (14) */
+static struct valkyrie_regvals valkyrie_reg_init_14 = {
+	14,
+	{ 15, 31, 3 },	/* pixel clock = 64.58MHz for V=59.62Hz */
+	{ 1024, 0 }
+};
+
+/* Register values for 832x624, 75Hz mode (13) */
+static struct valkyrie_regvals valkyrie_reg_init_13 = {
+	9,
+	{ 23, 42, 3 },	/* pixel clock = 57.07MHz for V=74.27Hz */
+	{ 832, 0 }
+};
+
+/* Register values for 800x600, 72Hz mode (11) */
+static struct valkyrie_regvals valkyrie_reg_init_11 = {
+	13,
+	{ 17, 27, 3 },	/* pixel clock = 49.63MHz for V=71.66Hz */
+	{ 800, 0 }
+};
+
+/* Register values for 800x600, 60Hz mode (10) */
+static struct valkyrie_regvals valkyrie_reg_init_10 = {
+	12,
+	{ 20, 53, 2 },	/* pixel clock = 41.41MHz for V=59.78Hz */
+	{ 800, 0 }
+};
+
+/* Register values for 640x480, 67Hz mode (6) */
+static struct valkyrie_regvals valkyrie_reg_init_6 = {
+	6,
+	{ 14, 27, 2 },	/* pixel clock = 30.13MHz for V=66.43Hz */
+	{ 640, 1280 }
+};
+
+/* Register values for 640x480, 60Hz mode (5) */
+static struct valkyrie_regvals valkyrie_reg_init_5 = {
+	11,
+	{ 23, 37, 2 },	/* pixel clock = 25.14MHz for V=59.85Hz */
+	{ 640, 1280 }
+};
+
+static struct valkyrie_regvals *valkyrie_reg_init[20] = {
+	NULL, NULL, NULL, NULL,
+	&valkyrie_reg_init_5,
+	&valkyrie_reg_init_6,
+	NULL, NULL, NULL,
+	&valkyrie_reg_init_10,
+	&valkyrie_reg_init_11,
+	NULL,
+	&valkyrie_reg_init_13,
+	&valkyrie_reg_init_14,
+	&valkyrie_reg_init_15,
+	NULL, NULL, NULL, NULL, NULL
+};
+
+/*
+ * Get the monitor sense value.
+ */
+static int
+read_valkyrie_sense()
+{
+	int sense;
+
+	out_8(&disp_regs->msense, 0);	/* release all lines */
+	__delay(20000);
+	sense = (in_8(&disp_regs->msense) & 0x70) << 4;
+
+	/* drive each sense line low in turn and collect the other 2 */
+	out_8(&disp_regs->msense, 4);	/* drive A low */
+	__delay(20000);
+	sense |= in_8(&disp_regs->msense) & 0x30;
+	out_8(&disp_regs->msense, 2);	/* drive B low */
+	__delay(20000);
+	sense |= ((in_8(&disp_regs->msense) & 0x40) >> 3)
+		| ((in_8(&disp_regs->msense) & 0x10) >> 2);
+	out_8(&disp_regs->msense, 1);	/* drive C low */
+	__delay(20000);
+	sense |= (in_8(&disp_regs->msense) & 0x60) >> 5;
+
+	out_8(&disp_regs->msense, 7);
+	return sense;
+}
+
+void
+map_valkyrie_display(struct device_node *dp)
+{
+	int sense;
+	unsigned long addr;
+
+	if (dp->next != 0)
+		printk("Warning: only using first valkyrie display device\n");
+	if (dp->n_addrs != 1)
+		panic("expecting 1 address for valkyrie (got %d)", dp->n_addrs);
+
+	/* Map in frame buffer and registers */
+	addr = dp->addrs[0].address;
+	frame_buffer = ioremap(addr, 0x100000);
+	disp_regs = ioremap(addr + 0x30a000, 4096);
+	cmap_regs = ioremap(addr + 0x304000, 4096);
+
+	/* Read the monitor sense value and choose the video mode */
+	sense = read_valkyrie_sense();
+	if (video_mode == VMODE_NVRAM) {
+		video_mode = nvram_read_byte(NV_VMODE);
+		if (video_mode <= 0 || video_mode > VMODE_MAX
+		    || valkyrie_reg_init[video_mode-1] == 0)
+			video_mode = VMODE_CHOOSE;
+	}
+	if (video_mode == VMODE_CHOOSE)
+		video_mode = map_monitor_sense(sense);
+	if (valkyrie_reg_init[video_mode-1] == 0)
+		video_mode = VMODE_640_480_60;
+
+	/*
+	 * Reduce the pixel size if we don't have enough VRAM.
+	 */
+	if (color_mode == CMODE_NVRAM)
+		color_mode = nvram_read_byte(NV_CMODE);
+	if (color_mode < CMODE_8 || color_mode > CMODE_16
+	    || valkyrie_reg_init[video_mode-1]->pitch[color_mode] == 0)
+		color_mode = CMODE_8;
+
+	printk("Monitor sense value = 0x%x, ", sense);
+}
+
+static void
+set_valkyrie_clock(unsigned char *params)
+{
+	struct cuda_request req;
+	int i;
+
+	for (i = 0; i < 3; ++i) {
+		cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC,
+			     0x50, i + 1, params[i]);
+		while (!req.got_reply)
+			cuda_poll();
+	}
+}
+
+void
+valkyrie_init()
+{
+	int i, yoff, hres;
+	unsigned *p;
+	struct valkyrie_regvals *init;
+
+	if (video_mode <= 0 || video_mode > VMODE_MAX
+	    || (init = valkyrie_reg_init[video_mode-1]) == 0)
+		panic("valkyrie: display mode %d not supported", video_mode);
+	n_scanlines = vmode_attrs[video_mode-1].vres;
+	hres = vmode_attrs[video_mode-1].hres;
+	pixel_size = 1 << color_mode;
+	line_pitch = init->pitch[color_mode];
+	row_pitch = line_pitch * 16;
+
+	/* Reset the valkyrie */
+	out_8(&disp_regs->status, 0);
+	udelay(100);
+
+	/* Initialize display timing registers */
+	out_8(&disp_regs->mode, init->mode | 0x80);
+	out_8(&disp_regs->depth, color_mode + 3);
+	set_valkyrie_clock(init->clock_params);
+	udelay(100);
+
+	pmac_init_palette();	/* Initialize colormap */
+
+	/* Turn on display */
+	out_8(&disp_regs->mode, init->mode);
+
+	yoff = (n_scanlines % 16) / 2;
+	fb_start = frame_buffer + yoff * line_pitch + 0x1000;
+
+	/* Clear screen */
+	p = (unsigned *) (frame_buffer + 0x1000);
+	for (i = n_scanlines * line_pitch / sizeof(unsigned); i != 0; --i)
+		*p++ = 0;
+
+	display_info.height = n_scanlines;
+	display_info.width = hres;
+	display_info.depth = pixel_size * 8;
+	display_info.pitch = line_pitch;
+	display_info.mode = video_mode;
+	strncpy(display_info.name, "valkyrie", sizeof(display_info.name));
+	display_info.fb_address = (unsigned long) frame_buffer + 0x1000;
+	display_info.cmap_adr_address = (unsigned long) &cmap_regs->addr;
+	display_info.cmap_data_address = (unsigned long) &cmap_regs->lut;
+	display_info.disp_reg_address = (unsigned long) &disp_regs;
+}
+
+int
+valkyrie_setmode(struct vc_mode *mode, int doit)
+{
+	int cmode;
+
+	switch (mode->depth) {
+	case 16:
+		cmode = CMODE_16;
+		break;
+	case 8:
+	case 0:		/* (default) */
+		cmode = CMODE_8;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (mode->mode <= 0 || mode->mode > VMODE_MAX
+	    || valkyrie_reg_init[mode->mode-1] == 0
+	    || valkyrie_reg_init[mode->mode-1]->pitch[cmode] == 0)
+		return -EINVAL;
+	if (doit) {
+		video_mode = mode->mode;
+		color_mode = cmode;
+		valkyrie_init();
+	}
+	return 0;
+}
+
+void
+valkyrie_set_palette(unsigned char red[], unsigned char green[],
+		    unsigned char blue[], int index, int ncolors)
+{
+	int i;
+
+	for (i = 0; i < ncolors; ++i) {
+		out_8(&cmap_regs->addr, index + i);
+		udelay(1);
+		out_8(&cmap_regs->lut, red[i]);
+		out_8(&cmap_regs->lut, green[i]);
+		out_8(&cmap_regs->lut, blue[i]);
+	}
+}
+
+void
+valkyrie_set_blanking(int blank_mode)
+{
+	/* don't know how to do this yet */
+}
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/valkyrie.h linux/drivers/macintosh/valkyrie.h
--- v2.1.50/linux/drivers/macintosh/valkyrie.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/valkyrie.h	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,17 @@
+/*
+ * Exported procedures for the "valkyrie" display driver on PowerMacs.
+ *
+ * Copyright (C) 1997 Paul Mackerras.
+ *	
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+extern void map_valkyrie_display(struct device_node *);
+extern void valkyrie_init(void);
+extern int valkyrie_setmode(struct vc_mode *mode, int doit);
+extern void valkyrie_set_palette(unsigned char red[], unsigned char green[],
+				 unsigned char blue[], int index, int ncolors);
+extern void valkyrie_set_blanking(int blank_mode);
diff -u --recursive --new-file v2.1.50/linux/drivers/macintosh/via-cuda.c linux/drivers/macintosh/via-cuda.c
--- v2.1.50/linux/drivers/macintosh/via-cuda.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/macintosh/via-cuda.c	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,415 @@
+/*
+ * Device driver for the via-cuda on Apple Powermacs.
+ *
+ * The VIA (versatile interface adapter) interfaces to the CUDA,
+ * a 6805 microprocessor core which controls the ADB (Apple Desktop
+ * Bus) which connects to the keyboard and mouse.  The CUDA also
+ * controls system power and the RTC (real time clock) chip.
+ *
+ * This file also contains routines to support access to ADB
+ * devices via the /dev/adb interface.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <asm/prom.h>
+#include <asm/cuda.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+static volatile unsigned char *via;
+
+/* VIA registers - spaced 0x200 bytes apart */
+#define RS		0x200		/* skip between registers */
+#define B		0		/* B-side data */
+#define A		RS		/* A-side data */
+#define DIRB		(2*RS)		/* B-side direction (1=output) */
+#define DIRA		(3*RS)		/* A-side direction (1=output) */
+#define T1CL		(4*RS)		/* Timer 1 ctr/latch (low 8 bits) */
+#define T1CH		(5*RS)		/* Timer 1 counter (high 8 bits) */
+#define T1LL		(6*RS)		/* Timer 1 latch (low 8 bits) */
+#define T1LH		(7*RS)		/* Timer 1 latch (high 8 bits) */
+#define T2CL		(8*RS)		/* Timer 2 ctr/latch (low 8 bits) */
+#define T2CH		(9*RS)		/* Timer 2 counter (high 8 bits) */
+#define SR		(10*RS)		/* Shift register */
+#define ACR		(11*RS)		/* Auxiliary control register */
+#define PCR		(12*RS)		/* Peripheral control register */
+#define IFR		(13*RS)		/* Interrupt flag register */
+#define IER		(14*RS)		/* Interrupt enable register */
+#define ANH		(15*RS)		/* A-side data, no handshake */
+
+/* Bits in B data register: all active low */
+#define TREQ		0x08		/* Transfer request (input) */
+#define TACK		0x10		/* Transfer acknowledge (output) */
+#define TIP		0x20		/* Transfer in progress (output) */
+
+/* Bits in ACR */
+#define SR_CTRL		0x1c		/* Shift register control bits */
+#define SR_EXT		0x0c		/* Shift on external clock */
+#define SR_OUT		0x10		/* Shift out if 1 */
+
+/* Bits in IFR and IER */
+#define IER_SET		0x80		/* set bits in IER */
+#define IER_CLR		0		/* clear bits in IER */
+#define SR_INT		0x04		/* Shift register full/empty */
+
+static struct adb_handler {
+    void (*handler)(unsigned char *, int, struct pt_regs *);
+} adb_handler[16];
+
+static enum cuda_state {
+    idle,
+    sent_first_byte,
+    sending,
+    reading,
+    read_done,
+    awaiting_reply
+} cuda_state;
+
+static struct cuda_request *current_req;
+static struct cuda_request *last_req;
+static unsigned char cuda_rbuf[16];
+static unsigned char *reply_ptr;
+static int reading_reply;
+static int data_index;
+
+static int init_via(void);
+static void cuda_start(void);
+static void via_interrupt(int irq, void *arg, struct pt_regs *regs);
+static void cuda_input(unsigned char *buf, int nb, struct pt_regs *regs);
+
+void
+via_cuda_init()
+{
+    struct device_node *vias;
+
+    vias = find_devices("via-cuda");
+    if (vias == 0) {
+	printk(KERN_WARNING "Warning: no via-cuda\n");
+	vias = find_devices("via-pmu");
+	if (vias == 0)
+	    return;
+	printk(KERN_WARNING "Found via-pmu, using it as via-cuda\n");
+    }
+    if (vias->next != 0)
+	printk("Warning: only using 1st via-cuda\n");
+
+#if 0
+    { int i;
+
+    printk("via_cuda_init: node = %p, addrs =", vias->node);
+    for (i = 0; i < vias->n_addrs; ++i)
+	printk(" %x(%x)", vias->addrs[i].address, vias->addrs[i].size);
+    printk(", intrs =");
+    for (i = 0; i < vias->n_intrs; ++i)
+	printk(" %x", vias->intrs[i]);
+    printk("\n"); }
+#endif
+
+    if (vias->n_addrs != 1 || vias->n_intrs != 1)
+	panic("via-cuda: expecting 1 address and 1 interrupt");
+    via = (volatile unsigned char *) vias->addrs->address;
+
+    if (!init_via())
+	panic("init_via failed");
+
+    cuda_state = idle;
+
+    if (request_irq(vias->intrs[0], via_interrupt, 0, "VIA", (void *)0))
+	panic("VIA: can't get irq %d\n", vias->intrs[0]);
+
+    /* Clear and enable interrupts */
+    via[IFR] = 0x7f; eieio();	/* clear interrupts by writing 1s */
+    via[IER] = IER_SET|SR_INT; eieio();	/* enable interrupt from SR */
+}
+
+#define WAIT_FOR(cond, what)				\
+    do {						\
+	for (x = 1000; !(cond); --x) {			\
+	    if (x == 0) {				\
+		printk("Timeout waiting for " what);	\
+		return 0;				\
+	    }						\
+	    udelay(100);					\
+	}						\
+    } while (0)
+
+static int
+init_via()
+{
+    int x;
+
+    via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ;	/* TACK & TIP out */
+    via[B] |= TACK | TIP;				/* negate them */
+    via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT;		/* SR data in */
+    eieio();
+    x = via[SR]; eieio();	/* clear any left-over data */
+    via[IER] = 0x7f; eieio();	/* disable interrupts from VIA */
+    eieio();
+
+    /* delay 4ms and then clear any pending interrupt */
+    udelay(4000);
+    x = via[SR]; eieio();
+
+    /* sync with the CUDA - assert TACK without TIP */
+    via[B] &= ~TACK; eieio();
+
+    /* wait for the CUDA to assert TREQ in response */
+    WAIT_FOR((via[B] & TREQ) == 0, "CUDA response to sync");
+
+    /* wait for the interrupt and then clear it */
+    WAIT_FOR(via[IFR] & SR_INT, "CUDA response to sync (2)");
+    x = via[SR]; eieio();
+
+    /* finish the sync by negating TACK */
+    via[B] |= TACK; eieio();
+
+    /* wait for the CUDA to negate TREQ and the corresponding interrupt */
+    WAIT_FOR(via[B] & TREQ, "CUDA response to sync (3)");
+    WAIT_FOR(via[IFR] & SR_INT, "CUDA response to sync (4)");
+    x = via[SR]; eieio();
+    via[B] |= TIP; eieio();	/* should be unnecessary */
+
+    return 1;
+}
+
+/* Construct and send a cuda request */
+int
+cuda_request(struct cuda_request *req, void (*done)(struct cuda_request *),
+	     int nbytes, ...)
+{
+    va_list list;
+    int i;
+
+    req->nbytes = nbytes;
+    req->done = done;
+    va_start(list, nbytes);
+    for (i = 0; i < nbytes; ++i)
+	req->data[i] = va_arg(list, int);
+    va_end(list);
+    req->reply_expected = 1;
+    return cuda_send_request(req);
+}
+
+int
+cuda_send_request(struct cuda_request *req)
+{
+    unsigned long flags;
+
+    req->next = 0;
+    req->sent = 0;
+    req->got_reply = 0;
+    req->reply_len = 0;
+    save_flags(flags); cli();
+
+    if (current_req != 0) {
+	last_req->next = req;
+	last_req = req;
+    } else {
+	current_req = req;
+	last_req = req;
+	if (cuda_state == idle)
+	    cuda_start();
+    }
+
+    restore_flags(flags);
+    return 0;
+}
+
+static void
+cuda_start()
+{
+    unsigned long flags;
+    struct cuda_request *req;
+
+    /* assert cuda_state == idle */
+    /* get the packet to send */
+    req = current_req;
+    if (req == 0)
+	return;
+    save_flags(flags); cli();
+    if ((via[B] & TREQ) == 0) {
+	restore_flags(flags);
+	return;			/* a byte is coming in from the CUDA */
+    }
+
+    /* set the shift register to shift out and send a byte */
+    via[ACR] |= SR_OUT; eieio();
+    via[SR] = req->data[0]; eieio();
+    via[B] &= ~TIP;
+    cuda_state = sent_first_byte;
+    restore_flags(flags);
+}
+
+void
+cuda_poll()
+{
+    int ie;
+
+    ie = _disable_interrupts();
+    if (via[IFR] & SR_INT)
+	via_interrupt(0, 0, 0);
+    _enable_interrupts(ie);
+}
+
+static void
+via_interrupt(int irq, void *arg, struct pt_regs *regs)
+{
+    int x, status;
+    struct cuda_request *req;
+
+    if ((via[IFR] & SR_INT) == 0)
+	return;
+
+    status = (~via[B] & (TIP|TREQ)) | (via[ACR] & SR_OUT); eieio();
+    /* printk("via_interrupt: state=%d status=%x\n", cuda_state, status); */
+    switch (cuda_state) {
+    case idle:
+	/* CUDA has sent us the first byte of data - unsolicited */
+	if (status != TREQ)
+	    printk("cuda: state=idle, status=%x\n", status);
+	x = via[SR]; eieio();
+	via[B] &= ~TIP; eieio();
+	cuda_state = reading;
+	reply_ptr = cuda_rbuf;
+	reading_reply = 0;
+	break;
+
+    case awaiting_reply:
+	/* CUDA has sent us the first byte of data of a reply */
+	if (status != TREQ)
+	    printk("cuda: state=awaiting_reply, status=%x\n", status);
+	x = via[SR]; eieio();
+	via[B] &= ~TIP; eieio();
+	cuda_state = reading;
+	reply_ptr = current_req->reply;
+	reading_reply = 1;
+	break;
+
+    case sent_first_byte:
+	if (status == TREQ + TIP + SR_OUT) {
+	    /* collision */
+	    via[ACR] &= ~SR_OUT; eieio();
+	    x = via[SR]; eieio();
+	    via[B] |= TIP | TACK; eieio();
+	    cuda_state = idle;
+	} else {
+	    /* assert status == TIP + SR_OUT */
+	    if (status != TIP + SR_OUT)
+		printk("cuda: state=sent_first_byte status=%x\n", status);
+	    via[SR] = current_req->data[1]; eieio();
+	    via[B] ^= TACK; eieio();
+	    data_index = 2;
+	    cuda_state = sending;
+	}
+	break;
+
+    case sending:
+	req = current_req;
+	if (data_index >= req->nbytes) {
+	    via[ACR] &= ~SR_OUT; eieio();
+	    x = via[SR]; eieio();
+	    via[B] |= TACK | TIP; eieio();
+	    req->sent = 1;
+	    if (req->reply_expected) {
+		cuda_state = awaiting_reply;
+	    } else {
+		current_req = req->next;
+		if (req->done)
+		    (*req->done)(req);
+		/* not sure about this */
+		cuda_state = idle;
+		cuda_start();
+	    }
+	} else {
+	    via[SR] = req->data[data_index++]; eieio();
+	    via[B] ^= TACK; eieio();
+	}
+	break;
+
+    case reading:
+	*reply_ptr++ = via[SR]; eieio();
+	if (status == TIP) {
+	    /* that's all folks */
+	    via[B] |= TACK | TIP; eieio();
+	    cuda_state = read_done;
+	} else {
+	    /* assert status == TIP | TREQ */
+	    if (status != TIP + TREQ)
+		printk("cuda: state=reading status=%x\n", status);
+	    via[B] ^= TACK; eieio();
+	}
+	break;
+
+    case read_done:
+	x = via[SR]; eieio();
+	if (reading_reply) {
+	    req = current_req;
+	    req->reply_len = reply_ptr - req->reply;
+	    req->got_reply = 1;
+	    current_req = req->next;
+	    if (req->done)
+		(*req->done)(req);
+	} else {
+	    cuda_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs);
+	}
+	if (status == TREQ) {
+	    via[B] &= ~TIP; eieio();
+	    cuda_state = reading;
+	    reply_ptr = cuda_rbuf;
+	    reading_reply = 0;
+	} else {
+	    cuda_state = idle;
+	    cuda_start();
+	}
+	break;
+
+    default:
+	printk("via_interrupt: unknown cuda_state %d?\n", cuda_state);
+    }
+}
+
+static void
+cuda_input(unsigned char *buf, int nb, struct pt_regs *regs)
+{
+    int i, id;
+    static int dump_cuda_input = 0;
+
+    switch (buf[0]) {
+    case ADB_PACKET:
+	id = buf[2] >> 4;
+	if (dump_cuda_input) {
+	    printk(KERN_INFO "adb packet: ");
+	    for (i = 0; i < nb; ++i)
+		printk(" %x", buf[i]);
+	    printk(", id = %d\n", id);
+	}
+	if (adb_handler[id].handler != 0) {
+	    (*adb_handler[id].handler)(buf, nb, regs);
+	}
+	break;
+
+    default:
+	printk("data from cuda (%d bytes):", nb);
+	for (i = 0; i < nb; ++i)
+	    printk(" %.2x", buf[i]);
+	printk("\n");
+    }
+}
+
+/* Ultimately this should return the number of devices with
+   the given default id. */
+int
+adb_register(int default_id,
+	     void (*handler)(unsigned char *, int, struct pt_regs *))
+{
+    if (adb_handler[default_id].handler != 0)
+	panic("Two handlers for ADB device %d\n", default_id);
+    adb_handler[default_id].handler = handler;
+    return 1;
+}
diff -u --recursive --new-file v2.1.50/linux/drivers/net/mace.c linux/drivers/net/mace.c
--- v2.1.50/linux/drivers/net/mace.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/mace.c	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,800 @@
+/*
+ * Network device driver for the MACE ethernet controller on
+ * Apple Powermacs.  Assumes it's under a DBDMA controller.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <asm/prom.h>
+#include <asm/dbdma.h>
+#include <asm/io.h>
+#include "mace.h"
+
+#define N_RX_RING	8
+#define N_TX_RING	6
+#define MAX_TX_ACTIVE	1
+#define NCMDS_TX	1	/* dma commands per element in tx ring */
+#define RX_BUFLEN	(ETH_FRAME_LEN + 8)
+#define TX_TIMEOUT	HZ	/* 1 second */
+
+/* Bits in transmit DMA status */
+#define TX_DMA_ERR	0x80
+
+struct mace_data {
+    volatile struct mace *mace;
+    volatile struct dbdma_regs *tx_dma;
+    int tx_dma_intr;
+    volatile struct dbdma_regs *rx_dma;
+    int rx_dma_intr;
+    volatile struct dbdma_cmd *tx_cmds;	/* xmit dma command list */
+    volatile struct dbdma_cmd *rx_cmds;	/* recv dma command list */
+    struct sk_buff *rx_bufs[N_RX_RING];
+    int rx_fill;
+    int rx_empty;
+    struct sk_buff *tx_bufs[N_TX_RING];
+    int tx_fill;
+    int tx_empty;
+    unsigned char maccc;
+    unsigned char tx_fullup;
+    unsigned char tx_active;
+    unsigned char tx_bad_runt;
+    struct net_device_stats stats;
+    struct timer_list tx_timeout;
+};
+
+/*
+ * Number of bytes of private data per MACE: allow enough for
+ * the rx and tx dma commands plus a branch dma command each,
+ * and another 16 bytes to allow us to align the dma command
+ * buffers on a 16 byte boundary.
+ */
+#define PRIV_BYTES	(sizeof(struct mace_data) \
+	+ (N_RX_RING + NCMDS_TX * N_TX_RING + 3) * sizeof(struct dbdma_cmd))
+
+static int bitrev(int);
+static int mace_open(struct device *dev);
+static int mace_close(struct device *dev);
+static int mace_xmit_start(struct sk_buff *skb, struct device *dev);
+static struct net_device_stats *mace_stats(struct device *dev);
+static void mace_set_multicast(struct device *dev);
+static void mace_reset(struct device *dev);
+static int mace_set_address(struct device *dev, void *addr);
+static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static void mace_set_timeout(struct device *dev);
+static void mace_tx_timeout(unsigned long data);
+
+/*
+ * If we can't get a skbuff when we need it, we use this area for DMA.
+ */
+static unsigned char dummy_buf[RX_BUFLEN+2];
+
+/* Bit-reverse one byte of an ethernet hardware address. */
+static int
+bitrev(int b)
+{
+    int d = 0, i;
+
+    for (i = 0; i < 8; ++i, b >>= 1)
+	d = (d << 1) | (b & 1);
+    return d;
+}
+
+int
+mace_probe(struct device *dev)
+{
+    int j, rev;
+    struct mace_data *mp;
+    struct device_node *maces;
+    unsigned char *addr;
+
+    maces = find_devices("mace");
+    if (maces == 0)
+	return ENODEV;
+
+    do {
+	if (maces->n_addrs != 3 || maces->n_intrs != 3) {
+	    printk(KERN_ERR "can't use MACE %s: expect 3 addrs and 3 intrs\n",
+		   maces->full_name);
+	    continue;
+	}
+
+	if (dev == NULL)
+	    dev = init_etherdev(0, PRIV_BYTES);
+	else {
+	    /* XXX this doesn't look right (but it's never used :-) */
+	    dev->priv = kmalloc(PRIV_BYTES, GFP_KERNEL);
+	    if (dev->priv == 0)
+		return -ENOMEM;
+	}
+
+	mp = (struct mace_data *) dev->priv;
+	dev->base_addr = maces->addrs[0].address;
+	mp->mace = (volatile struct mace *) maces->addrs[0].address;
+	dev->irq = maces->intrs[0];
+
+	if (request_irq(dev->irq, mace_interrupt, 0, "MACE", dev)) {
+	    printk(KERN_ERR "MACE: can't get irq %d\n", dev->irq);
+	    return -EAGAIN;
+	}
+	if (request_irq(maces->intrs[1], mace_txdma_intr, 0, "MACE-txdma",
+			dev)) {
+	    printk(KERN_ERR "MACE: can't get irq %d\n", maces->intrs[1]);
+	    return -EAGAIN;
+	}
+	if (request_irq(maces->intrs[2], mace_rxdma_intr, 0, "MACE-rxdma",
+			dev)) {
+	    printk(KERN_ERR "MACE: can't get irq %d\n", maces->intrs[2]);
+	    return -EAGAIN;
+	}
+
+	addr = get_property(maces, "mac-address", NULL);
+	if (addr == NULL) {
+	    addr = get_property(maces, "local-mac-address", NULL);
+	    if (addr == NULL) {
+		printk(KERN_ERR "Can't get mac-address for MACE at %lx\n",
+		       dev->base_addr);
+		return -EAGAIN;
+	    }
+	}
+
+	printk(KERN_INFO "%s: MACE at", dev->name);
+	rev = addr[0] == 0 && addr[1] == 0xA0;
+	for (j = 0; j < 6; ++j) {
+	    dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
+	    printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
+	}
+	printk("\n");
+
+	mp = (struct mace_data *) dev->priv;
+	mp->maccc = ENXMT | ENRCV;
+	mp->tx_dma = (volatile struct dbdma_regs *) maces->addrs[1].address;
+	mp->tx_dma_intr = maces->intrs[1];
+	mp->rx_dma = (volatile struct dbdma_regs *) maces->addrs[2].address;
+	mp->rx_dma_intr = maces->intrs[2];
+
+	mp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(mp + 1);
+	mp->rx_cmds = mp->tx_cmds + NCMDS_TX * N_TX_RING + 1;
+
+	memset(&mp->stats, 0, sizeof(mp->stats));
+	memset((char *) mp->tx_cmds, 0,
+	      (NCMDS_TX*N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));
+
+	mace_reset(dev);
+
+	dev->open = mace_open;
+	dev->stop = mace_close;
+	dev->hard_start_xmit = mace_xmit_start;
+	dev->get_stats = mace_stats;
+	dev->set_multicast_list = mace_set_multicast;
+	dev->set_mac_address = mace_set_address;
+
+	ether_setup(dev);
+
+    } while ((maces = maces->next) != 0);
+
+    return 0;
+}
+
+static void mace_reset(struct device *dev)
+{
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+    volatile struct mace *mb = mp->mace;
+    int i;
+
+    /* soft-reset the chip */
+    mb->biucc = SWRST; eieio();
+    udelay(100);
+
+    mb->biucc = XMTSP_64;
+    mb->imr = 0xff;		/* disable all intrs for now */
+    i = mb->ir;
+    mb->maccc = 0;		/* turn off tx, rx */
+    mb->utr = RTRD;
+    mb->fifocc = RCVFW_64;
+    mb->xmtfc = AUTO_PAD_XMIT;	/* auto-pad short frames */
+
+    /* load up the hardware address */
+    mb->iac = ADDRCHG | PHYADDR; eieio();
+    while ((mb->iac & ADDRCHG) != 0)
+	eieio();
+    for (i = 0; i < 6; ++i) {
+	mb->padr = dev->dev_addr[i];
+	eieio();
+    }
+
+    /* clear the multicast filter */
+    mb->iac = ADDRCHG | LOGADDR; eieio();
+    while ((mb->iac & ADDRCHG) != 0)
+	eieio();
+    for (i = 0; i < 8; ++i) {
+	mb->ladrf = 0;
+	eieio();
+    }
+
+    mb->plscc = PORTSEL_GPSI + ENPLSIO;
+}
+
+static int mace_set_address(struct device *dev, void *addr)
+{
+    unsigned char *p = addr;
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+    volatile struct mace *mb = mp->mace;
+    int i;
+    unsigned long flags;
+
+    save_flags(flags); cli();
+
+    /* load up the hardware address */
+    mb->iac = ADDRCHG | PHYADDR; eieio();
+    while ((mb->iac & ADDRCHG) != 0)
+	eieio();
+    for (i = 0; i < 6; ++i) {
+	mb->padr = dev->dev_addr[i] = p[i];
+	eieio();
+    }
+    /* note: setting ADDRCHG clears ENRCV */
+    mb->maccc = mp->maccc; eieio();
+
+    restore_flags(flags);
+    return 0;
+}
+
+static int mace_open(struct device *dev)
+{
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+    volatile struct mace *mb = mp->mace;
+    volatile struct dbdma_regs *rd = mp->rx_dma;
+    volatile struct dbdma_regs *td = mp->tx_dma;
+    volatile struct dbdma_cmd *cp;
+    int i;
+    struct sk_buff *skb;
+    unsigned char *data;
+
+    /* initialize list of sk_buffs for receiving and set up recv dma */
+    memset((char *)mp->rx_cmds, 0, N_RX_RING * sizeof(struct dbdma_cmd));
+    cp = mp->rx_cmds;
+    for (i = 0; i < N_RX_RING - 1; ++i) {
+	skb = dev_alloc_skb(RX_BUFLEN + 2);
+	if (skb == 0) {
+	    data = dummy_buf;
+	} else {
+	    skb_reserve(skb, 2);	/* so IP header lands on 4-byte bdry */
+	    data = skb->data;
+	}
+	mp->rx_bufs[i] = skb;
+	st_le16(&cp->req_count, RX_BUFLEN);
+	st_le16(&cp->command, INPUT_LAST + INTR_ALWAYS);
+	st_le32(&cp->phy_addr, virt_to_bus(data));
+	cp->xfer_status = 0;
+	++cp;
+    }
+    mp->rx_bufs[i] = 0;
+    st_le16(&cp->command, DBDMA_STOP);
+    mp->rx_fill = i;
+    mp->rx_empty = 0;
+
+    /* Put a branch back to the beginning of the receive command list */
+    ++cp;
+    st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
+    st_le32(&cp->cmd_dep, virt_to_bus(mp->rx_cmds));
+
+    /* start rx dma */
+    out_le32(&rd->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* clear run bit */
+    out_le32(&rd->cmdptr, virt_to_bus(mp->rx_cmds));
+    out_le32(&rd->control, (RUN << 16) | RUN);
+
+    /* put a branch at the end of the tx command list */
+    cp = mp->tx_cmds + NCMDS_TX * N_TX_RING;
+    st_le16(&cp->command, DBDMA_NOP + BR_ALWAYS);
+    st_le32(&cp->cmd_dep, virt_to_bus(mp->tx_cmds));
+
+    /* reset tx dma */
+    out_le32(&td->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+    out_le32(&td->cmdptr, virt_to_bus(mp->tx_cmds));
+    mp->tx_fill = 0;
+    mp->tx_empty = 0;
+    mp->tx_fullup = 0;
+    mp->tx_active = 0;
+    mp->tx_bad_runt = 0;
+
+    /* turn it on! */
+    mb->maccc = mp->maccc; eieio();
+    /* enable all interrupts except receive interrupts */
+    mb->imr = RCVINT; eieio();
+    return 0;
+}
+
+static int mace_close(struct device *dev)
+{
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+    volatile struct mace *mb = mp->mace;
+    volatile struct dbdma_regs *rd = mp->rx_dma;
+    volatile struct dbdma_regs *td = mp->tx_dma;
+    int i;
+
+    /* disable rx and tx */
+    mb->maccc = 0;
+    mb->imr = 0xff;		/* disable all intrs */
+
+    /* disable rx and tx dma */
+    st_le32(&rd->control, (RUN|PAUSE|FLUSH|WAKE) << 16);	/* clear run bit */
+    st_le32(&td->control, (RUN|PAUSE|FLUSH|WAKE) << 16);	/* clear run bit */
+
+    /* free some skb's */
+    for (i = 0; i < N_RX_RING; ++i) {
+	if (mp->rx_bufs[i] != 0) {
+	    dev_kfree_skb(mp->rx_bufs[i], FREE_READ);
+	    mp->rx_bufs[i] = 0;
+	}
+    }
+    for (i = mp->tx_empty; i != mp->tx_fill; ) {
+	dev_kfree_skb(mp->tx_bufs[i], FREE_WRITE);
+	if (++i >= N_TX_RING)
+	    i = 0;
+    }
+
+    return 0;
+}
+
+static inline void mace_set_timeout(struct device *dev)
+{
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+
+    mp->tx_timeout.expires = jiffies + TX_TIMEOUT;
+    mp->tx_timeout.function = mace_tx_timeout;
+    mp->tx_timeout.data = (unsigned long) dev;
+    add_timer(&mp->tx_timeout);
+}
+
+static int mace_xmit_start(struct sk_buff *skb, struct device *dev)
+{
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+    volatile struct dbdma_regs *td = mp->tx_dma;
+    volatile struct dbdma_cmd *cp, *np;
+    unsigned long flags;
+    int fill, next, len;
+
+    /* see if there's a free slot in the tx ring */
+    save_flags(flags); cli();
+    fill = mp->tx_fill;
+    next = fill + 1;
+    if (next >= N_TX_RING)
+	next = 0;
+    if (next == mp->tx_empty) {
+	dev->tbusy = 1;
+	mp->tx_fullup = 1;
+	restore_flags(flags);
+	return -1;		/* can't take it at the moment */
+    }
+    restore_flags(flags);
+
+    /* partially fill in the dma command block */
+    len = skb->len;
+    if (len > ETH_FRAME_LEN) {
+	printk(KERN_DEBUG "mace: xmit frame too long (%d)\n", len);
+	len = ETH_FRAME_LEN;
+    }
+    mp->tx_bufs[fill] = skb;
+    cp = mp->tx_cmds + NCMDS_TX * fill;
+    st_le16(&cp->req_count, len);
+    st_le32(&cp->phy_addr, virt_to_bus(skb->data));
+
+    np = mp->tx_cmds + NCMDS_TX * next;
+    out_le16(&np->command, DBDMA_STOP);
+
+    /* poke the tx dma channel */
+    save_flags(flags);
+    cli();
+    mp->tx_fill = next;
+    if (!mp->tx_bad_runt && mp->tx_active < MAX_TX_ACTIVE) {
+	out_le16(&cp->xfer_status, 0);
+	out_le16(&cp->command, OUTPUT_LAST);
+	out_le32(&td->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+	++mp->tx_active;
+	mace_set_timeout(dev);
+    }
+    restore_flags(flags);
+
+    return 0;
+}
+
+static struct net_device_stats *mace_stats(struct device *dev)
+{
+    struct mace_data *p = (struct mace_data *) dev->priv;
+
+    return &p->stats;
+}
+
+/*
+ * CRC polynomial - used in working out multicast filter bits.
+ */
+#define CRC_POLY	0xedb88320
+
+static void mace_set_multicast(struct device *dev)
+{
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+    volatile struct mace *mb = mp->mace;
+    int i, j, k, b;
+    unsigned long crc;
+
+    mp->maccc &= ~PROM;
+    if (dev->flags & IFF_PROMISC) {
+	mp->maccc |= PROM;
+    } else {
+	unsigned char multicast_filter[8];
+	struct dev_mc_list *dmi = dev->mc_list;
+
+	if (dev->flags & IFF_ALLMULTI) {
+	    for (i = 0; i < 8; i++)
+		multicast_filter[i] = 0xff;
+	} else {
+	    for (i = 0; i < 8; i++)
+		multicast_filter[i] = 0;
+	    for (i = 0; i < dev->mc_count; i++) {
+		crc = ~0;
+		for (j = 0; j < 6; ++j) {
+		    b = dmi->dmi_addr[j];
+		    for (k = 0; k < 8; ++k) {
+			if ((crc ^ b) & 1)
+			    crc = (crc >> 1) ^ CRC_POLY;
+			else
+			    crc >>= 1;
+			b >>= 1;
+		    }
+		}
+		j = crc >> 26;	/* bit number in multicast_filter */
+		multicast_filter[j >> 3] |= 1 << (j & 7);
+		dmi = dmi->next;
+	    }
+	}
+#if 0
+	printk("Multicast filter :");
+	for (i = 0; i < 8; i++)
+	    printk("%02x ", multicast_filter[i]);
+	printk("\n");
+#endif
+
+	mb->iac = ADDRCHG | LOGADDR; eieio();
+	while ((mb->iac & ADDRCHG) != 0)
+	    eieio();
+	for (i = 0; i < 8; ++i) {
+	    mb->ladrf = multicast_filter[i];
+	    eieio();
+	}
+    }
+    /* reset maccc */
+    mb->maccc = mp->maccc; eieio();
+}
+
+static void mace_handle_misc_intrs(struct mace_data *mp, int intr)
+{
+    volatile struct mace *mb = mp->mace;
+    static int mace_babbles, mace_jabbers;
+
+    if (intr & MPCO)
+	mp->stats.rx_missed_errors += 256;
+    mp->stats.rx_missed_errors += mb->mpc;	/* reading clears it */
+    if (intr & RNTPCO)
+	mp->stats.rx_length_errors += 256;
+    mp->stats.rx_length_errors += mb->rntpc;	/* reading clears it */
+    if (intr & CERR)
+	++mp->stats.tx_heartbeat_errors;
+    if (intr & BABBLE)
+	if (mace_babbles++ < 4)
+	    printk(KERN_DEBUG "mace: babbling transmitter\n");
+    if (intr & JABBER)
+	if (mace_jabbers++ < 4)
+	    printk(KERN_DEBUG "mace: jabbering transceiver\n");
+}
+
+static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct device *dev = (struct device *) dev_id;
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+    volatile struct mace *mb = mp->mace;
+    volatile struct dbdma_regs *td = mp->tx_dma;
+    volatile struct dbdma_cmd *cp;
+    int intr, fs, i, stat, x;
+    int xcount, dstat;
+    static int mace_last_fs, mace_last_xcount;
+
+    intr = mb->ir;		/* read interrupt register */
+    mace_handle_misc_intrs(mp, intr);
+
+    i = mp->tx_empty;
+    while (mb->pr & XMTSV) {
+	/*
+	 * Clear any interrupt indication associated with this status
+	 * word.  This appears to unlatch any error indication from
+	 * the DMA controller.
+	 */
+	intr = mb->ir;
+	if (intr != 0)
+	    mace_handle_misc_intrs(mp, intr);
+	if (mp->tx_bad_runt) {
+	    fs = mb->xmtfs;
+	    eieio();
+	    mp->tx_bad_runt = 0;
+	    mb->xmtfc = AUTO_PAD_XMIT;
+	    del_timer(&mp->tx_timeout);
+	    continue;
+	}
+	dstat = ld_le32(&td->status);
+	/* stop DMA controller */
+	out_le32(&td->control, RUN << 16);
+	/*
+	 * xcount is the number of complete frames which have been
+	 * written to the fifo but for which status has not been read.
+	 */
+	xcount = (mb->fifofc >> XMTFC_SH) & XMTFC_MASK;
+	if (xcount == 0 || (dstat & DEAD)) {
+	    /*
+	     * If a packet was aborted before the DMA controller has
+	     * finished transferring it, it seems that there are 2 bytes
+	     * which are stuck in some buffer somewhere.  These will get
+	     * transmitted as soon as we read the frame status (which
+	     * reenables the transmit data transfer request).  Turning
+	     * off the DMA controller and/or resetting the MACE doesn't
+	     * help.  So we disable auto-padding and FCS transmission
+	     * so the two bytes will only be a runt packet which should
+	     * be ignored by other stations.
+	     */
+	    mb->xmtfc = DXMTFCS;
+	    eieio();
+	}
+	fs = mb->xmtfs;
+	if ((fs & XMTSV) == 0) {
+	    printk(KERN_ERR "mace: xmtfs not valid! (fs=%x xc=%d ds=%x)\n", fs, xcount, dstat);
+	}
+	cp = mp->tx_cmds + NCMDS_TX * i;
+	stat = ld_le16(&cp->xfer_status);
+	if ((fs & (UFLO|LCOL|LCAR|RTRY)) || (dstat & DEAD) || xcount == 0) {
+	    /*
+	     * Check whether there were in fact 2 bytes written to
+	     * the transmit FIFO.
+	     */
+	    x = (mb->fifofc >> XMTFC_SH) & XMTFC_MASK;
+	    if (x != 0) {
+		/* there were two bytes with an end-of-packet indication */
+		mp->tx_bad_runt = 1;
+		mace_set_timeout(dev);
+	    } else {
+		/*
+		 * Either there weren't the two bytes buffered up, or they
+		 * didn't have an end-of-packet indication.  Maybe we ought
+		 * to flush the transmit FIFO just in case (by setting the
+		 * XMTFWU bit with the transmitter disabled).
+		 */
+		mb->xmtfc = AUTO_PAD_XMIT;
+		eieio();
+	    }
+	}
+	/* dma should have finished */
+	if (i == mp->tx_fill) {
+	    printk(KERN_DEBUG "mace: tx ring ran out? (fs=%x xc=%d ds=%x)\n", fs, xcount, dstat);
+	    continue;
+	}
+	/* Update stats */
+	if (fs & (UFLO|LCOL|LCAR|RTRY)) {
+	    ++mp->stats.tx_errors;
+	    if (fs & LCAR)
+		++mp->stats.tx_carrier_errors;
+	    if (fs & (UFLO|LCOL|RTRY))
+		++mp->stats.tx_aborted_errors;
+	} else
+	    ++mp->stats.tx_packets;
+	dev_kfree_skb(mp->tx_bufs[i], FREE_WRITE);
+	--mp->tx_active;
+	if (++i >= N_TX_RING)
+	    i = 0;
+	mace_last_fs = fs;
+	mace_last_xcount = xcount;
+	del_timer(&mp->tx_timeout);
+    }
+
+    mp->tx_empty = i;
+    i += mp->tx_active;
+    if (i >= N_TX_RING)
+	i -= N_TX_RING;
+    if (i != mp->tx_fill && mp->tx_fullup) {
+	mp->tx_fullup = 0;
+	dev->tbusy = 0;
+	mark_bh(NET_BH);
+    }
+    if (!mp->tx_bad_runt && i != mp->tx_fill && mp->tx_active < MAX_TX_ACTIVE) {
+	do {
+	    /* set up the next one */
+	    cp = mp->tx_cmds + NCMDS_TX * i;
+	    out_le16(&cp->xfer_status, 0);
+	    out_le16(&cp->command, OUTPUT_LAST);
+	    ++mp->tx_active;
+	    if (++i >= N_TX_RING)
+		i = 0;
+	} while (i != mp->tx_fill && mp->tx_active < MAX_TX_ACTIVE);
+	out_le32(&td->control, ((RUN|WAKE) << 16) + (RUN|WAKE));
+	mace_set_timeout(dev);
+    }
+}
+
+static void mace_tx_timeout(unsigned long data)
+{
+    struct device *dev = (struct device *) data;
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+    volatile struct mace *mb = mp->mace;
+    volatile struct dbdma_regs *td = mp->tx_dma;
+    volatile struct dbdma_regs *rd = mp->rx_dma;
+    volatile struct dbdma_cmd *cp;
+    unsigned long flags;
+    int i;
+
+    save_flags(flags);
+    cli();
+    if (mp->tx_active == 0 && !mp->tx_bad_runt)
+	goto out;
+
+    /* update various counters */
+    mace_handle_misc_intrs(mp, mb->ir);
+
+    cp = mp->tx_cmds + NCMDS_TX * mp->tx_empty;
+    printk(KERN_DEBUG "mace: tx dmastat=%x %x bad_runt=%d pr=%x fs=%x fc=%x\n",
+	   ld_le32(&td->status), ld_le16(&cp->xfer_status), mp->tx_bad_runt,
+	   mb->pr, mb->xmtfs, mb->fifofc);
+
+    /* turn off both tx and rx and reset the chip */
+    mb->maccc = 0;
+    out_le32(&td->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+    printk(KERN_ERR "mace: transmit timeout - resetting\n");
+    mace_reset(dev);
+
+    /* restart rx dma */
+    cp = bus_to_virt(ld_le32(&rd->cmdptr));
+    out_le32(&rd->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+    out_le16(&cp->xfer_status, 0);
+    out_le32(&rd->cmdptr, virt_to_bus(cp));
+    out_le32(&rd->control, (RUN << 16) | RUN);
+
+    /* fix up the transmit side */
+    i = mp->tx_empty;
+    mp->tx_active = 0;
+    ++mp->stats.tx_errors;
+    if (mp->tx_bad_runt) {
+	mp->tx_bad_runt = 0;
+    } else if (i != mp->tx_fill) {
+	dev_kfree_skb(mp->tx_bufs[i], FREE_WRITE);
+	if (++i >= N_TX_RING)
+	    i = 0;
+	mp->tx_empty = i;
+    }
+    if (mp->tx_fullup) {
+	mp->tx_fullup = 0;
+	dev->tbusy = 0;
+	mark_bh(NET_BH);
+    }
+    if (i != mp->tx_fill) {
+	cp = mp->tx_cmds + NCMDS_TX * i;
+	out_le16(&cp->xfer_status, 0);
+	out_le16(&cp->command, OUTPUT_LAST);
+	out_le32(&td->cmdptr, virt_to_bus(cp));
+	out_le32(&td->control, (RUN << 16) | RUN);
+	++mp->tx_active;
+	mace_set_timeout(dev);
+    }
+
+    /* turn it back on */
+    out_8(&mb->imr, RCVINT);
+    out_8(&mb->maccc, mp->maccc);
+
+out:
+    restore_flags(flags);
+}
+
+static void mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static void mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct device *dev = (struct device *) dev_id;
+    struct mace_data *mp = (struct mace_data *) dev->priv;
+    volatile struct dbdma_regs *rd = mp->rx_dma;
+    volatile struct dbdma_cmd *cp, *np;
+    int i, nb, stat, next;
+    struct sk_buff *skb;
+    unsigned frame_status;
+    static int mace_lost_status;
+    unsigned char *data;
+
+    for (i = mp->rx_empty; i != mp->rx_fill; ) {
+	cp = mp->rx_cmds + i;
+	stat = ld_le16(&cp->xfer_status);
+	if ((stat & ACTIVE) == 0) {
+	    next = i + 1;
+	    if (next >= N_RX_RING)
+		next = 0;
+	    np = mp->rx_cmds + next;
+	    if (next != mp->rx_fill
+		&& (ld_le16(&np->xfer_status) & ACTIVE) != 0) {
+		printk(KERN_DEBUG "mace: lost a status word\n");
+		++mace_lost_status;
+	    } else
+		break;
+	}
+	nb = ld_le16(&cp->req_count) - ld_le16(&cp->res_count);
+	out_le16(&cp->command, DBDMA_STOP);
+	/* got a packet, have a look at it */
+	skb = mp->rx_bufs[i];
+	if (skb == 0) {
+	    ++mp->stats.rx_dropped;
+	} else if (nb > 8) {
+	    data = skb->data;
+	    frame_status = (data[nb-3] << 8) + data[nb-4];
+	    if (frame_status & (RS_OFLO|RS_CLSN|RS_FRAMERR|RS_FCSERR)) {
+		++mp->stats.rx_errors;
+		if (frame_status & RS_OFLO)
+		    ++mp->stats.rx_over_errors;
+		if (frame_status & RS_FRAMERR)
+		    ++mp->stats.rx_frame_errors;
+		if (frame_status & RS_FCSERR)
+		    ++mp->stats.rx_crc_errors;
+	    } else {
+		nb -= 8;
+		skb_put(skb, nb);
+		skb->dev = dev;
+		skb->protocol = eth_type_trans(skb, dev);
+		netif_rx(skb);
+		mp->rx_bufs[i] = 0;
+		++mp->stats.rx_packets;
+	    }
+	} else {
+	    ++mp->stats.rx_errors;
+	    ++mp->stats.rx_length_errors;
+	}
+
+	/* advance to next */
+	if (++i >= N_RX_RING)
+	    i = 0;
+    }
+    mp->rx_empty = i;
+
+    i = mp->rx_fill;
+    for (;;) {
+	next = i + 1;
+	if (next >= N_RX_RING)
+	    next = 0;
+	if (next == mp->rx_empty)
+	    break;
+	cp = mp->rx_cmds + i;
+	skb = mp->rx_bufs[i];
+	if (skb == 0) {
+	    skb = dev_alloc_skb(RX_BUFLEN + 2);
+	    if (skb != 0) {
+		skb_reserve(skb, 2);
+		mp->rx_bufs[i] = skb;
+	    }
+	}
+	st_le16(&cp->req_count, RX_BUFLEN);
+	data = skb? skb->data: dummy_buf;
+	st_le32(&cp->phy_addr, virt_to_bus(data));
+	out_le16(&cp->xfer_status, 0);
+	out_le16(&cp->command, INPUT_LAST + INTR_ALWAYS);
+#if 0
+	if ((ld_le32(&rd->status) & ACTIVE) != 0) {
+	    out_le32(&rd->control, (PAUSE << 16) | PAUSE);
+	    while ((in_le32(&rd->status) & ACTIVE) != 0)
+		;
+	}
+#endif
+	i = next;
+    }
+    if (i != mp->rx_fill) {
+	out_le32(&rd->control, ((RUN|WAKE) << 16) | (RUN|WAKE));
+	mp->rx_fill = i;
+    }
+}
diff -u --recursive --new-file v2.1.50/linux/drivers/net/mace.h linux/drivers/net/mace.h
--- v2.1.50/linux/drivers/net/mace.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/mace.h	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,173 @@
+/*
+ * mace.h - definitions for the registers in the Am79C940 MACE
+ * (Medium Access Control for Ethernet) controller.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define REG(x)	volatile unsigned char x; char x ## _pad[15]
+
+struct mace {
+	REG(rcvfifo);		/* receive FIFO */
+	REG(xmtfifo);		/* transmit FIFO */
+	REG(xmtfc);		/* transmit frame control */
+	REG(xmtfs);		/* transmit frame status */
+	REG(xmtrc);		/* transmit retry count */
+	REG(rcvfc);		/* receive frame control */
+	REG(rcvfs);		/* receive frame status (4 bytes) */
+	REG(fifofc);		/* FIFO frame count */
+	REG(ir);		/* interrupt register */
+	REG(imr);		/* interrupt mask register */
+	REG(pr);		/* poll register */
+	REG(biucc);		/* bus interface unit config control */
+	REG(fifocc);		/* FIFO configuration control */
+	REG(maccc);		/* medium access control config control */
+	REG(plscc);		/* phys layer signalling config control */
+	REG(phycc);		/* physical configuration control */
+	REG(chipid_lo);		/* chip ID, lsb */
+	REG(chipid_hi);		/* chip ID, msb */
+	REG(iac);		/* internal address config */
+	REG(reg19);
+	REG(ladrf);		/* logical address filter (8 bytes) */
+	REG(padr);		/* physical address (6 bytes) */
+	REG(reg22);
+	REG(reg23);
+	REG(mpc);		/* missed packet count (clears when read) */
+	REG(reg25);
+	REG(rntpc);		/* runt packet count (clears when read) */
+	REG(rcvcc);		/* recv collision count (clears when read) */
+	REG(reg28);
+	REG(utr);		/* user test reg */
+	REG(reg30);
+	REG(reg31);
+};
+
+/* Bits in XMTFC */
+#define DRTRY		0x80	/* don't retry transmission after collision */
+#define DXMTFCS		0x08	/* don't append FCS to transmitted frame */
+#define AUTO_PAD_XMIT	0x01	/* auto-pad short packets on transmission */
+
+/* Bits in XMTFS: only valid when XMTSV is set in PR and XMTFS */
+#define XMTSV		0x80	/* transmit status (i.e. XMTFS) valid */
+#define UFLO		0x40	/* underflow - xmit fifo ran dry */
+#define LCOL		0x20	/* late collision (transmission aborted) */
+#define MORE		0x10	/* 2 or more retries needed to xmit frame */
+#define ONE		0x08	/* 1 retry needed to xmit frame */
+#define DEFER		0x04	/* MACE had to defer xmission (enet busy) */
+#define LCAR		0x02	/* loss of carrier (transmission aborted) */
+#define RTRY		0x01	/* too many retries (transmission aborted) */
+
+/* Bits in XMTRC: only valid when XMTSV is set in PR (and XMTFS) */
+#define EXDEF		0x80	/* had to defer for excessive time */
+#define RETRY_MASK	0x0f	/* number of retries (0 - 15) */
+
+/* Bits in RCVFC */
+#define LLRCV		0x08	/* low latency receive: early DMA request */
+#define M_RBAR		0x04	/* sets function of EAM/R pin */
+#define AUTO_STRIP_RCV	0x01	/* auto-strip short LLC frames on recv */
+
+/*
+ * Bits in RCVFS.  After a frame is received, four bytes of status
+ * are automatically read from this register and appended to the frame
+ * data in memory.  These are:
+ * Byte 0 and 1: message byte count and frame status
+ * Byte 2: runt packet count
+ * Byte 3: receive collision count
+ */
+#define RS_OFLO		0x8000	/* receive FIFO overflowed */
+#define RS_CLSN		0x4000	/* received frame suffered (late) collision */
+#define RS_FRAMERR	0x2000	/* framing error flag */
+#define RS_FCSERR	0x1000	/* frame had FCS error */
+#define RS_COUNT	0x0fff	/* mask for byte count field */
+
+/* Bits (fields) in FIFOFC */
+#define RCVFC_SH	4	/* receive frame count in FIFO */
+#define RCVFC_MASK	0x0f
+#define XMTFC_SH	0	/* transmit frame count in FIFO */
+#define XMTFC_MASK	0x0f
+
+/*
+ * Bits in IR and IMR.  The IR clears itself when read.
+ * Setting a bit in the IMR will disable the corresponding interrupt.
+ */
+#define JABBER		0x80	/* jabber error - 10baseT xmission too long */
+#define BABBLE		0x40	/* babble - xmitter xmitting for too long */
+#define CERR		0x20	/* collision err - no SQE test (heartbeat) */
+#define RCVCCO		0x10	/* RCVCC overflow */
+#define RNTPCO		0x08	/* RNTPC overflow */
+#define MPCO		0x04	/* MPC overflow */
+#define RCVINT		0x02	/* receive interrupt */
+#define XMTINT		0x01	/* transmitter interrupt */
+
+/* Bits in PR */
+#define XMTSV		0x80	/* XMTFS valid (same as in XMTFS) */
+#define TDTREQ		0x40	/* set when xmit fifo is requesting data */
+#define RDTREQ		0x20	/* set when recv fifo requests data xfer */
+
+/* Bits in BIUCC */
+#define BSWP		0x40	/* byte swap, i.e. big-endian bus */
+#define XMTSP_4		0x00	/* start xmitting when 4 bytes in FIFO */
+#define XMTSP_16	0x10	/* start xmitting when 16 bytes in FIFO */
+#define XMTSP_64	0x20	/* start xmitting when 64 bytes in FIFO */
+#define XMTSP_112	0x30	/* start xmitting when 112 bytes in FIFO */
+#define SWRST		0x01	/* software reset */
+
+/* Bits in FIFOCC */
+#define XMTFW_8		0x00	/* xmit fifo watermark = 8 words free */
+#define XMTFW_16	0x40	/*  16 words free */
+#define XMTFW_32	0x80	/*  32 words free */
+#define RCVFW_16	0x00	/* recv fifo watermark = 16 bytes avail */
+#define RCVFW_32	0x10	/*  32 bytes avail */
+#define RCVFW_64	0x20	/*  64 bytes avail */
+#define XMTFWU		0x08	/* xmit fifo watermark update enable */
+#define RCVFWU		0x04	/* recv fifo watermark update enable */
+#define XMTBRST		0x02	/* enable transmit burst mode */
+#define RCVBRST		0x01	/* enable receive burst mode */
+
+/* Bits in MACCC */
+#define PROM		0x80	/* promiscuous mode */
+#define DXMT2PD		0x40	/* disable xmit two-part deferral algorithm */
+#define EMBA		0x20	/* enable modified backoff algorithm */
+#define DRCVPA		0x08	/* disable receiving physical address */
+#define DRCVBC		0x04	/* disable receiving broadcasts */
+#define ENXMT		0x02	/* enable transmitter */
+#define ENRCV		0x01	/* enable receiver */
+
+/* Bits in PLSCC */
+#define XMTSEL		0x08	/* select DO+/DO- state when idle */
+#define PORTSEL_AUI	0x00	/* select AUI port */
+#define PORTSEL_10T	0x02	/* select 10Base-T port */
+#define PORTSEL_DAI	0x04	/* select DAI port */
+#define PORTSEL_GPSI	0x06	/* select GPSI port */
+#define ENPLSIO		0x01	/* enable optional PLS I/O pins */
+
+/* Bits in PHYCC */
+#define LNKFL		0x80	/* reports 10Base-T link failure */
+#define DLNKTST		0x40	/* disable 10Base-T link test */
+#define REVPOL		0x20	/* 10Base-T receiver polarity reversed */
+#define DAPC		0x10	/* disable auto receiver polarity correction */
+#define LRT		0x08	/* low receive threshold for long links */
+#define ASEL		0x04	/* auto-select AUI or 10Base-T port */
+#define RWAKE		0x02	/* remote wake function */
+#define AWAKE		0x01	/* auto wake function */
+
+/* Bits in IAC */
+#define ADDRCHG		0x80	/* request address change */
+#define PHYADDR		0x04	/* access physical address */
+#define LOGADDR		0x02	/* access multicast filter */
+
+/* Bits in UTR */
+#define RTRE		0x80	/* reserved test register enable. DON'T SET. */
+#define RTRD		0x40	/* reserved test register disable.  Sticky */
+#define RPA		0x20	/* accept runt packets */
+#define FCOLL		0x10	/* force collision */
+#define RCVFCSE		0x08	/* receive FCS enable */
+#define LOOP_NONE	0x00	/* no loopback */
+#define LOOP_EXT	0x02	/* external loopback */
+#define LOOP_INT	0x04	/* internal loopback, excludes MENDEC */
+#define LOOP_MENDEC	0x06	/* internal loopback, includes MENDEC */
diff -u --recursive --new-file v2.1.50/linux/drivers/sbus/char/creator.c linux/drivers/sbus/char/creator.c
--- v2.1.50/linux/drivers/sbus/char/creator.c	Mon Aug  4 16:25:37 1997
+++ linux/drivers/sbus/char/creator.c	Sat Aug 16 10:00:28 1997
@@ -1,4 +1,4 @@
-/* $Id: creator.c,v 1.8 1997/07/22 06:14:12 davem Exp $
+/* $Id: creator.c,v 1.7 1997/07/17 02:21:47 davem Exp $
  * creator.c: Creator/Creator3D frame buffer driver
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
diff -u --recursive --new-file v2.1.50/linux/drivers/sbus/char/tcx.c linux/drivers/sbus/char/tcx.c
--- v2.1.50/linux/drivers/sbus/char/tcx.c	Mon Aug  4 16:25:38 1997
+++ linux/drivers/sbus/char/tcx.c	Sat Aug 16 10:00:30 1997
@@ -1,4 +1,4 @@
-/* $Id: tcx.c,v 1.18 1997/07/22 06:14:09 davem Exp $
+/* $Id: tcx.c,v 1.17 1997/07/17 02:21:50 davem Exp $
  * tcx.c: SUNW,tcx 24/8bit frame buffer driver
  *
  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
diff -u --recursive --new-file v2.1.50/linux/drivers/sbus/char/weitek.c linux/drivers/sbus/char/weitek.c
--- v2.1.50/linux/drivers/sbus/char/weitek.c	Mon Aug  4 16:25:38 1997
+++ linux/drivers/sbus/char/weitek.c	Sat Aug 16 10:00:30 1997
@@ -1,4 +1,4 @@
-/* $Id: weitek.c,v 1.15 1997/07/22 06:14:11 davem Exp $
+/* $Id: weitek.c,v 1.14 1997/07/17 02:21:53 davem Exp $
  * weitek.c: Tadpole P9100/P9000 console driver
  *
  * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
diff -u --recursive --new-file v2.1.50/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.1.50/linux/drivers/scsi/Config.in	Thu Aug 14 20:49:16 1997
+++ linux/drivers/scsi/Config.in	Sat Aug 16 09:53:08 1997
@@ -108,4 +108,9 @@
   fi
 dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
 #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
+dep_tristate 'MESH (Power Mac internal SCSI) support' CONFIG_SCSI_MESH $CONFIG_SCSI
+if [ "$CONFIG_SCSI_MESH" != "n" ]; then
+  int '  maximum synchronous transfer rate (MB/s) (0 = async)' CONFIG_SCSI_MESH_SYNC_RATE 5
+fi
+dep_tristate '53C94 (Power Mac external SCSI) support' CONFIG_SCSI_MAC53C94 $CONFIG_SCSI
 endmenu
diff -u --recursive --new-file v2.1.50/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v2.1.50/linux/drivers/scsi/Makefile	Mon Aug 11 14:47:05 1997
+++ linux/drivers/scsi/Makefile	Sat Aug 16 09:53:08 1997
@@ -273,6 +273,22 @@
   endif
 endif
 
+ifeq ($(CONFIG_SCSI_MESH),y)
+L_OBJS += mesh.o
+else
+  ifeq ($(CONFIG_SCSI_MESH),m)
+  M_OBJS += mesh.o
+  endif
+endif
+
+ifeq ($(CONFIG_SCSI_MAC53C94),y)
+L_OBJS += mac53c94.o
+else
+  ifeq ($(CONFIG_SCSI_MAC53C94),m)
+  M_OBJS += mac53c94.o
+  endif
+endif
+
 ifeq ($(CONFIG_SCSI_DEBUG),y)
 L_OBJS += scsi_debug.o
 else
diff -u --recursive --new-file v2.1.50/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c
--- v2.1.50/linux/drivers/scsi/hosts.c	Sat May 24 09:10:24 1997
+++ linux/drivers/scsi/hosts.c	Sat Aug 16 09:53:08 1997
@@ -186,6 +186,14 @@
 #include "ide-scsi.h"
 #endif
 
+#ifdef CONFIG_SCSI_MESH
+#include "mesh.h"
+#endif
+
+#ifdef CONFIG_SCSI_MAC53C94
+#include "mac53c94.h"
+#endif
+
 #ifdef CONFIG_SCSI_DEBUG
 #include "scsi_debug.h"
 #endif
@@ -338,6 +346,12 @@
 #endif
 #ifdef CONFIG_BLK_DEV_IDESCSI
     IDESCSI,
+#endif
+#ifdef CONFIG_SCSI_MESH
+    SCSI_MESH,
+#endif
+#ifdef CONFIG_SCSI_MAC53C94
+    SCSI_MAC53C94,
 #endif
 #ifdef CONFIG_SCSI_DEBUG
     SCSI_DEBUG,
diff -u --recursive --new-file v2.1.50/linux/drivers/scsi/mac53c94.c linux/drivers/scsi/mac53c94.c
--- v2.1.50/linux/drivers/scsi/mac53c94.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/mac53c94.c	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,502 @@
+/*
+ * SCSI low-level driver for the 53c94 SCSI bus adaptor found
+ * on Power Macintosh computers, controlling the external SCSI chain.
+ * We assume the 53c94 is connected to a DBDMA (descriptor-based DMA)
+ * controller.
+ *
+ * Paul Mackerras, August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#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/dbdma.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "mac53c94.h"
+
+struct proc_dir_entry proc_scsi_mac53c94 = {
+	PROC_SCSI_53C94, 5, "53c94",
+	S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+enum fsc_phase {
+	idle,
+	selecting,
+	dataing,
+	completing,
+	busfreeing,
+};
+
+struct fsc_state {
+	volatile struct	mac53c94_regs *regs;
+	int	intr;
+	volatile struct	dbdma_regs *dma;
+	int	dmaintr;
+	int	clk_freq;
+	struct	Scsi_Host *host;
+	struct	fsc_state *next;
+	Scsi_Cmnd *request_q;
+	Scsi_Cmnd *request_qtail;
+	Scsi_Cmnd *current_req;		/* req we're currently working on */
+	enum fsc_phase phase;		/* what we're currently trying to do */
+	struct dbdma_cmd *dma_cmds;	/* space for dbdma commands, aligned */
+};
+
+static struct fsc_state *all_53c94s;
+
+static void mac53c94_init(struct fsc_state *);
+static void mac53c94_start(struct fsc_state *);
+static void mac53c94_interrupt(int, void *, struct pt_regs *);
+static void cmd_done(struct fsc_state *, int result);
+static void set_dma_cmds(struct fsc_state *, Scsi_Cmnd *);
+static int data_goes_out(Scsi_Cmnd *);
+
+int
+mac53c94_detect(Scsi_Host_Template *tp)
+{
+	struct device_node *node;
+	int nfscs;
+	struct fsc_state *state, **prev_statep;
+	struct Scsi_Host *host;
+	void *dma_cmd_space;
+	unsigned char *clkprop;
+	int proplen;
+
+	nfscs = 0;
+	prev_statep = &all_53c94s;
+	for (node = find_devices("53c94"); node != 0; node = node->next) {
+		if (node->n_addrs != 2 || node->n_intrs != 2)
+			panic("53c94: expected 2 addrs and intrs (got %d/%d)",
+			      node->n_addrs, node->n_intrs);
+		host = scsi_register(tp, sizeof(struct fsc_state));
+		if (host == 0)
+			panic("couldn't register 53c94 host");
+		host->unique_id = nfscs;
+		note_scsi_host(node, host);
+
+		state = (struct fsc_state *) host->hostdata;
+		if (state == 0)
+			panic("no 53c94 state");
+		state->host = host;
+		state->regs = (volatile struct mac53c94_regs *)
+			node->addrs[0].address;
+		state->intr = node->intrs[0];
+		state->dma = (volatile struct dbdma_regs *)
+			node->addrs[1].address;
+		state->dmaintr = node->intrs[1];
+
+		clkprop = get_property(node, "clock-frequency", &proplen);
+		if (clkprop == NULL || proplen != sizeof(int)) {
+			printk(KERN_ERR "%s: can't get clock frequency\n",
+			       node->full_name);
+			state->clk_freq = 25000000;
+		} else
+			state->clk_freq = *(int *)clkprop;
+
+		/* Space for dma command list: +1 for stop command,
+		   +1 to allow for aligning. */
+		dma_cmd_space = kmalloc((host->sg_tablesize + 2) *
+					sizeof(struct dbdma_cmd), GFP_KERNEL);
+		if (dma_cmd_space == 0)
+			panic("53c94: couldn't allocate dma command space");
+		state->dma_cmds = (struct dbdma_cmd *)
+			DBDMA_ALIGN(dma_cmd_space);
+		memset(state->dma_cmds, 0, (host->sg_tablesize + 1)
+		       * sizeof(struct dbdma_cmd));
+
+		*prev_statep = state;
+		prev_statep = &state->next;
+
+		if (request_irq(state->intr, mac53c94_interrupt, 0,
+				"53C94", state)) {
+			printk(KERN_ERR "mac53C94: can't get irq %d\n", state->intr);
+		}
+
+		mac53c94_init(state);
+
+		++nfscs;
+	}
+	return nfscs;
+}
+
+int
+mac53c94_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+{
+	unsigned long flags;
+	struct fsc_state *state;
+
+#if 0
+	if (data_goes_out(cmd)) {
+		int i;
+		printk(KERN_DEBUG "mac53c94_queue %p: command is", cmd);
+		for (i = 0; i < cmd->cmd_len; ++i)
+			printk(" %.2x", cmd->cmnd[i]);
+		printk("\n" KERN_DEBUG "use_sg=%d request_bufflen=%d request_buffer=%p\n",
+		       cmd->use_sg, cmd->request_bufflen, cmd->request_buffer);
+	}
+#endif
+
+	cmd->scsi_done = done;
+	cmd->host_scribble = NULL;
+
+	state = (struct fsc_state *) cmd->host->hostdata;
+
+	save_flags(flags);
+	cli();
+	if (state->request_q == NULL)
+		state->request_q = cmd;
+	else
+		state->request_qtail->host_scribble = (void *) cmd;
+	state->request_qtail = cmd;
+
+	if (state->phase == idle)
+		mac53c94_start(state);
+
+	restore_flags(flags);
+	return 0;
+}
+
+int
+mac53c94_abort(Scsi_Cmnd *cmd)
+{
+	return SCSI_ABORT_SNOOZE;
+}
+
+int
+mac53c94_reset(Scsi_Cmnd *cmd, unsigned how)
+{
+	struct fsc_state *state = (struct fsc_state *) cmd->host->hostdata;
+	volatile struct mac53c94_regs *regs = state->regs;
+	volatile struct dbdma_regs *dma = state->dma;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	st_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+	regs->command = CMD_SCSI_RESET;	/* assert RST */
+	eieio();
+	udelay(100);			/* leave it on for a while (>= 25us) */
+	regs->command = CMD_RESET;
+	eieio();
+	udelay(20);
+	mac53c94_init(state);
+	regs->command = CMD_NOP;
+	eieio();
+	restore_flags(flags);
+	return SCSI_RESET_PENDING;
+}
+
+int
+mac53c94_command(Scsi_Cmnd *cmd)
+{
+	printk(KERN_DEBUG "whoops... mac53c94_command called\n");
+	return -1;
+}
+
+static void
+mac53c94_init(struct fsc_state *state)
+{
+	volatile struct mac53c94_regs *regs = state->regs;
+	volatile struct dbdma_regs *dma = state->dma;
+	int x;
+
+	regs->config1 = state->host->this_id | CF1_PAR_ENABLE;
+	regs->sel_timeout = TIMO_VAL(250);	/* 250ms */
+	regs->clk_factor = CLKF_VAL(state->clk_freq);
+	regs->config2 = CF2_FEATURE_EN;
+	regs->config3 = 0;
+	regs->sync_period = 0;
+	regs->sync_offset = 0;
+	eieio();
+	x = regs->interrupt;
+	st_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+}
+
+/*
+ * Start the next command for a 53C94.
+ * Should be called with interrupts disabled.
+ */
+static void
+mac53c94_start(struct fsc_state *state)
+{
+	Scsi_Cmnd *cmd;
+	volatile struct mac53c94_regs *regs = state->regs;
+	int i;
+
+	if (state->phase != idle || state->current_req != NULL)
+		panic("inappropriate mac53c94_start (state=%p)", state);
+	if (state->request_q == NULL)
+		return;
+	state->current_req = cmd = state->request_q;
+	state->request_q = (Scsi_Cmnd *) cmd->host_scribble;
+
+	/* Off we go */
+	regs->count_lo = 0;
+	regs->count_mid = 0;
+	regs->count_hi = 0;
+	eieio();
+	regs->command = CMD_NOP + CMD_DMA_MODE;
+	udelay(1);
+	eieio();
+	regs->command = CMD_FLUSH;
+	udelay(1);
+	eieio();
+	regs->dest_id = cmd->target;
+	regs->sync_period = 0;
+	regs->sync_offset = 0;
+	eieio();
+
+	/* load the command into the FIFO */
+	for (i = 0; i < cmd->cmd_len; ++i) {
+		regs->fifo = cmd->cmnd[i];
+		eieio();
+	}
+
+	/* do select without ATN XXX */
+	regs->command = CMD_SELECT;
+	state->phase = selecting;
+
+	if (cmd->use_sg > 0 || cmd->request_bufflen != 0)
+		set_dma_cmds(state, cmd);
+}
+
+static void
+mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+	struct fsc_state *state = (struct fsc_state *) dev_id;
+	volatile struct mac53c94_regs *regs = state->regs;
+	volatile struct dbdma_regs *dma = state->dma;
+	Scsi_Cmnd *cmd = state->current_req;
+	int nb, stat, seq, intr;
+	static int mac53c94_errors;
+
+	/*
+	 * Apparently, reading the interrupt register unlatches
+	 * the status and sequence step registers.
+	 */
+	seq = regs->seqstep;
+	stat = regs->status;
+	intr = regs->interrupt;
+
+#if 0
+	printk(KERN_DEBUG "mac53c94_intr, intr=%x stat=%x seq=%x phase=%d\n",
+	       intr, stat, seq, state->phase);
+#endif
+
+	if (intr & INTR_RESET) {
+		/* SCSI bus was reset */
+		printk(KERN_INFO "external SCSI bus reset detected\n");
+		regs->command = CMD_NOP;
+		st_le32(&dma->control, RUN << 16);	/* stop dma */
+		cmd_done(state, DID_RESET << 16);
+		return;
+	}
+	if (intr & INTR_ILL_CMD) {
+		printk(KERN_ERR "53c94: illegal cmd, intr=%x stat=%x seq=%x phase=%d\n",
+		       intr, stat, seq, state->phase);
+		cmd_done(state, DID_ERROR << 16);
+		return;
+	}
+	if (stat & STAT_ERROR) {
+#if 0
+		/* XXX these seem to be harmless? */
+		printk("53c94: bad error, intr=%x stat=%x seq=%x phase=%d\n",
+		       intr, stat, seq, state->phase);
+#endif
+		++mac53c94_errors;
+		regs->command = CMD_NOP + CMD_DMA_MODE;
+		eieio();
+	}
+	if (cmd == 0) {
+		printk(KERN_DEBUG "53c94: interrupt with no command active?\n");
+		return;
+	}
+	if (stat & STAT_PARITY) {
+		printk(KERN_ERR "mac53c94: parity error\n");
+		cmd_done(state, DID_PARITY << 16);
+		return;
+	}
+	switch (state->phase) {
+	case selecting:
+		if (intr & INTR_DISCONNECT) {
+			/* selection timed out */
+			cmd_done(state, DID_BAD_TARGET << 16);
+			return;
+		}
+		if (intr != INTR_BUS_SERV + INTR_DONE) {
+			printk(KERN_DEBUG "got intr %x during selection\n", intr);
+			cmd_done(state, DID_ERROR << 16);
+			return;
+		}
+		if ((seq & SS_MASK) != SS_DONE) {
+			printk(KERN_DEBUG "seq step %x after command\n", seq);
+			cmd_done(state, DID_ERROR << 16);
+			return;
+		}
+		regs->command = CMD_NOP;
+		/* set DMA controller going if any data to transfer */
+		if ((stat & (STAT_MSG|STAT_CD)) == 0
+		    && (cmd->use_sg > 0 || cmd->request_bufflen != 0)) {
+			nb = cmd->SCp.this_residual;
+			if (nb > 0xfff0)
+				nb = 0xfff0;
+			cmd->SCp.this_residual -= nb;
+			regs->count_lo = nb;
+			regs->count_mid = nb >> 8;
+			eieio();
+			regs->command = CMD_DMA_MODE + CMD_NOP;
+			eieio();
+			st_le32(&dma->cmdptr, virt_to_phys(state->dma_cmds));
+			st_le32(&dma->control, (RUN << 16) | RUN);
+			eieio();
+			regs->command = CMD_DMA_MODE + CMD_XFER_DATA;
+			state->phase = dataing;
+			break;
+		} else if ((stat & STAT_PHASE) == STAT_CD + STAT_IO) {
+			/* up to status phase already */
+			regs->command = CMD_I_COMPLETE;
+			state->phase = completing;
+		} else {
+			printk(KERN_DEBUG "in unexpected phase %x after cmd\n",
+			       stat & STAT_PHASE);
+			cmd_done(state, DID_ERROR << 16);
+			return;
+		}
+		break;
+
+	case dataing:
+		if (intr != INTR_BUS_SERV) {
+			printk(KERN_DEBUG "got intr %x before status\n", intr);
+			cmd_done(state, DID_ERROR << 16);
+			return;
+		}
+		if (cmd->SCp.this_residual != 0
+		    && (stat & (STAT_MSG|STAT_CD)) == 0) {
+			/* Set up the count regs to transfer more */
+			nb = cmd->SCp.this_residual;
+			if (nb > 0xfff0)
+				nb = 0xfff0;
+			cmd->SCp.this_residual -= nb;
+			regs->count_lo = nb;
+			regs->count_mid = nb >> 8;
+			eieio();
+			regs->command = CMD_DMA_MODE + CMD_NOP;
+			eieio();
+			regs->command = CMD_DMA_MODE + CMD_XFER_DATA;
+			break;
+		}
+		if ((stat & STAT_PHASE) != STAT_CD + STAT_IO) {
+			printk(KERN_DEBUG "intr %x before data xfer complete\n", intr);
+		}
+		st_le32(&dma->control, RUN << 16);	/* stop dma */
+		/* should check dma status */
+		regs->command = CMD_I_COMPLETE;
+		state->phase = completing;
+		break;
+	case completing:
+		if (intr != INTR_DONE) {
+			printk(KERN_DEBUG "got intr %x on completion\n", intr);
+			cmd_done(state, DID_ERROR << 16);
+			return;
+		}
+		cmd->SCp.Status = regs->fifo; eieio();
+		cmd->SCp.Message = regs->fifo; eieio();
+		cmd->result = 
+		regs->command = CMD_ACCEPT_MSG;
+		state->phase = busfreeing;
+		break;
+	case busfreeing:
+		if (intr != INTR_DISCONNECT) {
+			printk(KERN_DEBUG "got intr %x when expected disconnect\n", intr);
+		}
+		cmd_done(state, (DID_OK << 16) + (cmd->SCp.Message << 8)
+			 + cmd->SCp.Status);
+		break;
+	default:
+		printk(KERN_DEBUG "don't know about phase %d\n", state->phase);
+	}
+}
+
+static void
+cmd_done(struct fsc_state *state, int result)
+{
+	Scsi_Cmnd *cmd;
+
+	cmd = state->current_req;
+	if (cmd != 0) {
+		cmd->result = result;
+		(*cmd->scsi_done)(cmd);
+		state->current_req = NULL;
+	}
+	state->phase = idle;
+	mac53c94_start(state);
+}
+
+/*
+ * Set up DMA commands for transferring data.
+ */
+static void
+set_dma_cmds(struct fsc_state *state, Scsi_Cmnd *cmd)
+{
+	int i, dma_cmd, total;
+	struct scatterlist *scl;
+	struct dbdma_cmd *dcmds;
+
+	dma_cmd = data_goes_out(cmd)? OUTPUT_MORE: INPUT_MORE;
+	dcmds = state->dma_cmds;
+	if (cmd->use_sg > 0) {
+		total = 0;
+		scl = (struct scatterlist *) cmd->buffer;
+		for (i = 0; i < cmd->use_sg; ++i) {
+			if (scl->length > 0xffff)
+				panic("mac53c94: scatterlist element >= 64k");
+			total += scl->length;
+			st_le16(&dcmds->req_count, scl->length);
+			st_le16(&dcmds->command, dma_cmd);
+			st_le32(&dcmds->phy_addr, virt_to_phys(scl->address));
+			dcmds->xfer_status = 0;
+			++scl;
+			++dcmds;
+		}
+	} else {
+		total = cmd->request_bufflen;
+		if (total > 0xffff)
+			panic("mac53c94: transfer size >= 64k");
+		st_le16(&dcmds->req_count, total);
+		st_le32(&dcmds->phy_addr, virt_to_phys(cmd->request_buffer));
+		dcmds->xfer_status = 0;
+		++dcmds;
+	}
+	dma_cmd += OUTPUT_LAST - OUTPUT_MORE;
+	st_le16(&dcmds[-1].command, dma_cmd);
+	st_le16(&dcmds->command, DBDMA_STOP);
+	cmd->SCp.this_residual = total;
+}
+
+/*
+ * Work out whether data will be going out from the host adaptor or into it.
+ * (If this information is available from somewhere else in the scsi
+ * code, somebody please let me know :-)
+ */
+static int
+data_goes_out(Scsi_Cmnd *cmd)
+{
+	switch (cmd->cmnd[0]) {
+	case WRITE_6:
+	case WRITE_10:
+	case WRITE_12:		/* any others? */
+		return 1;
+	default:
+		return 0;
+	}
+}
diff -u --recursive --new-file v2.1.50/linux/drivers/scsi/mac53c94.h linux/drivers/scsi/mac53c94.h
--- v2.1.50/linux/drivers/scsi/mac53c94.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/mac53c94.h	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,246 @@
+/*
+ * mac53c94.h: definitions for the driver for the 53c94 SCSI bus adaptor
+ * found on Power Macintosh computers, controlling the external SCSI chain.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#ifndef _MAC53C94_H
+#define _MAC53C94_H
+
+extern struct proc_dir_entry proc_scsi_mac53c94;
+
+int mac53c94_detect(Scsi_Host_Template *);
+int mac53c94_command(Scsi_Cmnd *);
+int mac53c94_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int mac53c94_abort(Scsi_Cmnd *);
+int mac53c94_reset(Scsi_Cmnd *, unsigned int);
+
+#define SCSI_MAC53C94 {					\
+	NULL,			/* next */		\
+	NULL,			/* usage_count */	\
+	&proc_scsi_mac53c94,	/* proc_dir */		\
+	NULL,			/* proc_info */		\
+	"53C94",		/* name */		\
+	mac53c94_detect,	/* detect */		\
+	NULL,			/* release */		\
+	NULL,			/* info */		\
+	mac53c94_command,	/* command */		\
+	mac53c94_queue,		/* queuecommand */	\
+	mac53c94_abort,		/* abort */		\
+	mac53c94_reset,		/* reset */		\
+	NULL,			/* slave_attach */	\
+	NULL,			/* bios_param */	\
+	1,			/* can_queue */		\
+	7,			/* this_id */		\
+	SG_ALL,			/* sg_tablesize */	\
+	1,			/* cmd_per_lun */	\
+	0,			/* present */		\
+	0,			/* unchecked_isa_dma */	\
+	DISABLE_CLUSTERING,	/* use_clustering */	\
+}
+
+/*
+ * Registers in the 53C94 controller.
+ */
+
+struct mac53c94_regs {
+	unsigned char	count_lo;
+	char pad0[15];
+	unsigned char	count_mid;
+	char pad1[15];
+	unsigned char	fifo;
+	char pad2[15];
+	unsigned char	command;
+	char pad3[15];
+	unsigned char	status;
+	char pad4[15];
+	unsigned char	interrupt;
+	char pad5[15];
+	unsigned char	seqstep;
+	char pad6[15];
+	unsigned char	flags;
+	char pad7[15];
+	unsigned char	config1;
+	char pad8[15];
+	unsigned char	clk_factor;
+	char pad9[15];
+	unsigned char	test;
+	char pad10[15];
+	unsigned char	config2;
+	char pad11[15];
+	unsigned char	config3;
+	char pad12[15];
+	unsigned char	config4;
+	char pad13[15];
+	unsigned char	count_hi;
+	char pad14[15];
+	unsigned char	fifo_res;
+	char pad15[15];
+};
+
+/*
+ * Alternate functions for some registers.
+ */
+#define dest_id		status
+#define sel_timeout	interrupt
+#define sync_period	seqstep
+#define sync_offset	flags
+
+/*
+ * Bits in command register.
+ */
+#define CMD_DMA_MODE	0x80
+#define CMD_MODE_MASK	0x70
+#define CMD_MODE_INIT	0x10
+#define CMD_MODE_TARG	0x20
+#define CMD_MODE_DISC	0x40
+
+#define CMD_NOP		0
+#define CMD_FLUSH	1
+#define CMD_RESET	2
+#define CMD_SCSI_RESET	3
+
+#define CMD_XFER_DATA	0x10
+#define CMD_I_COMPLETE	0x11
+#define CMD_ACCEPT_MSG	0x12
+#define CMD_XFER_PAD	0x18
+#define CMD_SET_ATN	0x1a
+#define CMD_CLR_ATN	0x1b
+
+#define CMD_SEND_MSG	0x20
+#define CMD_SEND_STATUS	0x21
+#define CMD_SEND_DATA	0x22
+#define CMD_DISC_SEQ	0x23
+#define CMD_TERMINATE	0x24
+#define CMD_T_COMPLETE	0x25
+#define CMD_DISCONNECT	0x27
+#define CMD_RECV_MSG	0x28
+#define CMD_RECV_CDB	0x29
+#define CMD_RECV_DATA	0x2a
+#define CMD_RECV_CMD	0x2b
+#define CMD_ABORT_DMA	0x04
+
+#define CMD_RESELECT	0x40
+#define CMD_SELECT	0x41
+#define CMD_SELECT_ATN	0x42
+#define CMD_SELATN_STOP	0x43
+#define CMD_ENABLE_SEL	0x44
+#define CMD_DISABLE_SEL	0x45
+#define CMD_SEL_ATN3	0x46
+#define CMD_RESEL_ATN3	0x47
+
+/*
+ * Bits in status register.
+ */
+#define STAT_IRQ	0x80
+#define STAT_ERROR	0x40
+#define STAT_PARITY	0x20
+#define STAT_TC_ZERO	0x10
+#define STAT_DONE	0x08
+#define STAT_PHASE	0x07
+#define STAT_MSG	0x04
+#define STAT_CD		0x02
+#define STAT_IO		0x01
+
+/*
+ * Bits in interrupt register.
+ */
+#define INTR_RESET	0x80	/* SCSI bus was reset */
+#define INTR_ILL_CMD	0x40	/* illegal command */
+#define INTR_DISCONNECT	0x20	/* we got disconnected */
+#define INTR_BUS_SERV	0x10	/* bus service requested */
+#define INTR_DONE	0x08	/* function completed */
+#define INTR_RESELECTED	0x04	/* we were reselected */
+#define INTR_SEL_ATN	0x02	/* we were selected, ATN asserted */
+#define INTR_SELECT	0x01	/* we were selected, ATN negated */
+
+/*
+ * Encoding for the select timeout.
+ */
+#define TIMO_VAL(x)	((x) * 5000 / 7682)
+
+/*
+ * Bits in sequence step register.
+ */
+#define SS_MASK		7
+#define SS_ARB_SEL	0	/* Selection & arbitration complete */
+#define SS_MSG_SENT	1	/* One message byte sent */
+#define SS_NOT_CMD	2	/* Not in command phase */
+#define SS_PHASE_CHG	3	/* Early phase change, cmd bytes lost */
+#define SS_DONE		4	/* Command was sent OK */
+
+/*
+ * Encoding for sync transfer period.
+ */
+#define SYNCP_MASK	0x1f
+#define SYNCP_MIN	4
+#define SYNCP_MAX	31
+
+/*
+ * Bits in flags register.
+ */
+#define FLAGS_FIFO_LEV	0x1f
+#define FLAGS_SEQ_STEP	0xe0
+
+/*
+ * Encoding for sync offset.
+ */
+#define SYNCO_MASK	0x0f
+#define SYNCO_ASS_CTRL	0x30	/* REQ/ACK assertion control */
+#define SYNCO_NEG_CTRL	0xc0	/* REQ/ACK negation control */
+
+/*
+ * Bits in config1 register.
+ */
+#define CF1_SLOW_CABLE	0x80	/* Slow cable mode */
+#define CF1_NO_RES_REP	0x40	/* Disable SCSI reset reports */
+#define CF1_PAR_TEST	0x20	/* Parity test mode enable */
+#define CF1_PAR_ENABLE	0x10	/* Enable parity checks */
+#define CF1_TEST	0x08	/* Chip tests */
+#define CF1_MY_ID	0x07	/* Controller's address on bus */
+
+/*
+ * Encoding for clk_factor register.
+ */
+#define CLKF_MASK	7
+#define CLKF_VAL(freq)	((((freq) + 4999999) / 5000000) & CLKF_MASK)
+
+/*
+ * Bits in test mode register.
+ */
+#define TEST_TARGET	1	/* target test mode */
+#define TEST_INITIATOR	2	/* initiator test mode */
+#define TEST_TRISTATE	4	/* tristate (hi-z) test mode */
+
+/*
+ * Bits in config2 register.
+ */
+#define CF2_RFB		0x80
+#define CF2_FEATURE_EN	0x40	/* enable features / phase latch */
+#define CF2_BYTECTRL	0x20
+#define CF2_DREQ_HIZ	0x10
+#define CF2_SCSI2	0x08
+#define CF2_PAR_ABORT	0x04	/* bad parity target abort */
+#define CF2_REG_PARERR	0x02	/* register parity error */
+#define CF2_DMA_PARERR	0x01	/* DMA parity error */
+
+/*
+ * Bits in the config3 register.
+ */
+#define CF3_ID_MSG_CHK	0x80
+#define CF3_3B_MSGS	0x40
+#define CF3_CDB10	0x20
+#define CF3_FASTSCSI	0x10	/* enable fast SCSI support */
+#define CF3_FASTCLOCK	0x08
+#define CF3_SAVERESID	0x04
+#define CF3_ALT_DMA	0x02
+#define CF3_THRESH_8	0x01
+
+/*
+ * Bits in the config4 register.
+ */
+#define CF4_EAN		0x04
+#define CF4_TEST	0x02
+#define CF4_BBTE	0x01
+
+#endif /* _MAC53C94_H */
diff -u --recursive --new-file v2.1.50/linux/drivers/scsi/mesh.c linux/drivers/scsi/mesh.c
--- v2.1.50/linux/drivers/scsi/mesh.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/mesh.c	Sat Aug 16 10:09:10 1997
@@ -0,0 +1,1321 @@
+/*
+ * SCSI low-level driver for the MESH (Macintosh Enhanced SCSI Hardware)
+ * bus adaptor found on Power Macintosh computers.
+ * We assume the MESH is connected to a DBDMA (descriptor-based DMA)
+ * controller.
+ *
+ * Paul Mackerras, August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#include <linux/config.h>
+
+#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 <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <asm/dbdma.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "mesh.h"
+
+#if 0
+#undef KERN_DEBUG
+#define KERN_DEBUG KERN_WARNING
+#endif
+
+#if CONFIG_SCSI_MESH_SYNC_RATE == 0
+int mesh_sync_period = 100;
+int mesh_sync_offset = 0;
+#else
+int mesh_sync_period = 1000 / CONFIG_SCSI_MESH_SYNC_RATE;	/* ns */
+int mesh_sync_offset = 15;
+#endif
+
+int mesh_sync_targets = 0xff;	/* targets to set synchronous (bitmap) */
+int mesh_resel_targets = 0xff;	/* targets that we let disconnect (bitmap) */
+int mesh_debug_targets = 0;	/* print debug for these targets */
+
+#define ALLOW_SYNC(tgt)		((mesh_sync_targets >> (tgt)) & 1)
+#define ALLOW_RESEL(tgt)	((mesh_resel_targets >> (tgt)) & 1)
+#define ALLOW_DEBUG(tgt)	((mesh_debug_targets >> (tgt)) & 1)
+#define DEBUG_TARGET(cmd)	((cmd) && ALLOW_DEBUG((cmd)->target))
+
+struct proc_dir_entry proc_scsi_mesh = {
+	PROC_SCSI_MESH, 4, "mesh",
+	S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+enum mesh_phase {
+	idle,
+	arbitrating,
+	selecting,
+	commanding,
+	dataing,
+	statusing,
+	busfreeing,
+	disconnecting,
+	reselecting
+};
+
+enum msg_phase {
+	msg_none,
+	msg_out,
+	msg_out_xxx,
+	msg_out_last,
+	msg_in,
+};
+
+enum sdtr_phase {
+	do_sdtr,
+	sdtr_sent,
+	sdtr_done
+};
+
+struct mesh_target {
+	enum sdtr_phase sdtr_state;
+	enum mesh_phase phase;
+	int	sync_params;
+	int	data_goes_out;
+	Scsi_Cmnd *current_req;
+	u32	saved_ptr;
+};
+
+struct mesh_state {
+	volatile struct	mesh_regs *mesh;
+	int	meshintr;
+	volatile struct	dbdma_regs *dma;
+	int	dmaintr;
+	struct	Scsi_Host *host;
+	struct	mesh_state *next;
+	Scsi_Cmnd *request_q;
+	Scsi_Cmnd *request_qtail;
+	enum mesh_phase phase;		/* what we're currently trying to do */
+	enum msg_phase msgphase;
+	int	conn_tgt;		/* target we're connected to */
+	Scsi_Cmnd *current_req;		/* req we're currently working on */
+	int	data_ptr;
+	int	data_goes_out;		/* guess as to data direction */
+	int	dma_started;
+	int	dma_count;
+	int	expect_reply;
+	int	n_msgin;
+	u8	msgin[16];
+	int	n_msgout;
+	int	last_n_msgout;
+	u8	msgout[16];
+	struct dbdma_cmd *dma_cmds;	/* space for dbdma commands, aligned */
+	int	clk_freq;
+	struct mesh_target tgts[8];
+	struct tq_struct tqueue;
+	Scsi_Cmnd *completed_q;
+	Scsi_Cmnd *completed_qtail;
+};
+
+static struct mesh_state *all_meshes;
+
+static void mesh_init(struct mesh_state *);
+static int mesh_notify_reboot(struct notifier_block *, unsigned long, void *);
+static void mesh_dump_regs(struct mesh_state *);
+static void mesh_start(struct mesh_state *);
+static void finish_cmds(void *);
+static void add_sdtr_msg(struct mesh_state *);
+static void set_sdtr(struct mesh_state *, int, int);
+static void start_phase(struct mesh_state *);
+static void get_msgin(struct mesh_state *);
+static int msgin_length(struct mesh_state *);
+static void cmd_complete(struct mesh_state *);
+static void phase_mismatch(struct mesh_state *);
+static void reselected(struct mesh_state *);
+static void handle_reset(struct mesh_state *);
+static void mesh_interrupt(int, void *, struct pt_regs *);
+static void handle_msgin(struct mesh_state *);
+static void mesh_done(struct mesh_state *);
+static void mesh_completed(struct mesh_state *, Scsi_Cmnd *);
+static void set_dma_cmds(struct mesh_state *, Scsi_Cmnd *);
+static void halt_dma(struct mesh_state *);
+static int data_goes_out(Scsi_Cmnd *);
+
+static struct notifier_block mesh_notifier = {
+	mesh_notify_reboot,
+	NULL,
+	0
+};
+
+int
+mesh_detect(Scsi_Host_Template *tp)
+{
+	struct device_node *mesh;
+	int nmeshes, tgt, *cfp, minper;
+	struct mesh_state *ms, **prev_statep;
+	struct Scsi_Host *mesh_host;
+	void *dma_cmd_space;
+
+	nmeshes = 0;
+	prev_statep = &all_meshes;
+	for (mesh = find_devices("mesh"); mesh != 0; mesh = mesh->next) {
+		if (mesh->n_addrs != 2 || mesh->n_intrs != 2)
+			panic("mesh: expected 2 addrs and intrs (got %d/%d)",
+			      mesh->n_addrs, mesh->n_intrs);
+		mesh_host = scsi_register(tp, sizeof(struct mesh_state));
+		if (mesh_host == 0)
+			panic("couldn't register mesh host");
+		mesh_host->unique_id = nmeshes;
+		note_scsi_host(mesh, mesh_host);
+
+		ms = (struct mesh_state *) mesh_host->hostdata;
+		if (ms == 0)
+			panic("no mesh state");
+		memset(ms, 0, sizeof(*ms));
+		ms->host = mesh_host;
+		ms->mesh = (volatile struct mesh_regs *)
+			mesh->addrs[0].address;
+		ms->meshintr = mesh->intrs[0];
+		ms->dma = (volatile struct dbdma_regs *)
+			mesh->addrs[1].address;
+		ms->dmaintr = mesh->intrs[1];
+
+		/* Space for dma command list: +1 for stop command,
+		   +1 to allow for aligning. */
+		dma_cmd_space = kmalloc((mesh_host->sg_tablesize + 2) *
+					sizeof(struct dbdma_cmd), GFP_KERNEL);
+		if (dma_cmd_space == 0)
+			panic("mesh: couldn't allocate dma command space");
+		ms->dma_cmds = (struct dbdma_cmd *) DBDMA_ALIGN(dma_cmd_space);
+		memset(ms->dma_cmds, 0, (mesh_host->sg_tablesize + 1)
+		       * sizeof(struct dbdma_cmd));
+
+		ms->current_req = 0;
+		for (tgt = 0; tgt < 8; ++tgt) {
+			ms->tgts[tgt].sdtr_state = do_sdtr;
+			ms->tgts[tgt].sync_params = ASYNC_PARAMS;
+			ms->tgts[tgt].current_req = 0;
+		}
+
+		ms->tqueue.routine = finish_cmds;
+		ms->tqueue.data = ms;
+
+		*prev_statep = ms;
+		prev_statep = &ms->next;
+
+		if (request_irq(ms->meshintr, mesh_interrupt, 0, "MESH", ms)) {
+			printk(KERN_ERR "MESH: can't get irq %d\n", ms->meshintr);
+		}
+
+		cfp = (int *) get_property(mesh, "clock-frequency", NULL);
+		if (cfp) {
+			ms->clk_freq = *cfp;
+		} else {
+			printk(KERN_INFO "mesh: assuming 50MHz clock frequency\n");
+			ms->clk_freq = 50000000;
+		}
+		/* The maximum sync rate is clock / 5; increase
+		   mesh_sync_period if necessary. */
+		minper = 1000000000 / (ms->clk_freq / 5);	/* ns */
+		if (mesh_sync_period < minper)
+			mesh_sync_period = minper;
+
+		mesh_init(ms);
+
+		++nmeshes;
+	}
+	if (nmeshes > 0)
+		register_reboot_notifier(&mesh_notifier);
+
+	return nmeshes;
+}
+
+int
+mesh_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+{
+	unsigned long flags;
+	struct mesh_state *ms;
+
+#if 0
+	if (data_goes_out(cmd)) {
+		printk(KERN_DEBUG "mesh_queue %p: command is", cmd);
+		for (i = 0; i < cmd->cmd_len; ++i)
+			printk(" %.2x", cmd->cmnd[i]);
+		printk("\n" KERN_DEBUG "use_sg=%d request_bufflen=%d request_buffer=%p\n",
+		       cmd->use_sg, cmd->request_bufflen, cmd->request_buffer);
+	}
+#endif
+
+	cmd->scsi_done = done;
+	cmd->host_scribble = NULL;
+
+	ms = (struct mesh_state *) cmd->host->hostdata;
+
+	save_flags(flags);
+	cli();
+	if (ms->request_q == NULL)
+		ms->request_q = cmd;
+	else
+		ms->request_qtail->host_scribble = (void *) cmd;
+	ms->request_qtail = cmd;
+
+	if (ms->phase == idle)
+		mesh_start(ms);
+
+	restore_flags(flags);
+	return 0;
+}
+
+int
+mesh_abort(Scsi_Cmnd *cmd)
+{
+	printk(KERN_DEBUG "mesh_abort(%p)\n", cmd);
+	mesh_dump_regs((struct mesh_state *)(cmd->host->hostdata));
+	return SCSI_ABORT_SNOOZE;
+}
+
+static void
+mesh_dump_regs(struct mesh_state *ms)
+{
+	volatile struct mesh_regs *mr = ms->mesh;
+	volatile struct dbdma_regs *md = ms->dma;
+	int t;
+	struct mesh_target *tp;
+
+	printk(KERN_DEBUG "mesh: state at %p, regs at %p, dma at %p\n",
+	       ms, mr, md);
+	printk(KERN_DEBUG "    ct=%4x seq=%2x bs=%4x fc=%2x exc=%2x err=%2x sp=%2x\n",
+	       (mr->count_hi << 8) + mr->count_lo, mr->sequence,
+	       (mr->bus_status1 << 8) + mr->bus_status0, mr->fifo_count,
+	       mr->exception, mr->error, mr->sync_params);
+	printk(KERN_DEBUG "    dma stat=%x cmdptr=%x\n",
+	       in_le32(&md->status), in_le32(&md->cmdptr));
+	printk(KERN_DEBUG "    phase=%d msgphase=%d conn_tgt=%d data_ptr=%d\n",
+	       ms->phase, ms->msgphase, ms->conn_tgt, ms->data_ptr);
+	printk(KERN_DEBUG "    goes_out=%d dma_st=%d dma_ct=%d n_msgout=%d\n",
+	       ms->data_goes_out, ms->dma_started, ms->dma_count, ms->n_msgout);
+	for (t = 0; t < 8; ++t) {
+		tp = &ms->tgts[t];
+		if (tp->current_req == NULL)
+			continue;
+		printk(KERN_DEBUG "    target %d: req=%p phase=%d saved_ptr=%d\n",
+		       t, tp->current_req, tp->phase, tp->saved_ptr);
+	}
+}
+
+int
+mesh_reset(Scsi_Cmnd *cmd, unsigned how)
+{
+	struct mesh_state *ms = (struct mesh_state *) cmd->host->hostdata;
+	volatile struct mesh_regs *mr = ms->mesh;
+	volatile struct dbdma_regs *md = ms->dma;
+	unsigned long flags;
+	int ret;
+
+	printk(KERN_DEBUG "mesh_reset %x\n", how);
+	ret = SCSI_RESET_BUS_RESET;
+	save_flags(flags);
+	cli();
+	out_8(&mr->exception, 0xff);	/* clear all exception bits */
+	out_8(&mr->error, 0xff);	/* clear all error bits */
+	out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+	if (how & SCSI_RESET_SUGGEST_HOST_RESET) {
+		out_8(&mr->sequence, SEQ_RESETMESH);
+		ret |= SCSI_RESET_HOST_RESET;
+		udelay(1);
+		out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+	}
+	out_8(&mr->bus_status1, BS1_RST);	/* assert RST */
+	udelay(30);			/* leave it on for >= 25us */
+	out_8(&mr->bus_status1, 0);	/* negate RST */
+#ifdef DO_ASYNC_RESET
+	if (how & SCSI_RESET_ASYNCHRONOUS) {
+		restore_flags(flags);
+		ret |= SCSI_RESET_PENDING;
+	} else
+#endif
+	{
+		out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+		handle_reset(ms);
+		restore_flags(flags);
+		finish_cmds(ms);
+		ret |= SCSI_RESET_SUCCESS;
+	}
+	return ret;
+}
+
+/*
+ * If we leave drives set for synchronous transfers (especially
+ * CDROMs), and reboot to MacOS, it gets confused, poor thing.
+ * So, on reboot we reset the SCSI bus.
+ */
+static int
+mesh_notify_reboot(struct notifier_block *this, unsigned long code, void *x)
+{
+	struct mesh_state *ms;
+	volatile struct mesh_regs *mr;
+
+	if (code == SYS_DOWN || code == SYS_HALT) {
+		printk(KERN_INFO "resetting MESH scsi bus(es)\n");
+		for (ms = all_meshes; ms != 0; ms = ms->next) {
+			mr = ms->mesh;
+			out_8(&mr->intr_mask, 0);
+			out_8(&mr->interrupt,
+			      INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+			out_8(&mr->bus_status1, BS1_RST);
+			udelay(30);
+			out_8(&mr->bus_status1, 0);
+		}
+	}
+	return NOTIFY_DONE;
+}
+
+int
+mesh_command(Scsi_Cmnd *cmd)
+{
+	printk(KERN_WARNING "whoops... mesh_command called\n");
+	return -1;
+}
+
+static void
+mesh_init(struct mesh_state *ms)
+{
+	volatile struct mesh_regs *mr = ms->mesh;
+	volatile struct dbdma_regs *md = ms->dma;
+
+	out_8(&mr->interrupt, 0xff);	/* clear all interrupt bits */
+	out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+	out_8(&mr->source_id, ms->host->this_id);
+	out_8(&mr->sel_timeout, 25);	/* 250ms */
+	out_8(&mr->sync_params, ASYNC_PARAMS);	/* asynchronous initially */
+	out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+}
+
+/*
+ * Start the next command for a MESH.
+ * Should be called with interrupts disabled.
+ */
+static void
+mesh_start(struct mesh_state *ms)
+{
+	Scsi_Cmnd *cmd, *prev, *next;
+	volatile struct mesh_regs *mr = ms->mesh;
+
+	if (ms->phase != idle || ms->current_req != NULL)
+		panic("inappropriate mesh_start (ms=%p)", ms);
+
+	prev = NULL;
+	for (cmd = ms->request_q; ; cmd = (Scsi_Cmnd *) cmd->host_scribble) {
+		if (cmd == NULL)
+			return;
+		if (ms->tgts[cmd->target].current_req == NULL)
+			break;
+		prev = cmd;
+	}
+	next = (Scsi_Cmnd *) cmd->host_scribble;
+	if (prev == NULL)
+		ms->request_q = next;
+	else
+		prev->host_scribble = (void *) next;
+	if (next == NULL)
+		ms->request_qtail = prev;
+
+	ms->current_req = cmd;
+	ms->data_goes_out = data_goes_out(cmd);
+	ms->tgts[cmd->target].current_req = cmd;
+
+#if 1
+	if (DEBUG_TARGET(cmd)) {
+		int i;
+		printk(KERN_DEBUG "mesh_start: %p ser=%lu tgt=%d cmd=",
+		       cmd, cmd->serial_number, cmd->target);
+		for (i = 0; i < cmd->cmd_len; ++i)
+			printk(" %x", cmd->cmnd[i]);
+		printk(" use_sg=%d buffer=%p bufflen=%u\n",
+		       cmd->use_sg, cmd->request_buffer, cmd->request_bufflen);
+	}
+#endif
+
+	/* Off we go */
+	out_8(&mr->sequence, SEQ_ARBITRATE);
+
+	ms->phase = arbitrating;
+	ms->msgphase = msg_none;
+	ms->data_ptr = 0;
+	ms->dma_started = 0;
+	ms->n_msgout = 0;
+	ms->last_n_msgout = 0;
+	ms->expect_reply = 0;
+	ms->conn_tgt = cmd->target;
+	ms->tgts[cmd->target].saved_ptr = 0;
+}
+
+static void
+finish_cmds(void *data)
+{
+	struct mesh_state *ms = data;
+	Scsi_Cmnd *cmd;
+	unsigned long flags;
+
+	for (;;) {
+		save_flags(flags);
+		cli();
+		cmd = ms->completed_q;
+		if (cmd == NULL) {
+			restore_flags(flags);
+			break;
+		}
+		ms->completed_q = (Scsi_Cmnd *) cmd->host_scribble;
+		restore_flags(flags);
+		(*cmd->scsi_done)(cmd);
+	}
+}
+
+static inline void
+add_sdtr_msg(struct mesh_state *ms)
+{
+	int i = ms->n_msgout;
+
+	ms->msgout[i] = EXTENDED_MESSAGE;
+	ms->msgout[i+1] = 3;
+	ms->msgout[i+2] = EXTENDED_SDTR;
+	ms->msgout[i+3] = mesh_sync_period/4;
+	ms->msgout[i+4] = (ALLOW_SYNC(ms->conn_tgt)? mesh_sync_offset: 0);
+	ms->n_msgout = i + 5;
+}
+
+static void
+set_sdtr(struct mesh_state *ms, int period, int offset)
+{
+	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+	volatile struct mesh_regs *mr = ms->mesh;
+	int v, tr;
+
+	tp->sdtr_state = sdtr_done;
+	if (offset == 0) {
+		/* asynchronous */
+		if (SYNC_OFF(tp->sync_params))
+			printk(KERN_INFO "mesh: target %d now asynchronous\n",
+			       ms->conn_tgt);
+		tp->sync_params = ASYNC_PARAMS;
+		out_8(&mr->sync_params, ASYNC_PARAMS);
+		return;
+	}
+	/*
+	 * We need to compute ceil(clk_freq * period / 500e6) - 2
+	 * without incurring overflow.
+	 */
+	v = (ms->clk_freq / 5000) * period;
+	if (v <= 250000) {
+		/* special case: sync_period == 5 * clk_period */
+		v = 0;
+		/* units of tr are 100kB/s */
+		tr = (ms->clk_freq + 250000) / 500000;
+	} else {
+		/* sync_period == (v + 2) * 2 * clk_period */
+		v = (v + 99999) / 100000 - 2;
+		if (v > 15)
+			v = 15;	/* oops */
+		tr = ((ms->clk_freq / (v + 2)) + 199999) / 200000;
+	}
+	if (offset > 15)
+		offset = 15;	/* can't happen */
+	tp->sync_params = SYNC_PARAMS(offset, v);
+	out_8(&mr->sync_params, tp->sync_params);
+	printk(KERN_INFO "mesh: target %d synchronous at %d.%d MB/s\n",
+	       ms->conn_tgt, tr/10, tr%10);
+}
+
+static void
+start_phase(struct mesh_state *ms)
+{
+	int i, seq, nb;
+	volatile struct mesh_regs *mr = ms->mesh;
+	volatile struct dbdma_regs *md = ms->dma;
+	Scsi_Cmnd *cmd = ms->current_req;
+	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+
+	if (cmd == 0) {
+		printk(KERN_ERR "mesh: start_phase but no cmd?\n");
+		return;
+	}
+	seq = SEQ_ACTIVE_NEG + (ms->n_msgout? SEQ_ATN: 0);
+	switch (ms->msgphase) {
+	case msg_none:
+		break;
+
+	case msg_in:
+		out_8(&mr->count_hi, 0);
+		out_8(&mr->count_lo, 1);
+		out_8(&mr->sequence, SEQ_MSGIN + seq);
+		ms->n_msgin = 0;
+		return;
+
+	case msg_out:
+		/*
+		 * To make sure ATN drops before we assert ACK for
+		 * the last byte of the message, we have to do the
+		 * last byte specially.
+		 */
+		if (DEBUG_TARGET(cmd)) {
+			printk(KERN_DEBUG "mesh: sending %d msg bytes:",
+			       ms->n_msgout);
+			for (i = 0; i < ms->n_msgout; ++i)
+				printk(" %x", ms->msgout[i]);
+			printk("\n");
+		}
+		out_8(&mr->count_hi, 0);
+		if (ms->n_msgout == 1) {
+			out_8(&mr->count_lo, 1);
+			out_8(&mr->sequence, SEQ_MSGOUT + SEQ_ACTIVE_NEG);
+			udelay(1);
+			out_8(&mr->fifo, ms->msgout[0]);
+			ms->msgphase = msg_out_last;
+		} else {
+			out_8(&mr->count_lo, ms->n_msgout - 1);
+			out_8(&mr->sequence, SEQ_MSGOUT + seq);
+			for (i = 0; i < ms->n_msgout - 1; ++i)
+				out_8(&mr->fifo, ms->msgout[i]);
+		}
+		return;
+
+	default:
+		printk(KERN_ERR "mesh bug: start_phase msgphase=%d\n",
+		       ms->msgphase);
+	}
+
+	switch (ms->phase) {
+	case selecting:
+		out_8(&mr->dest_id, cmd->target);
+		out_8(&mr->sequence, SEQ_SELECT + SEQ_ATN);
+		break;
+	case commanding:
+		out_8(&mr->sync_params, tp->sync_params);
+		out_8(&mr->count_hi, 0);
+		out_8(&mr->count_lo, cmd->cmd_len);
+		out_8(&mr->sequence, SEQ_COMMAND + seq);
+		for (i = 0; i < cmd->cmd_len; ++i)
+			out_8(&mr->fifo, cmd->cmnd[i]);
+		break;
+	case dataing:
+		/* transfer data, if any */
+		if (!ms->dma_started) {
+			set_dma_cmds(ms, cmd);
+			out_le32(&md->cmdptr, virt_to_phys(ms->dma_cmds));
+			out_le32(&md->control, (RUN << 16) | RUN);
+			ms->dma_started = 1;
+		}
+		nb = ms->dma_count;
+		if (nb > 0xfff0)
+			nb = 0xfff0;
+		ms->dma_count -= nb;
+		ms->data_ptr += nb;
+		out_8(&mr->count_lo, nb);
+		out_8(&mr->count_hi, nb >> 8);
+		out_8(&mr->sequence, (ms->data_goes_out?
+				SEQ_DATAOUT: SEQ_DATAIN) + SEQ_DMA_MODE + seq);
+		break;
+	case statusing:
+		out_8(&mr->count_hi, 0);
+		out_8(&mr->count_lo, 1);
+		out_8(&mr->sequence, SEQ_STATUS + seq);
+		break;
+	case busfreeing:
+	case disconnecting:
+		out_8(&mr->sequence, SEQ_ENBRESEL);
+		udelay(1);
+		out_8(&mr->sequence, SEQ_BUSFREE);
+		break;
+	default:
+		printk(KERN_ERR "mesh: start_phase called with phase=%d\n",
+		       ms->phase);
+	}
+
+}
+
+static inline void
+get_msgin(struct mesh_state *ms)
+{
+	volatile struct mesh_regs *mr = ms->mesh;
+	int i, n;
+
+	n = mr->fifo_count;
+	if (n != 0) {
+		i = ms->n_msgin;
+		ms->n_msgin = i + n;
+		for (; n > 0; --n)
+			ms->msgin[i++] = in_8(&mr->fifo);
+	}
+}
+
+static inline int
+msgin_length(struct mesh_state *ms)
+{
+	int b, n;
+
+	n = 1;
+	if (ms->n_msgin > 0) {
+		b = ms->msgin[0];
+		if (b == 1) {
+			/* extended message */
+			n = ms->n_msgin < 2? 2: ms->msgin[1] + 2;
+		} else if (0x20 <= b && b <= 0x2f) {
+			/* 2-byte message */
+			n = 2;
+		}
+	}
+	return n;
+}
+
+static void
+cmd_complete(struct mesh_state *ms)
+{
+	volatile struct mesh_regs *mr = ms->mesh;
+	Scsi_Cmnd *cmd = ms->current_req;
+	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+	int seq, n, t;
+
+	seq = SEQ_ACTIVE_NEG + (ms->n_msgout? SEQ_ATN: 0);
+	switch (ms->msgphase) {
+	case msg_out_xxx:
+		/* huh?  we expected a phase mismatch */
+		ms->n_msgin = 0;
+		ms->msgphase = msg_in;
+		/* fall through */
+
+	case msg_in:
+		/* should have some message bytes in fifo */
+		get_msgin(ms);
+		n = msgin_length(ms);
+		if (ms->n_msgin < n) {
+			out_8(&mr->count_lo, n - ms->n_msgin);
+			out_8(&mr->sequence, SEQ_MSGIN + seq);
+		} else {
+			ms->msgphase = msg_none;
+			handle_msgin(ms);
+			start_phase(ms);
+		}
+		break;
+
+	case msg_out:
+		/*
+		 * To get the right timing on ATN wrt ACK, we have
+		 * to get the MESH to drop ACK, wait until REQ gets
+		 * asserted, then drop ATN.  To do this we first
+		 * issue a SEQ_MSGOUT with ATN and wait for REQ,
+		 * then change the command to a SEQ_MSGOUT w/o ATN.
+		 * If we don't see REQ in a reasonable time, we
+		 * change the command to SEQ_MSGIN with ATN,
+		 * wait for the phase mismatch interrupt, then
+		 * issue the SEQ_MSGOUT without ATN.
+		 */
+		out_8(&mr->count_lo, 1);
+		out_8(&mr->sequence, SEQ_MSGOUT + SEQ_ACTIVE_NEG + SEQ_ATN);
+		t = 30;		/* wait up to 30us */
+		while ((mr->bus_status0 & BS0_REQ) == 0 && --t >= 0)
+			udelay(1);
+		if (mr->bus_status0 & BS0_REQ) {
+			out_8(&mr->sequence, SEQ_MSGOUT + SEQ_ACTIVE_NEG);
+			udelay(1);
+			out_8(&mr->fifo, ms->msgout[ms->n_msgout-1]);
+			ms->msgphase = msg_out_last;
+		} else {
+			out_8(&mr->sequence, SEQ_MSGIN + SEQ_ACTIVE_NEG + SEQ_ATN);
+			ms->msgphase = msg_out_xxx;
+		}
+		break;
+
+	case msg_out_last:
+		ms->last_n_msgout = ms->n_msgout;
+		ms->n_msgout = 0;
+		ms->msgphase = ms->expect_reply? msg_in: msg_none;
+		start_phase(ms);
+		break;
+
+	case msg_none:
+		switch (ms->phase) {
+		case selecting:
+			ms->msgout[0] = IDENTIFY(ALLOW_RESEL(cmd->target), cmd->lun);
+			ms->n_msgout = 1;
+			ms->expect_reply = 0;
+			if (tp->sdtr_state == do_sdtr) {
+				/* add SDTR message */
+				add_sdtr_msg(ms);
+				ms->expect_reply = 1;
+				tp->sdtr_state = sdtr_sent;
+			}
+			ms->msgphase = msg_out;
+			/*
+			 * We need to wait for REQ before dropping ATN.
+			 * We wait for at most 30us, then fall back to
+			 * a scheme where we issue a SEQ_COMMAND with ATN,
+			 * which will give us a phase mismatch interrupt
+			 * when REQ does come, and then we send the message.
+			 */
+			t = 30;		/* wait up to 30us */
+			while ((mr->bus_status0 & BS0_REQ) == 0) {
+				if (--t < 0) {
+					ms->msgphase = msg_none;
+					break;
+				}
+				udelay(1);
+			}
+			break;
+		case dataing:
+			if (ms->dma_count != 0) {
+				start_phase(ms);
+				return;
+			}
+			halt_dma(ms);
+			break;
+		case statusing:
+			cmd->SCp.Status = mr->fifo;
+			cmd->result = (DID_OK << 16) + cmd->SCp.Status;
+			ms->msgphase = msg_in;
+			if (DEBUG_TARGET(cmd))
+				printk(KERN_DEBUG "mesh: status is %x\n",
+				       cmd->SCp.Status);
+			break;
+		case busfreeing:
+			mesh_done(ms);
+			return;
+		case disconnecting:
+			ms->current_req = 0;
+			ms->phase = idle;
+			mesh_start(ms);
+			return;
+		default:
+			break;
+		}
+		++ms->phase;
+		start_phase(ms);
+		break;
+	}
+}
+
+static void phase_mismatch(struct mesh_state *ms)
+{
+	volatile struct mesh_regs *mr = ms->mesh;
+	int phase;
+
+	phase = mr->bus_status0 & BS0_PHASE;
+	if (ms->msgphase == msg_out_xxx && phase == BP_MSGOUT) {
+		/* output the last byte of the message, without ATN */
+		out_8(&mr->count_lo, 1);
+		out_8(&mr->sequence, SEQ_MSGOUT + SEQ_ACTIVE_NEG);
+		udelay(1);
+		out_8(&mr->fifo, ms->msgout[ms->n_msgout-1]);
+		ms->msgphase = msg_out_last;
+		return;
+	}
+
+	if (ms->msgphase == msg_in) {
+		get_msgin(ms);
+		if (ms->n_msgin)
+			handle_msgin(ms);
+	}
+
+	if (ms->dma_started)
+		halt_dma(ms);
+	if (mr->fifo_count) {
+		out_8(&mr->sequence, SEQ_FLUSHFIFO);
+		udelay(1);
+	}
+
+	ms->msgphase = msg_none;
+	switch (phase) {
+	case BP_DATAIN:
+		ms->data_goes_out = 0;
+		ms->phase = dataing;
+		break;
+	case BP_DATAOUT:
+		ms->data_goes_out = 1;
+		ms->phase = dataing;
+		break;
+	case BP_COMMAND:
+		ms->phase = commanding;
+		break;
+	case BP_STATUS:
+		ms->phase = statusing;
+		break;
+	case BP_MSGIN:
+		ms->msgphase = msg_in;
+		ms->n_msgin = 0;
+		break;
+	case BP_MSGOUT:
+		ms->msgphase = msg_out;
+		if (ms->n_msgout == 0) {
+			if (ms->last_n_msgout == 0) {
+				printk(KERN_DEBUG "mesh: no msg to repeat\n");
+				ms->msgout[0] = NOP;
+				ms->last_n_msgout = 1;
+			}
+			ms->n_msgout = ms->last_n_msgout;
+		}
+		break;
+	default:
+		printk(KERN_DEBUG "mesh: unknown scsi phase %x\n", phase);
+		ms->current_req->result = DID_ERROR << 16;
+		mesh_done(ms);
+		return;
+	}
+
+	start_phase(ms);
+}
+
+static void
+reselected(struct mesh_state *ms)
+{
+	volatile struct mesh_regs *mr = ms->mesh;
+	Scsi_Cmnd *cmd = ms->current_req;
+	struct mesh_target *tp;
+	int b, t;
+
+	switch (ms->phase) {
+	case idle:
+	case arbitrating:
+		break;
+	case busfreeing:
+		ms->phase = reselecting;
+		mesh_done(ms);
+		cmd = NULL;
+		break;
+	case disconnecting:
+		cmd = NULL;
+		break;
+	default:
+		printk(KERN_ERR "mesh: reselected in phase %d/%d\n",
+		       ms->msgphase, ms->phase);
+	}
+	if (cmd) {
+		/* put the command back on the queue */
+		cmd->host_scribble = (void *) ms->request_q;
+		if (ms->request_q == NULL)
+			ms->request_qtail = cmd;
+		ms->request_q = cmd;
+		tp = &ms->tgts[cmd->target];
+		tp->current_req = NULL;
+		ms->current_req = NULL;
+	}
+
+	/*
+	 * Find out who reselected us.
+	 */
+	if (mr->fifo_count == 0) {
+		printk(KERN_ERR "mesh: reselection but nothing in fifo?\n");
+		return;
+	}
+	/* get the last byte in the fifo */
+	do {
+		b = in_8(&mr->fifo);
+	} while (in_8(&mr->fifo_count));
+	for (t = 0; t < 8; ++t)
+		if ((b & (1 << t)) != 0 && t != ms->host->this_id)
+			break;
+	if (b != (1 << t) + (1 << ms->host->this_id)) {
+		printk(KERN_ERR "mesh: bad reselection data %x\n", b);
+		return;
+	}
+
+	/*
+	 * Set up to continue with that target's transfer.
+	 */
+	tp = &ms->tgts[t];
+	if (ALLOW_DEBUG(t)) {
+		printk(KERN_DEBUG "mesh: reselected by target %d\n", t);
+		printk(KERN_DEBUG "mesh: saved_ptr=%x phase=%d cmd=%p\n",
+		       tp->saved_ptr, tp->phase, tp->current_req);
+	}
+	if (tp->current_req == NULL) {
+		printk(KERN_ERR "mesh: reselected by tgt %d but no cmd!\n", t);
+		return;
+	}
+	ms->current_req = tp->current_req;
+	ms->phase = tp->phase;
+	ms->msgphase = msg_in;
+	ms->data_goes_out = tp->data_goes_out;
+	ms->data_ptr = tp->saved_ptr;
+	ms->conn_tgt = t;
+	ms->dma_started = 0;
+	ms->n_msgout = 0;
+	ms->last_n_msgout = 0;
+	out_8(&mr->sync_params, tp->sync_params);
+	start_phase(ms);
+}
+
+static void
+handle_reset(struct mesh_state *ms)
+{
+	int tgt;
+	struct mesh_target *tp;
+	Scsi_Cmnd *cmd;
+	volatile struct mesh_regs *mr = ms->mesh;
+
+	for (tgt = 0; tgt < 8; ++tgt) {
+		tp = &ms->tgts[tgt];
+		if ((cmd = tp->current_req) != NULL) {
+			cmd->result = DID_RESET << 16;
+			tp->current_req = NULL;
+			mesh_completed(ms, cmd);
+		}
+		ms->tgts[tgt].sdtr_state = do_sdtr;
+		ms->tgts[tgt].sync_params = ASYNC_PARAMS;
+	}
+	ms->current_req = NULL;
+	while ((cmd = ms->request_q) != NULL) {
+		ms->request_q = (Scsi_Cmnd *) cmd->host_scribble;
+		cmd->result = DID_RESET << 16;
+		mesh_completed(ms, cmd);
+	}
+	ms->phase = idle;
+	out_8(&mr->sync_params, ASYNC_PARAMS);
+}
+
+static void
+mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+	struct mesh_state *ms = (struct mesh_state *) dev_id;
+	volatile struct mesh_regs *mr = ms->mesh;
+	Scsi_Cmnd *cmd = ms->current_req;
+	int stat, exc, err, intr;
+
+#if 0
+	if (DEBUG_TARGET(cmd))
+		printk(KERN_DEBUG "mesh_intr, bs0=%x int=%x exc=%x err=%x phase=%d msgphase=%d\n",
+		       mr->bus_status0, mr->interrupt, mr->exception, mr->error, ms->phase, ms->msgphase);
+#endif
+	while ((intr = in_8(&mr->interrupt)) != 0) {
+		if (intr & INT_ERROR) {
+			stat = DID_BAD_INTR << 16;
+			err = in_8(&mr->error);
+			exc = in_8(&mr->exception);
+			out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+			if (err & ERR_SCSIRESET) {
+				/* SCSI bus was reset */
+				printk(KERN_INFO "mesh: SCSI bus reset detected: "
+				       "waiting for end...");
+				while ((mr->bus_status1 & BS1_RST) != 0)
+					udelay(1);
+				printk("done\n");
+				handle_reset(ms);
+				/* request_q is empty, no point in mesh_start() */
+				continue;
+			} else if (err & ERR_UNEXPDISC) {
+				/* Unexpected disconnect */
+				printk(KERN_WARNING "mesh: target %d aborted\n",
+				       ms->conn_tgt);
+				stat = DID_ABORT << 16;
+			} else if (err & ERR_PARITY) {
+				printk(KERN_ERR "mesh: parity error\n");
+				stat = DID_PARITY << 16;
+			} else if ((err & ERR_SEQERR) && (exc & EXC_RESELECTED)
+				   && ms->phase == arbitrating) {
+				/* This can happen if we issue a command to
+				   get the bus just after the target
+				   reselects us. */
+				static int mesh_resel_seqerr;
+				mesh_resel_seqerr++;
+				reselected(ms);
+				continue;
+			} else {
+				printk(KERN_ERR "mesh: error %x (exc = %x)\n",
+				       err, exc);
+				mesh_dump_regs(ms);
+			}
+			if (cmd != 0) {
+				cmd->result = stat;
+				mesh_done(ms);
+			}
+
+		} else if (intr & INT_EXCEPTION) {
+			exc = in_8(&mr->exception);
+			out_8(&mr->interrupt, INT_EXCEPTION | INT_CMDDONE);
+			if (exc & EXC_RESELECTED) {
+				static int mesh_resel_exc;
+				mesh_resel_exc++;
+				reselected(ms);
+			} else if (cmd && exc == EXC_ARBLOST
+				   && ms->phase == arbitrating) {
+				printk(KERN_DEBUG "mesh: lost arbitration\n");
+				cmd->result = DID_BUS_BUSY << 16;
+				mesh_done(ms);
+			} else if (cmd && exc == EXC_SELTO && ms->phase == selecting) {
+				/* selection timed out */
+				cmd->result = DID_BAD_TARGET << 16;
+				mesh_done(ms);
+			} else if (cmd && exc == EXC_PHASEMM
+				   && (mr->bus_status0 & BS0_REQ) != 0) {
+				/* target wants to do something different:
+			   find out what it wants and do it. */
+				phase_mismatch(ms);
+			} else {
+				printk(KERN_ERR "mesh: can't cope with exception %x\n",
+				       exc);
+				cmd->result = DID_ERROR << 16;
+				mesh_done(ms);
+			}
+
+		} else if (intr & INT_CMDDONE) {
+			out_8(&mr->interrupt, INT_CMDDONE);
+			cmd_complete(ms);
+		}
+	}
+}
+
+static void
+handle_msgin(struct mesh_state *ms)
+{
+	int i;
+	Scsi_Cmnd *cmd = ms->current_req;
+	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+
+	if (ms->n_msgin == 0)
+		return;
+	if (DEBUG_TARGET(cmd)) {
+		printk(KERN_DEBUG "got %d message bytes:", ms->n_msgin);
+		for (i = 0; i < ms->n_msgin; ++i)
+			printk(" %x", ms->msgin[i]);
+		printk("\n");
+	}
+
+	ms->expect_reply = 0;
+	ms->n_msgout = 0;
+	if (ms->n_msgin < msgin_length(ms))
+		goto reject;
+	if (cmd)
+		cmd->SCp.Message = ms->msgin[0];
+	switch (ms->msgin[0]) {
+	case COMMAND_COMPLETE:
+		break;
+	case EXTENDED_MESSAGE:
+		switch (ms->msgin[2]) {
+		case EXTENDED_MODIFY_DATA_POINTER:
+			ms->data_ptr += (ms->msgin[3] << 24) + ms->msgin[6]
+				+ (ms->msgin[4] << 16) + (ms->msgin[5] << 8);
+			break;
+		case EXTENDED_SDTR:
+			if (tp->sdtr_state != sdtr_sent) {
+				/* reply with an SDTR */
+				add_sdtr_msg(ms);
+				/* limit period to at least his value,
+				   offset to no more than his */
+				if (ms->msgout[3] < ms->msgin[3])
+					ms->msgout[3] = ms->msgin[3];
+				if (ms->msgout[4] > ms->msgin[4])
+					ms->msgout[4] = ms->msgin[4];
+				set_sdtr(ms, ms->msgout[3], ms->msgout[4]);
+				ms->msgphase = msg_out;
+			} else {
+				set_sdtr(ms, ms->msgin[3], ms->msgin[4]);
+			}
+			break;
+		default:
+			goto reject;
+		}
+		break;
+	case SAVE_POINTERS:
+		tp->saved_ptr = ms->data_ptr;
+		break;
+	case RESTORE_POINTERS:
+		ms->data_ptr = tp->saved_ptr;
+		break;
+	case DISCONNECT:
+		tp->phase = ms->phase;
+		tp->data_goes_out = ms->data_goes_out;
+		ms->phase = disconnecting;
+		break;
+	case ABORT:
+		break;
+	case MESSAGE_REJECT:
+		if (tp->sdtr_state == sdtr_sent)
+			set_sdtr(ms, 0, 0);
+		break;
+	case NOP:
+		break;
+	default:
+		if (cmd && IDENTIFY_BASE <= ms->msgin[0]
+		    && ms->msgin[0] <= IDENTIFY_BASE + 7) {
+			i = ms->msgin[0] - IDENTIFY_BASE;
+			if (i != cmd->lun)
+				printk(KERN_WARNING "mesh: lun mismatch "
+				       "(%d != %d) on reselection from "
+				       "target %d\n", i, cmd->lun,
+				       ms->conn_tgt);
+			break;
+		}
+		goto reject;
+	}
+	return;
+
+ reject:
+	printk(KERN_WARNING "mesh: rejecting message %x from target %d\n",
+	       ms->msgin[0], ms->conn_tgt);
+	ms->msgout[0] = MESSAGE_REJECT;
+	ms->n_msgout = 1;
+	ms->msgphase = msg_out;
+}
+
+static void
+mesh_done(struct mesh_state *ms)
+{
+	Scsi_Cmnd *cmd;
+	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+
+	cmd = ms->current_req;
+	if (DEBUG_TARGET(cmd)) {
+		printk(KERN_DEBUG "mesh_done: result = %x, data_ptr=%d, buflen=%d\n",
+		       cmd->result, ms->data_ptr, cmd->request_bufflen);
+		if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12 || cmd->cmnd[0] == 3)
+		    && cmd->request_buffer != 0) {
+			unsigned char *b = cmd->request_buffer;
+			printk(KERN_DEBUG "buffer = %x %x %x %x %x %x %x %x\n",
+			       b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
+		}
+	}
+	tp->current_req = 0;
+	cmd->SCp.this_residual -= ms->data_ptr;
+	ms->current_req = NULL;
+	mesh_completed(ms, cmd);
+	if (ms->phase != reselecting) {
+		ms->phase = idle;
+		mesh_start(ms);
+	}
+}
+
+static void
+mesh_completed(struct mesh_state *ms, Scsi_Cmnd *cmd)
+{
+	if (ms->completed_q == NULL)
+		ms->completed_q = cmd;
+	else
+		ms->completed_qtail->host_scribble = (void *) cmd;
+	ms->completed_qtail = cmd;
+	cmd->host_scribble = NULL;
+	queue_task(&ms->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+/*
+ * Set up DMA commands for transferring data.
+ */
+static void
+set_dma_cmds(struct mesh_state *ms, Scsi_Cmnd *cmd)
+{
+	int i, dma_cmd, total, off, dtot;
+	struct scatterlist *scl;
+	struct dbdma_cmd *dcmds;
+
+	dma_cmd = ms->data_goes_out? OUTPUT_MORE: INPUT_MORE;
+	dcmds = ms->dma_cmds;
+	dtot = 0;
+	cmd->SCp.this_residual = cmd->request_bufflen;
+	if (cmd->use_sg > 0) {
+		total = 0;
+		scl = (struct scatterlist *) cmd->buffer;
+		off = ms->data_ptr;
+		for (i = 0; i < cmd->use_sg; ++i, ++scl) {
+			total += scl->length;
+			if (off >= scl->length) {
+				off -= scl->length;
+				continue;
+			}
+			if (scl->length > 0xffff)
+				panic("mesh: scatterlist element >= 64k");
+			st_le16(&dcmds->req_count, scl->length - off);
+			st_le16(&dcmds->command, dma_cmd);
+			st_le32(&dcmds->phy_addr,
+				virt_to_phys(scl->address) + off);
+			dcmds->xfer_status = 0;
+			++dcmds;
+			dtot += scl->length - off;
+			off = 0;
+		}
+	} else if (ms->data_ptr < cmd->request_bufflen) {
+		dtot = cmd->request_bufflen - ms->data_ptr;
+		if (dtot > 0xffff)
+			panic("mesh: transfer size >= 64k");
+		st_le16(&dcmds->req_count, dtot);
+		st_le32(&dcmds->phy_addr,
+			virt_to_phys(cmd->request_buffer) + ms->data_ptr);
+		dcmds->xfer_status = 0;
+		++dcmds;
+	}
+	if (dtot == 0) {
+		/* Either the target has overrun our buffer,
+		   or the caller didn't provide a buffer. */
+		static char mesh_extra_buf[64];
+
+		if (cmd->request_bufflen != 0)
+			printk(KERN_DEBUG "mesh: target %d overrun, "
+			       "data_ptr=%x total=%x goes_out=%d\n",
+			       ms->conn_tgt, ms->data_ptr,
+			       cmd->request_bufflen, ms->data_goes_out);
+		dtot = sizeof(mesh_extra_buf);
+		st_le16(&dcmds->req_count, dtot);
+		st_le32(&dcmds->phy_addr, virt_to_phys(mesh_extra_buf));
+		dcmds->xfer_status = 0;
+		++dcmds;
+	}
+	dma_cmd += OUTPUT_LAST - OUTPUT_MORE;
+	st_le16(&dcmds[-1].command, dma_cmd);
+	memset(dcmds, 0, sizeof(*dcmds));
+	st_le16(&dcmds->command, DBDMA_STOP);
+	ms->dma_count = dtot;
+}
+
+static void
+halt_dma(struct mesh_state *ms)
+{
+	volatile struct dbdma_regs *md = ms->dma;
+	volatile struct mesh_regs *mr = ms->mesh;
+	int t, nb;
+
+	if (!ms->data_goes_out) {
+		/* wait a little while until the fifo drains */
+		t = 50;
+		while (t > 0 && mr->fifo_count != 0
+		       && (in_le32(&md->status) & ACTIVE) != 0) {
+			--t;
+			udelay(1);
+		}
+	}
+	out_le32(&md->control, RUN << 16);	/* turn off RUN bit */
+	nb = (mr->count_hi << 8) + mr->count_lo;
+	if (ms->data_goes_out)
+		nb += mr->fifo_count;
+	/* nb is the number of bytes not yet transferred
+	   to/from the target. */
+	ms->data_ptr -= nb;
+	if (ms->data_ptr < 0) {
+		printk(KERN_ERR "mesh: halt_dma: data_ptr=%d (nb=%d, ms=%p)\n",
+		       ms->data_ptr, nb, ms);
+		ms->data_ptr = 0;
+	}
+	ms->dma_started = 0;
+}
+
+/*
+ * Work out whether we expect data to go out from the host adaptor or into it.
+ * (If this information is available from somewhere else in the scsi
+ * code, somebody please let me know :-)
+ */
+static int
+data_goes_out(Scsi_Cmnd *cmd)
+{
+	switch (cmd->cmnd[0]) {
+	case MODE_SELECT:
+	case MODE_SELECT_10:
+	case WRITE_6:
+	case WRITE_10:
+	case WRITE_12:		/* any others? */
+		return 1;
+	default:
+		return 0;
+	}
+}
diff -u --recursive --new-file v2.1.50/linux/drivers/scsi/mesh.h linux/drivers/scsi/mesh.h
--- v2.1.50/linux/drivers/scsi/mesh.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/mesh.h	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,159 @@
+/*
+ * mesh.h: definitions for the driver for the MESH SCSI bus adaptor
+ * (Macintosh Enhanced SCSI Hardware) found on Power Macintosh computers.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#ifndef _MESH_H
+#define _MESH_H
+
+extern struct proc_dir_entry proc_scsi_mesh;
+
+int mesh_detect(Scsi_Host_Template *);
+int mesh_command(Scsi_Cmnd *);
+int mesh_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int mesh_abort(Scsi_Cmnd *);
+int mesh_reset(Scsi_Cmnd *, unsigned int);
+
+#define SCSI_MESH {					\
+	NULL,			/* next */		\
+	NULL,			/* usage_count */	\
+	&proc_scsi_mesh,	/* proc_dir */		\
+	NULL,			/* proc_info */		\
+	"MESH",			/* name */		\
+	mesh_detect,		/* detect */		\
+	NULL,			/* release */		\
+	NULL,			/* info */		\
+	mesh_command,		/* command */		\
+	mesh_queue,		/* queuecommand */	\
+	mesh_abort,		/* abort */		\
+	mesh_reset,		/* reset */		\
+	NULL,			/* slave_attach */	\
+	NULL,			/* bios_param */	\
+	20,			/* can_queue */		\
+	7,			/* this_id */		\
+	SG_ALL,			/* sg_tablesize */	\
+	2,			/* cmd_per_lun */	\
+	0,			/* present */		\
+	0,			/* unchecked_isa_dma */	\
+	DISABLE_CLUSTERING,	/* use_clustering */	\
+}
+
+/*
+ * Registers in the MESH controller.
+ */
+
+struct mesh_regs {
+	unsigned char	count_lo;
+	char pad0[15];
+	unsigned char	count_hi;
+	char pad1[15];
+	unsigned char	fifo;
+	char pad2[15];
+	unsigned char	sequence;
+	char pad3[15];
+	unsigned char	bus_status0;
+	char pad4[15];
+	unsigned char	bus_status1;
+	char pad5[15];
+	unsigned char	fifo_count;
+	char pad6[15];
+	unsigned char	exception;
+	char pad7[15];
+	unsigned char	error;
+	char pad8[15];
+	unsigned char	intr_mask;
+	char pad9[15];
+	unsigned char	interrupt;
+	char pad10[15];
+	unsigned char	source_id;
+	char pad11[15];
+	unsigned char	dest_id;
+	char pad12[15];
+	unsigned char	sync_params;
+	char pad13[15];
+	unsigned char	mesh_id;
+	char pad14[15];
+	unsigned char	sel_timeout;
+	char pad15[15];
+};
+
+/* Bits in the sequence register. */
+#define SEQ_DMA_MODE	0x80	/* use DMA for data transfer */
+#define SEQ_TARGET	0x40	/* put the controller into target mode */
+#define SEQ_ATN		0x20	/* assert ATN signal */
+#define SEQ_ACTIVE_NEG	0x10	/* use active negation on REQ/ACK */
+#define SEQ_CMD		0x0f	/* command bits: */
+#define SEQ_ARBITRATE	1	/*  get the bus */
+#define SEQ_SELECT	2	/*  select a target */
+#define SEQ_COMMAND	3	/*  send a command */
+#define SEQ_STATUS	4	/*  receive status */
+#define SEQ_DATAOUT	5	/*  send data */
+#define SEQ_DATAIN	6	/*  receive data */
+#define SEQ_MSGOUT	7	/*  send a message */
+#define SEQ_MSGIN	8	/*  receive a message */
+#define SEQ_BUSFREE	9	/*  look for bus free */
+#define SEQ_ENBPARITY	0x0a	/*  enable parity checking */
+#define SEQ_DISPARITY	0x0b	/*  disable parity checking */
+#define SEQ_ENBRESEL	0x0c	/*  enable reselection */
+#define SEQ_DISRESEL	0x0d	/*  disable reselection */
+#define SEQ_RESETMESH	0x0e	/*  reset the controller */
+#define SEQ_FLUSHFIFO	0x0f	/*  clear out the FIFO */
+
+/* Bits in the bus_status0 and bus_status1 registers:
+   these correspond directly to the SCSI bus control signals. */
+#define BS0_REQ		0x20
+#define BS0_ACK		0x10
+#define BS0_ATN		0x08
+#define BS0_MSG		0x04
+#define BS0_CD		0x02
+#define BS0_IO		0x01
+#define BS1_RST		0x80
+#define BS1_BSY		0x40
+#define BS1_SEL		0x20
+
+/* Bus phases defined by the bits in bus_status0 */
+#define BS0_PHASE	(BS0_MSG+BS0_CD+BS0_IO)
+#define BP_DATAOUT	0
+#define BP_DATAIN	BS0_IO
+#define BP_COMMAND	BS0_CD
+#define BP_STATUS	(BS0_CD+BS0_IO)
+#define BP_MSGOUT	(BS0_MSG+BS0_CD)
+#define BP_MSGIN	(BS0_MSG+BS0_CD+BS0_IO)
+
+/* Bits in the exception register. */
+#define EXC_SELWATN	0x20	/* (as target) we were selected with ATN */
+#define EXC_SELECTED	0x10	/* (as target) we were selected w/o ATN */
+#define EXC_RESELECTED	0x08	/* (as initiator) we were reselected */
+#define EXC_ARBLOST	0x04	/* we lost arbitration */
+#define EXC_PHASEMM	0x02	/* SCSI phase mismatch */
+#define EXC_SELTO	0x01	/* selection timeout */
+
+/* Bits in the error register */
+#define ERR_UNEXPDISC	0x40	/* target unexpectedly disconnected */
+#define ERR_SCSIRESET	0x20	/* SCSI bus got reset on us */
+#define ERR_SEQERR	0x10	/* we did something the chip didn't like */
+#define ERR_PARITY	0x01	/* parity error was detected */
+
+/* Bits in the interrupt and intr_mask registers */
+#define INT_ERROR	0x04	/* error interrupt */
+#define INT_EXCEPTION	0x02	/* exception interrupt */
+#define INT_CMDDONE	0x01	/* command done interrupt */
+
+/* Fields in the sync_params register */
+#define SYNC_OFF(x)	((x) >> 4)	/* offset field */
+#define SYNC_PER(x)	((x) & 0xf)	/* period field */
+#define SYNC_PARAMS(o, p)	(((o) << 4) | (p))
+#define ASYNC_PARAMS	2	/* sync_params value for async xfers */
+
+/*
+ * Assuming a clock frequency of 50MHz:
+ *
+ * The transfer period with SYNC_PER(sync_params) == x
+ * is (x + 2) * 40ns, except that x == 0 gives 100ns.
+ *
+ * The units of the sel_timeout register are 10ms.
+ */
+
+
+#endif /* _MESH_H */
diff -u --recursive --new-file v2.1.50/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.1.50/linux/drivers/scsi/sr.c	Mon Apr  7 11:35:30 1997
+++ linux/drivers/scsi/sr.c	Thu Aug 14 20:55:14 1997
@@ -1007,12 +1007,13 @@
     for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++)
 	if(cpnt->device == SDp) {
 	    kdev_t devi = MKDEV(MAJOR_NR, i);
+	    struct super_block * sb = get_super(devi);
 
 	    /*
 	     * Since the cdrom is read-only, no need to sync the device.
 	     * We should be kind to our buffer cache, however.
 	     */
-	    invalidate_inodes(devi);
+	    if (sb) invalidate_inodes(sb);
 	    invalidate_buffers(devi);
 
 	    /*
diff -u --recursive --new-file v2.1.50/linux/fs/Config.in linux/fs/Config.in
--- v2.1.50/linux/fs/Config.in	Thu Jul 17 10:06:06 1997
+++ linux/fs/Config.in	Sat Aug 16 09:53:08 1997
@@ -60,5 +60,6 @@
   bool 'BSD disklabel (FreeBSD partition tables) support' CONFIG_BSD_DISKLABEL
   bool 'SMD disklabel (Sun partition tables) support' CONFIG_SMD_DISKLABEL
 fi
+bool 'Macintosh partition map support' CONFIG_MAC_PARTITION
 endmenu
 
diff -u --recursive --new-file v2.1.50/linux/fs/affs/file.c linux/fs/affs/file.c
--- v2.1.50/linux/fs/affs/file.c	Thu Jul 17 10:06:06 1997
+++ linux/fs/affs/file.c	Fri Aug 15 12:51:03 1997
@@ -629,7 +629,7 @@
 		inode->i_size = pos;
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 	filp->f_pos    = pos;
-	inode->i_dirt  = 1;
+	mark_inode_dirty(inode);
 	iput(ino);
 	return written;
 }
@@ -717,7 +717,7 @@
 		inode->i_size = pos;
 	filp->f_pos = pos;
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	inode->i_dirt  = 1;
+	mark_inode_dirty(inode);
 	iput(ino);
 	return written;
 }
diff -u --recursive --new-file v2.1.50/linux/fs/affs/inode.c linux/fs/affs/inode.c
--- v2.1.50/linux/fs/affs/inode.c	Thu Jul 17 10:06:06 1997
+++ linux/fs/affs/inode.c	Fri Aug 15 12:51:03 1997
@@ -595,11 +595,11 @@
 
 	s->s_dev       = dev;
 	s->s_op        = &affs_sops;
-	s->s_mounted   = iget(s,root_block);
+	s->s_root      = d_alloc_root(iget(s,root_block),NULL);
 	s->s_dirt      = 1;
 	unlock_super(s);
 
-	if (!(s->s_mounted)) {
+	if (!(s->s_root)) {
 		s->s_dev = 0;
 		printk(KERN_ERR "AFFS: get root inode failed\n");
 		MOD_DEC_USE_COUNT;
@@ -609,9 +609,9 @@
 	/* create data zones if the fs is mounted r/w */
 
 	if (!(s->s_flags & MS_RDONLY)) {
-		ROOT_END(s->u.affs_sb.s_root_bh->b_data,s->s_mounted)->bm_flag = 0;
+		ROOT_END(s->u.affs_sb.s_root_bh->b_data,s->s_root->d_inode)->bm_flag = 0;
 		secs_to_datestamp(CURRENT_TIME,&ROOT_END(s->u.affs_sb.s_root_bh->b_data,
-				  s->s_mounted)->disk_altered);
+				  s->s_root->d_inode)->disk_altered);
 		affs_fix_checksum(s->s_blocksize,s->u.affs_sb.s_root_bh->b_data,5);
 		mark_buffer_dirty(s->u.affs_sb.s_root_bh,1);
 		affs_make_zones(s);
@@ -803,7 +803,6 @@
 
 	pr_debug("AFFS: write_inode(%lu)\n",inode->i_ino);
 
-	inode->i_dirt = 0;
 	if (!inode->i_nlink)
 		return;
 	if (!(bh = bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)))) {
@@ -909,7 +908,7 @@
 	inode->i_dev     = sb->s_dev;
 	inode->i_uid     = current->fsuid;
 	inode->i_gid     = current->fsgid;
-	inode->i_dirt    = 1;
+	mark_inode_dirty(inode);
 	inode->i_ino     = block;
 	inode->i_op      = NULL;
 	inode->i_blocks  = 0;
@@ -1012,7 +1011,7 @@
 		FILE_END(link_bh->b_data,link)->link_chain   = ntohl(inode->i_ino);
 		affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5);
 		link->i_version = ++event;
-		link->i_dirt    = 1;
+		mark_inode_dirty(link);
 		mark_buffer_dirty(link_bh,1);
 	}
 	affs_fix_checksum(AFFS_I2BSIZE(inode),inode_bh->b_data,5);
@@ -1021,8 +1020,8 @@
 	dir->i_mtime   = dir->i_atime = dir->i_ctime = CURRENT_TIME;
 	unlock_super(inode->i_sb);
 
-	dir->i_dirt    = 1;
-	inode->i_dirt  = 1;
+	mark_inode_dirty(dir);
+	mark_inode_dirty(inode);
 	mark_buffer_dirty(dir_bh,1);
 	mark_buffer_dirty(inode_bh,1);
 
diff -u --recursive --new-file v2.1.50/linux/fs/affs/namei.c linux/fs/affs/namei.c
--- v2.1.50/linux/fs/affs/namei.c	Thu Jul 17 10:06:06 1997
+++ linux/fs/affs/namei.c	Fri Aug 15 12:51:03 1997
@@ -205,10 +205,10 @@
 		goto unlink_done;
 
 	inode->i_nlink=0;
-	inode->i_dirt=1;
+	mark_inode_dirty(inode);
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	dir->i_version = ++event;
-	dir->i_dirt=1;
+	mark_inode_dirty(dir);
 unlink_done:
 	affs_brelse(bh);
 	iput(inode);
@@ -244,7 +244,7 @@
 	if (error) {
 		iput(dir);
 		inode->i_nlink = 0;
-		inode->i_dirt  = 1;
+		mark_inode_dirty(inode);
 		iput(inode);
 		return -ENOSPC;
 	}
@@ -286,7 +286,7 @@
 	if (error) {
 		iput(dir);
 		inode->i_nlink = 0;
-		inode->i_dirt  = 1;
+		mark_inode_dirty(inode);
 		iput(inode);
 		return error;
 	}
@@ -356,10 +356,10 @@
 		goto rmdir_done;
 
 	inode->i_nlink=0;
-	inode->i_dirt=1;
+	mark_inode_dirty(inode);
 	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 	dir->i_version = ++event;
-	dir->i_dirt=1;
+	mark_inode_dirty(dir);
 rmdir_done:
 	iput(dir);
 	iput(inode);
@@ -392,7 +392,7 @@
 	if (!bh) {
 		iput(dir);
 		inode->i_nlink = 0;
-		inode->i_dirt  = 1;
+		mark_inode_dirty(inode);
 		iput(inode);
 		return -EIO;
 	}
@@ -426,7 +426,7 @@
 	*p = 0;
 	mark_buffer_dirty(bh,1);
 	affs_brelse(bh);
-	inode->i_dirt = 1;
+	mark_inode_dirty(inode);
 	bh = affs_find_entry(dir,name,len,&tmp);
 	if (bh) {
 		inode->i_nlink = 0;
@@ -438,7 +438,7 @@
 	i = affs_add_entry(dir,NULL,inode,name,len,ST_SOFTLINK);
 	if (i) {
 		inode->i_nlink = 0;
-		inode->i_dirt  = 1;
+		mark_inode_dirty(inode);
 		iput(inode);
 		affs_brelse(bh);
 		iput(dir);
@@ -497,7 +497,7 @@
 		error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKFILE);
 	if (error) {
 		inode->i_nlink = 0;
-		inode->i_dirt  = 1;
+		mark_inode_dirty(inode);
 	}
 	iput(dir);
 	iput(inode);
@@ -616,9 +616,9 @@
 			goto retry;
 		mark_buffer_dirty(new_bh,1);
 		new_dir->i_version = ++event;
-		new_dir->i_dirt    = 1;
+		mark_inode_dirty(new_dir);
 		new_inode->i_nlink = 0;
-		new_inode->i_dirt  = 1;
+		mark_inode_dirty(new_inode);
 	}
 	retval = affs_fix_hash_pred(old_dir,affs_hash_name(old_name,old_len,AFFS_I2FSTYPE(old_dir),
 				    AFFS_I2HSIZE(old_dir)) + 6,old_ino,
@@ -632,8 +632,8 @@
 	new_dir->i_ctime   = new_dir->i_mtime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
 	new_dir->i_version = ++event;
 	old_dir->i_version = ++event;
-	new_dir->i_dirt    = 1;
-	old_dir->i_dirt    = 1;
+	mark_inode_dirty(new_dir);
+	mark_inode_dirty(old_dir);
 	mark_buffer_dirty(old_bh,1);
 	
 end_rename:
@@ -704,7 +704,7 @@
 			ofinode->i_size              = inode->i_size;
 			ofinode->i_uid               = inode->i_uid;
 			ofinode->i_gid               = inode->i_gid;
-			ofinode->i_dirt              = 1;
+			mark_inode_dirty(ofinode);
 			link_key                     = ofinode->i_ino;
 
 			/* Let all remaining links point to the new file */
@@ -722,7 +722,7 @@
 							   "Inode %d in link chain is not a link",
 							   key);
 					ofinode->u.affs_i.i_original = link_key;
-					ofinode->i_dirt              = 1;
+					mark_inode_dirty(ofinode);
 					FILE_END(nbh->b_data,inode)->original = htonl(link_key);
 				} else
 					affs_error(inode->i_sb,"fixup","Cannot read block %d",key);
diff -u --recursive --new-file v2.1.50/linux/fs/autofs/inode.c linux/fs/autofs/inode.c
--- v2.1.50/linux/fs/autofs/inode.c	Mon Aug  4 16:25:38 1997
+++ linux/fs/autofs/inode.c	Fri Aug 15 10:01:29 1997
@@ -141,6 +141,9 @@
 struct super_block *autofs_read_super(struct super_block *s, void *data,
 				      int silent)
 {
+	struct inode * root_inode;
+	struct dentry * root;
+	struct file * pipe;
 	int pipefd;
 	struct autofs_sb_info *sbi;
 	int minproto, maxproto;
@@ -148,12 +151,13 @@
 	MOD_INC_USE_COUNT;
 
 	lock_super(s);
+	/* Super block already completed? */
+	if (s->s_root)
+		goto out_unlock;
+
 	sbi = (struct autofs_sb_info *) kmalloc(sizeof(struct autofs_sb_info), GFP_KERNEL);
-	if ( !sbi ) {
-		s->s_dev = 0;
-		MOD_DEC_USE_COUNT;
-		return NULL;
-	}
+	if ( !sbi )
+		goto fail_unlock;
 	DPRINTK(("autofs: starting up, sbi = %p\n",sbi));
 
 	s->u.generic_sbp = sbi;
@@ -169,50 +173,112 @@
 	s->s_blocksize_bits = 10;
 	s->s_magic = AUTOFS_SUPER_MAGIC;
 	s->s_op = &autofs_sops;
-	unlock_super(s);
-	s->s_root = d_alloc_root(iget(s, AUTOFS_ROOT_INO), NULL);
-	if (!s->s_root) {
-		printk("autofs: get root inode failed\n");
-		kfree(sbi);
-		s->s_dev = 0;
-		MOD_DEC_USE_COUNT;
-		return NULL;
-	}
+	s->s_root = NULL;
+	unlock_super(s); /* shouldn't we keep it locked a while longer? */
+
+	/*
+	 * Get the root inode and dentry, but defer checking for errors.
+	 */
+	root_inode = iget(s, AUTOFS_ROOT_INO);
+	root = d_alloc_root(root_inode, NULL);
+	pipe = NULL;
+
+	/*
+	 * Check whether somebody else completed the super block.
+	 */
+	if (s->s_root)
+		goto out_dput;
 
-	if ( parse_options(data,&pipefd,&s->s_root->d_inode->i_uid,&s->s_root->d_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
+	if (!root)
+		goto fail_iput;
+
+	/* Can this call block? */
+	if ( parse_options(data,&pipefd,&root_inode->i_uid,&root_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
 		printk("autofs: called with bogus options\n");
-		dput(s->s_root);
-		kfree(sbi);
-		s->s_dev = 0;
-		MOD_DEC_USE_COUNT;
-		return NULL;
+		goto fail_dput;
 	}
 
-	if ( minproto > AUTOFS_PROTO_VERSION || maxproto < AUTOFS_PROTO_VERSION ) {
+	/* Couldn't this be tested earlier? */
+	if ( minproto > AUTOFS_PROTO_VERSION || 
+	     maxproto < AUTOFS_PROTO_VERSION ) {
 		printk("autofs: kernel does not match daemon version\n");
-		dput(s->s_root);
-		kfree(sbi);
-		s->s_dev = 0;
-		MOD_DEC_USE_COUNT;
-		return NULL;
+		goto fail_dput;
 	}
 
 	DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, sbi->oz_pgrp));
-	sbi->pipe = fget(pipefd);
-	if ( !sbi->pipe || !sbi->pipe->f_op || !sbi->pipe->f_op->write ) {
-		if ( sbi->pipe ) {
-			fput(sbi->pipe);
-			printk("autofs: pipe file descriptor does not contain proper ops\n");
-		} else {
-			printk("autofs: could not open pipe file descriptor\n");
-		}
-		dput(s->s_root);
-		kfree(sbi);
-		s->s_dev = 0;
-		MOD_DEC_USE_COUNT;
-		return NULL;
+	pipe = fget(pipefd);
+	/*
+	 * Check whether somebody else completed the super block.
+	 */
+	if (s->s_root)
+		goto out_fput;
+	
+	if ( !pipe ) {
+		printk("autofs: could not open pipe file descriptor\n");
+		goto fail_dput;
 	}
+	if ( !pipe->f_op || !pipe->f_op->write )
+		goto fail_fput;
+	sbi->pipe = pipe;
+
+	/*
+	 * Success! Install the root dentry now to indicate completion.
+	 */
+	s->s_root = root;
 	return s;
+
+	/*
+	 * Success ... somebody else completed the super block for us. 
+	 */ 
+out_unlock:
+	unlock_super(s);
+	goto out_dec;
+out_fput:
+	if (pipe)
+		fput(pipe);
+out_dput:
+	if (root)
+		dput(root);
+	else
+		iput(root_inode);
+out_dec:
+	MOD_DEC_USE_COUNT;
+	return s;
+	
+	/*
+	 * Failure ... clear the s_dev slot and clean up.
+	 */
+fail_fput:
+	printk("autofs: pipe file descriptor does not contain proper ops\n");
+	/*
+	 * fput() can block, so we clear the super block first.
+	 */
+	s->s_dev = 0;
+	fput(pipe);
+	/* fall through */
+fail_dput:
+	/*
+	 * dput() can block, so we clear the super block first.
+	 */
+	s->s_dev = 0;
+	dput(root);
+	goto fail_free;
+fail_iput:
+	printk("autofs: get root dentry failed\n");
+	/*
+	 * iput() can block, so we clear the super block first.
+	 */
+	s->s_dev = 0;
+	iput(root_inode);
+fail_free:
+	kfree(sbi);
+	goto fail_dec;
+fail_unlock:
+	unlock_super(s);
+fail_dec:
+	s->s_dev = 0;
+	MOD_DEC_USE_COUNT;
+	return NULL;
 }
 
 static int autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
diff -u --recursive --new-file v2.1.50/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.1.50/linux/fs/binfmt_elf.c	Sun Jul 20 20:41:58 1997
+++ linux/fs/binfmt_elf.c	Sat Aug 16 09:55:26 1997
@@ -115,15 +115,17 @@
 
 	/*
 	 * Force 16 byte _final_ alignment here for generality.
+	 * Leave an extra 16 bytes free so that on the PowerPC we
+	 * can move the aux table up to start on a 16-byte boundary.
 	 */
-	sp = (elf_addr_t *) (~15UL & (unsigned long) p);
+	sp = (elf_addr_t *) ((~15UL & (unsigned long) p) - 16UL);
 	csp = sp;
 	csp -= exec ? DLINFO_ITEMS*2 : 2;
 	csp -= envc+1;
 	csp -= argc+1;
 	csp -= (!ibcs ? 3 : 1);	/* argc itself */
 	if ((unsigned long)csp & 15UL) {
-		sp -= (16UL - ((unsigned long)csp & 15UL)) / sizeof(*sp);
+		sp -= ((unsigned long)csp & 15UL) / sizeof(*sp);
 	}
 
 	/*
diff -u --recursive --new-file v2.1.50/linux/fs/dcache.c linux/fs/dcache.c
--- v2.1.50/linux/fs/dcache.c	Thu Aug 14 20:49:17 1997
+++ linux/fs/dcache.c	Thu Aug 14 21:53:08 1997
@@ -34,7 +34,7 @@
 static struct list_head dentry_hashtable[D_HASHSIZE];
 static LIST_HEAD(dentry_unused);
 
-void d_free(struct dentry *dentry)
+static inline void d_free(struct dentry *dentry)
 {
 	kfree(dentry->d_name.name);
 	kfree(dentry);
@@ -165,10 +165,10 @@
 	memcpy(str, name->name, name->len);
 	str[name->len] = 0;
 
-	dentry->d_count = 0;
+	dentry->d_count = 1;
 	dentry->d_flags = 0;
 	dentry->d_inode = NULL;
-	dentry->d_parent = parent;
+	dentry->d_parent = dget(parent);
 	dentry->d_mounts = dentry;
 	dentry->d_covers = dentry;
 	INIT_LIST_HEAD(&dentry->d_hash);
@@ -207,7 +207,6 @@
 	if (root_inode) {
 		res = d_alloc(NULL, &(const struct qstr) { "/", 1, 0 });
 		res->d_parent = res;
-		res->d_count = 1;
 		d_instantiate(res, root_inode);
 	}
 	return res;
@@ -238,13 +237,13 @@
 		if (parent->d_op && parent->d_op->d_compare) {
 			if (parent->d_op->d_compare(parent, &dentry->d_name, name))
 				continue;
-			return dentry;
+		} else {
+			if (dentry->d_name.len != len)
+				continue;
+			if (memcmp(dentry->d_name.name, str, len))
+				continue;
 		}
-		if (dentry->d_name.len != len)
-			continue;
-		if (memcmp(dentry->d_name.name, str, len))
-			continue;
-		return dentry;
+		return dget(dentry->d_mounts);
 	}
 	return NULL;
 }
@@ -329,7 +328,7 @@
 
 void d_add(struct dentry * entry, struct inode * inode)
 {
-	struct dentry * parent = dget(entry->d_parent);
+	struct dentry * parent = entry->d_parent;
 
 	list_add(&entry->d_hash, d_hash(parent, entry->d_name.hash));
 	d_instantiate(entry, inode);
diff -u --recursive --new-file v2.1.50/linux/fs/exec.c linux/fs/exec.c
--- v2.1.50/linux/fs/exec.c	Sun Jul 20 20:41:58 1997
+++ linux/fs/exec.c	Sat Aug 16 09:55:26 1997
@@ -396,7 +396,7 @@
 		*mm = *current->mm;
 		init_new_context(mm);
 		mm->def_flags = 0;	/* should future lockings be kept? */
-		mm->cpu_vm_mask = (1 << smp_processor_id());
+		mm->cpu_vm_mask = (1UL << smp_processor_id());
 		mm->count = 1;
 		mm->mmap = mm->mmap_cache = NULL;
 		mm->total_vm = 0;
diff -u --recursive --new-file v2.1.50/linux/fs/isofs/namei.c linux/fs/isofs/namei.c
--- v2.1.50/linux/fs/isofs/namei.c	Thu Jul 17 10:06:07 1997
+++ linux/fs/isofs/namei.c	Fri Aug 15 12:19:17 1997
@@ -63,12 +63,14 @@
 {
 	unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
 	unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
-	unsigned int block, i, f_pos, offset, inode_number;
+	unsigned int block, i, f_pos, offset, 
+		inode_number = 0; /* shut gcc up */
 	struct buffer_head * bh;
 	unsigned int old_offset;
 	int dlen, rrflag, match;
 	char * dpnt;
-	struct iso_directory_record * de;
+	struct iso_directory_record * de = NULL; /* shut gcc up */
+	char de_not_in_buf = 0;	  /* true if de is in kmalloc'd memory */
 	char c;
 
 	*ino = 0;
@@ -84,17 +86,36 @@
 	if (!block || !(bh = bread(dir->i_dev,block,bufsize))) return NULL;
   
 	while (f_pos < dir->i_size) {
-		de = (struct iso_directory_record *) (bh->b_data + offset);
-		inode_number = (block << bufbits) + (offset & (bufsize - 1));
 
-		/* If byte is zero, this is the end of file, or time to move to
-		   the next sector. Usually 2048 byte boundaries. */
+		/* if de is in kmalloc'd memory, do not point to the
+                   next de, instead we will move to the next sector */
+		if(!de_not_in_buf) {
+			de = (struct iso_directory_record *) 
+				(bh->b_data + offset);
+			inode_number = (block << bufbits) 
+				+ (offset & (bufsize - 1));
+		}
+
+		/* If byte is zero, or we had to fetch this de past
+		   the end of the buffer, this is the end of file, or
+		   time to move to the next sector. Usually 2048 byte
+		   boundaries. */
 		
-		if (*((unsigned char *) de) == 0) {
+		if (*((unsigned char *) de) == 0 || de_not_in_buf) {
+			if(de_not_in_buf) {
+				/* james@bpgc.com: Since we slopped
+                                   past the end of the last buffer, we
+                                   must start some way into the new
+                                   one */
+				de_not_in_buf = 0;
+				kfree(de);
+				offset -= bufsize;
+			}
+			else 
+				offset = 0;
 			brelse(bh);
-			offset = 0;
 			f_pos = ((f_pos & ~(ISOFS_BLOCK_SIZE - 1))
-				 + ISOFS_BLOCK_SIZE);
+				 + ISOFS_BLOCK_SIZE) + offset;
 
 			if( f_pos >= dir->i_size )
 			  {
@@ -111,11 +132,28 @@
 		offset += *((unsigned char *) de);
 		f_pos += *((unsigned char *) de);
 
-		/* Handle case where the directory entry spans two blocks.
-		   Usually 1024 byte boundaries */
+		/* james@bpgc.com: new code to handle case where the
+		   directory entry spans two blocks.  Usually 1024
+		   byte boundaries */
 		if (offset >= bufsize) {
-			printk("Directory entry extends past end of iso9660 block\n");
-	 		return 0;
+			struct buffer_head *bh_next;
+
+			/* james@bpgc.com: read the next block, and
+                           copy the split de into a newly kmalloc'd
+                           buffer */
+			block = isofs_bmap(dir,f_pos>>bufbits);
+			if (!block || 
+			    !(bh_next = bread(dir->i_dev,block,bufsize)))
+				return NULL;
+			
+			de = (struct iso_directory_record *)
+				kmalloc(offset - old_offset, GFP_KERNEL);
+			memcpy((char *)de, bh->b_data + old_offset, 
+			       bufsize - old_offset);
+			memcpy((char *)de + bufsize - old_offset,
+			       bh_next->b_data, offset - bufsize);
+			brelse(bh_next);
+			de_not_in_buf = 1;
 		}
 		
 		dlen = de->name_len[0];
@@ -161,11 +199,15 @@
 					   find_rock_ridge_relocation(de,dir));
 			}
 			*ino = inode_number;
+			if(de_not_in_buf) 
+				kfree(de);
 			return bh;
 		}
 	}
  out:
 	brelse(bh);
+	if(de_not_in_buf) 
+		kfree(de);
 	return NULL;
 }
 
diff -u --recursive --new-file v2.1.50/linux/fs/isofs/symlink.c linux/fs/isofs/symlink.c
--- v2.1.50/linux/fs/isofs/symlink.c	Mon Jun 16 16:35:57 1997
+++ linux/fs/isofs/symlink.c	Fri Aug 15 10:14:21 1997
@@ -19,6 +19,7 @@
 #include <asm/uaccess.h>
 
 static int isofs_readlink(struct inode *, char *, int);
+static struct dentry * isofs_follow_link(struct inode * inode, struct dentry *base);
 
 /*
  * symlinks can't do much...
@@ -35,6 +36,7 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	isofs_readlink,		/* readlink */
+	isofs_follow_link,	/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -51,7 +53,6 @@
 		buflen = 1023;
 	pnt = get_rock_ridge_symlink(inode);
 
-	iput(inode);
 	if (!pnt)
 		return 0;
 
@@ -62,4 +63,21 @@
 		i = -EFAULT; 	
 	kfree(pnt);
 	return i;
+}
+
+static struct dentry * isofs_follow_link(struct inode * inode, struct dentry *base)
+{
+	char * pnt;
+
+	pnt = get_rock_ridge_symlink(inode);
+
+	if(!pnt) {
+		dput(base);
+		return ERR_PTR(-ELOOP);
+	}
+
+	base = lookup_dentry(pnt, base, 1);
+
+	kfree(pnt);
+	return base;
 }
diff -u --recursive --new-file v2.1.50/linux/fs/namei.c linux/fs/namei.c
--- v2.1.50/linux/fs/namei.c	Thu Aug 14 20:49:17 1997
+++ linux/fs/namei.c	Sat Aug 16 22:27:58 1997
@@ -105,18 +105,6 @@
 	return res;
 }
 
-/*
- * Kernel pointers have redundant information, so we can use a
- * scheme where we can return either an error code or a dentry
- * pointer with the same return value.
- *
- * This should be a per-architecture thing, to allow different
- * error and pointer decisions.
- */
-#define ERR_PTR(err)	((void *)((long)(err)))
-#define PTR_ERR(ptr)	((long)(ptr))
-#define IS_ERR(ptr)	((unsigned long)(ptr) > (unsigned long)(-1000))
-
 inline void putname(char * name)
 {
 	if (name) {
@@ -243,15 +231,12 @@
 	down(&dir->i_sem);
 	result = d_lookup(parent, name);
 	if (!result) {
-		int error;
-		result = d_alloc(parent, name);
-		result->d_count++;
-		error = dir->i_op->lookup(dir, result);
-		result->d_count--;
-		if (error) {
-			d_free(result);
-			result = ERR_PTR(error);
-		}
+		struct dentry * dentry = d_alloc(parent, name);
+		int error = dir->i_op->lookup(dir, dentry);
+		result = ERR_PTR(error);
+		if (!error)
+			result = dget(dentry->d_mounts);
+		dput(dentry);
 	}
 	up(&dir->i_sem);
 	return result;
@@ -271,11 +256,11 @@
 	if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
 		int validated, (*revalidate)(struct dentry *) = dentry->d_op->d_revalidate;
 
-		dentry->d_count++;
 		validated = revalidate(dentry) || d_invalidate(dentry);
-		dput(dentry);
-		if (!validated)
+		if (!validated) {
+			dput(dentry);
 			dentry = NULL;
+		}
 	}
 	return dentry;
 }
@@ -302,28 +287,25 @@
 			result = parent;
 		}
 	}
-	return result;
+	return dget(result);
 }
 
 /* In difference to the former version, lookup() no longer eats the dir. */
-static struct dentry * lookup(struct dentry * dir, struct qstr * name)
+static inline struct dentry * lookup(struct dentry * dir, struct qstr * name)
 {
 	struct dentry * result;
 
 	result = reserved_lookup(dir, name);
 	if (result)
-		goto done_noerror;
+		goto done;
 
 	result = cached_lookup(dir, name);
 	if (result)
-		goto done_noerror;
+		goto done;
 
 	result = real_lookup(dir, name);
 
-	if (!IS_ERR(result)) {
-done_noerror:
-		result = dget(result->d_mounts);
-	}
+done:
 	return result;
 }
 
@@ -538,8 +520,9 @@
 			if (dir->i_sb && dir->i_sb->dq_op)
 				dir->i_sb->dq_op->initialize(dir, -1);
 			error = dir->i_op->create(dir, dentry, mode);
-			/* Don't check for write permission */
+			/* Don't check for write permission, don't truncate */
 			acc_mode = 0;
+			flag &= ~O_TRUNC;
 		}
 		up(&dir->i_sem);
 		if (error)
diff -u --recursive --new-file v2.1.50/linux/fs/ncpfs/file.c linux/fs/ncpfs/file.c
--- v2.1.50/linux/fs/ncpfs/file.c	Mon Jun 16 16:35:58 1997
+++ linux/fs/ncpfs/file.c	Fri Aug 15 12:51:03 1997
@@ -130,8 +130,8 @@
 	if (!IS_RDONLY(inode)) {
 		inode->i_atime = CURRENT_TIME;
 	}
-	inode->i_dirt = 1;
-
+	mark_inode_dirty(inode);
+	
 	DPRINTK("ncp_file_read: exit %s\n", NCP_ISTRUCT(inode)->entryName);
 
 	return already_read;
@@ -192,8 +192,8 @@
 	}
 
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	inode->i_dirt = 1;
-
+	mark_inode_dirty(inode);
+	
 	file->f_pos = pos;
 
 	if (pos > inode->i_size) {
diff -u --recursive --new-file v2.1.50/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v2.1.50/linux/fs/ncpfs/inode.c	Thu Jun 26 12:33:39 1997
+++ linux/fs/ncpfs/inode.c	Fri Aug 15 12:51:03 1997
@@ -165,7 +165,7 @@
 	}
 	if ((data->ncp_fd >= NR_OPEN)
 	    || ((ncp_filp = current->files->fd[data->ncp_fd]) == NULL)
-	    || (!S_ISSOCK(ncp_filp->f_inode->i_mode))) {
+	    || (!S_ISSOCK(ncp_filp->f_dentry->d_inode->i_mode))) {
 		printk("ncp_read_super: invalid ncp socket\n");
 		sb->s_dev = 0;
 		return NULL;
@@ -234,8 +234,8 @@
 
 	ncp_init_root(server);
 
-	if (!(sb->s_mounted = iget(sb, ncp_info_ino(server,
-						    &(server->root))))) {
+        if (!(sb->s_root = d_alloc_root(iget(sb,ncp_info_ino(server,
+						    &(server->root))),NULL))) {
 		sb->s_dev = 0;
 		printk("ncp_read_super: get root inode failed\n");
 		goto disconnect;
diff -u --recursive --new-file v2.1.50/linux/fs/ncpfs/mmap.c linux/fs/ncpfs/mmap.c
--- v2.1.50/linux/fs/ncpfs/mmap.c	Thu Jul 17 10:06:07 1997
+++ linux/fs/ncpfs/mmap.c	Fri Aug 15 12:51:03 1997
@@ -32,7 +32,7 @@
 static unsigned long ncp_file_mmap_nopage(struct vm_area_struct *area,
 				     unsigned long address, int no_share)
 {
-	struct inode *inode = area->vm_inode;
+	struct inode *inode = area->vm_dentry->d_inode;
 	unsigned long page;
 	unsigned int clear;
 	unsigned long tmp;
@@ -130,7 +130,7 @@
 		return -EACCES;
 	if (!IS_RDONLY(inode)) {
 		inode->i_atime = CURRENT_TIME;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 	}
 
 	vma->vm_dentry = dget(file->f_dentry);
diff -u --recursive --new-file v2.1.50/linux/fs/ncpfs/sock.c linux/fs/ncpfs/sock.c
--- v2.1.50/linux/fs/ncpfs/sock.c	Fri Apr  4 08:52:24 1997
+++ linux/fs/ncpfs/sock.c	Fri Aug 15 12:51:03 1997
@@ -102,7 +102,7 @@
 	struct ncp_reply_header reply;
 
 	file = server->ncp_filp;
-	inode = file->f_inode;
+	inode = file->f_dentry->d_inode;
 	sock = &inode->u.socket_i;
 	if (!sock) {
 		printk("ncp_rpc_call: socki_lookup failed\n");
diff -u --recursive --new-file v2.1.50/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.1.50/linux/fs/nfs/dir.c	Thu Aug 14 20:49:17 1997
+++ linux/fs/nfs/dir.c	Thu Aug 14 18:10:13 1997
@@ -561,9 +561,6 @@
 static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
 {
 	struct nfs_sattr sattr;
-	struct nfs_fattr fattr;
-	struct nfs_fh fhandle;
-	struct inode * inode;
 	int error;
 
 	dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
@@ -590,12 +587,16 @@
 	if (error)
 		return error;
 
-	inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
-	if (!inode)
-		return -EACCES;
-
 	nfs_invalidate_dircache(dir);
-	d_instantiate(dentry, inode);
+	/*  this looks _funny_ doesn't it? But: nfs_proc_symlynk()
+	 *  only fills in sattr, not fattr. Thus nfs_fhget() cannot be
+	 *  called, it would be pointless, without a valid fattr
+	 *  argument. Other possibility: call nfs_proc_lookup()
+	 *  HERE. But why? If somebody wants to reference this
+	 *  symlink, the cached_lookup() will fail, and
+	 *  nfs_proc_symlink() will be called anyway.
+	 */
+	d_drop(dentry);
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.50/linux/fs/nfs/symlink.c linux/fs/nfs/symlink.c
--- v2.1.50/linux/fs/nfs/symlink.c	Mon Jul  7 11:06:36 1997
+++ linux/fs/nfs/symlink.c	Thu Aug 14 18:20:15 1997
@@ -61,8 +61,8 @@
 		copy_to_user(buffer, res, len);
 		put_user('\0', buffer + len);
 		error = len;
+		kfree(mem);
 	}
-	kfree(mem);
 	return error;
 }
 
@@ -81,7 +81,6 @@
 
 	if (error) {
 		dput(base);
-		kfree(mem);
 		return ERR_PTR(error);
 	}
 	path = kmalloc(len + 1, GFP_KERNEL);
diff -u --recursive --new-file v2.1.50/linux/fs/nfsd/export.c linux/fs/nfsd/export.c
--- v2.1.50/linux/fs/nfsd/export.c	Mon Aug 11 14:47:05 1997
+++ linux/fs/nfsd/export.c	Sun Aug 17 09:54:07 1997
@@ -248,7 +248,7 @@
 
 finish:
 	/* Release dentry */
-	if (err < 0 && dentry)
+	if (err < 0 && !IS_ERR(dentry))
 		dput(dentry);
 
 	/* Unlock hashtable */
diff -u --recursive --new-file v2.1.50/linux/fs/open.c linux/fs/open.c
--- v2.1.50/linux/fs/open.c	Sun Jul 27 12:11:01 1997
+++ linux/fs/open.c	Sat Aug 16 09:55:26 1997
@@ -53,9 +53,6 @@
 	int error;
 
 	lock_kernel();
-	error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs));
-	if (error)
-		goto out;
 	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 		error = -EBADF;
 	else if (!(dentry = file->f_dentry))
@@ -67,8 +64,7 @@
 	else if (!inode->i_sb->s_op->statfs)
 		error = -ENOSYS;
 	else
-		inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
-out:
+		error = inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs));
 	unlock_kernel();
 	return error;
 }
diff -u --recursive --new-file v2.1.50/linux/fs/pipe.c linux/fs/pipe.c
--- v2.1.50/linux/fs/pipe.c	Mon Aug  4 16:25:39 1997
+++ linux/fs/pipe.c	Sun Aug 17 09:53:20 1997
@@ -399,7 +399,7 @@
 			/*
 			 * Mark the inode dirty from the very beginning,
 			 * that way it will never be moved to the dirty
-			 * list because "make_inode_dirty()" will think
+			 * list because "mark_inode_dirty()" will think
 			 * that it already _is_ on the dirty list.
 			 */
 			inode->i_state = 1 << I_DIRTY;
@@ -439,7 +439,7 @@
 	int error;
 	int i,j;
 
-	error = ENFILE;
+	error = -ENFILE;
 	f1 = get_empty_filp();
 	if (!f1)
 		goto no_files;
@@ -462,7 +462,10 @@
 		goto close_f12_inode_i;
 	j = error;
 
+	error = -ENOMEM;
 	f1->f_dentry = f2->f_dentry = dget(d_alloc_root(inode, NULL));
+	if (!f1->f_dentry)
+		goto close_f12_inode_i_j;
 
 	/* read file */
 	f1->f_pos = f2->f_pos = 0;
@@ -480,6 +483,8 @@
 	fd[1] = j;
 	return 0;
 
+close_f12_inode_i_j:
+	put_unused_fd(j);
 close_f12_inode_i:
 	put_unused_fd(i);
 close_f12_inode:
diff -u --recursive --new-file v2.1.50/linux/fs/proc/Makefile linux/fs/proc/Makefile
--- v2.1.50/linux/fs/proc/Makefile	Thu Jul 17 10:06:07 1997
+++ linux/fs/proc/Makefile	Sat Aug 16 09:53:08 1997
@@ -24,4 +24,8 @@
   endif
 endif
 
+ifeq ($(CONFIG_PROC_DEVICETREE),y)
+O_OBJS += proc_devtree.o
+endif
+
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.50/linux/fs/proc/openpromfs.c linux/fs/proc/openpromfs.c
--- v2.1.50/linux/fs/proc/openpromfs.c	Mon Aug  4 16:25:39 1997
+++ linux/fs/proc/openpromfs.c	Sat Aug 16 10:00:33 1997
@@ -1,4 +1,4 @@
-/* $Id: openpromfs.c,v 1.20 1997/07/22 06:40:07 davem Exp $
+/* $Id: openpromfs.c,v 1.18 1997/07/17 02:24:01 davem Exp $
  * openpromfs.c: /proc/openprom handling routines
  *
  * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
diff -u --recursive --new-file v2.1.50/linux/fs/proc/proc_devtree.c linux/fs/proc/proc_devtree.c
--- v2.1.50/linux/fs/proc/proc_devtree.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/proc/proc_devtree.c	Sat Aug 16 09:53:08 1997
@@ -0,0 +1,219 @@
+/*
+ * proc_devtree.c - handles /proc/device-tree
+ *
+ * Copyright 1997 Paul Mackerras
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <asm/prom.h>
+#include <asm/uaccess.h>
+
+static struct proc_dir_entry *proc_device_tree;
+
+/*
+ * Supply data on a read from /proc/device-tree/node/property.
+ */
+static int property_read_proc(char *page, char **start, off_t off,
+			      int count, int *eof, void *data)
+{
+	struct property *pp = data;
+	int n;
+
+	if (off >= pp->length) {
+		*eof = 1;
+		return 0;
+	}
+	n = pp->length - off;
+	if (n > count)
+		n = count;
+	else
+		*eof = 1;
+	memcpy(page, pp->value + off, n);
+	*start = page;
+	return n;
+}
+
+/*
+ * For a node with a name like "gc@10", we make symlinks called "gc"
+ * and "@10" to it.
+ */
+
+static int devtree_readlink(struct inode *, char *, int);
+static struct dentry *devtree_follow_link(struct inode *, struct dentry *);
+
+struct inode_operations devtree_symlink_inode_operations = {
+	NULL,			/* no file-operations */
+	NULL,			/* create */
+	NULL,			/* lookup */
+	NULL,			/* link */
+	NULL,			/* unlink */
+	NULL,			/* symlink */
+	NULL,			/* mkdir */
+	NULL,			/* rmdir */
+	NULL,			/* mknod */
+	NULL,			/* rename */
+	devtree_readlink,	/* readlink */
+	devtree_follow_link,	/* follow_link */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL,			/* permission */
+	NULL			/* smap */
+};
+
+static struct dentry *devtree_follow_link(struct inode *inode,
+					  struct dentry *base)
+{
+	struct proc_dir_entry * de;
+	char *link;
+
+	de = (struct proc_dir_entry *) inode->u.generic_ip;
+	link = (char *) de->data;
+	return lookup_dentry(link, base, 1);
+}
+
+static int devtree_readlink(struct inode *inode, char *buffer, int buflen)
+{
+	struct proc_dir_entry * de;
+	char *link;
+	int linklen;
+
+	de = (struct proc_dir_entry *) inode->u.generic_ip;
+	link = (char *) de->data;
+	linklen = strlen(link);
+	if (linklen > buflen)
+		linklen = buflen;
+	if (copy_to_user(buffer, link, linklen))
+		return -EFAULT;
+	return linklen;
+}
+
+/*
+ * Process a node, adding entries for its children and its properties.
+ */
+static void add_node(struct device_node *np, struct proc_dir_entry *de)
+{
+	struct property *pp;
+	struct proc_dir_entry *ent;
+	struct device_node *child, *sib;
+	const char *p, *at;
+	int l;
+	struct proc_dir_entry *list, **lastp, *al;
+
+	lastp = &list;
+	for (pp = np->properties; pp != 0; pp = pp->next) {
+		/*
+		 * Unfortunately proc_register puts each new entry
+		 * at the beginning of the list.  So we rearrange them.
+		 */
+		ent = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
+		if (ent == 0)
+			break;
+		memset(ent, 0, sizeof(struct proc_dir_entry));
+		ent->name = pp->name;
+		ent->namelen = strlen(pp->name);
+		ent->mode = S_IFREG | S_IRUGO;
+		ent->nlink = 1;
+		ent->data = pp;
+		ent->read_proc = property_read_proc;
+		ent->size = pp->length;
+		proc_register(de, ent);
+		*lastp = ent;
+		lastp = &ent->next;
+	}
+	for (child = np->child; child != 0; child = child->sibling) {
+		p = strrchr(child->full_name, '/');
+		if (p == 0)
+			p = child->full_name;
+		else
+			++p;
+		/* chop off '@0' if the name ends with that */
+		l = strlen(p);
+		if (l > 2 && p[l-2] == '@' && p[l-1] == '0')
+			l -= 2;
+		ent = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
+		if (ent == 0)
+			break;
+		memset(ent, 0, sizeof(struct proc_dir_entry));
+		ent->name = p;
+		ent->namelen = l;
+		ent->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+		ent->nlink = 2;
+		proc_register(de, ent);
+		*lastp = ent;
+		lastp = &ent->next;
+		add_node(child, ent);
+
+		/*
+		 * If we left the address part on the name, consider
+		 * adding symlinks from the name and address parts.
+		 */
+		if (p[l] != 0 || (at = strchr(p, '@')) == 0)
+			continue;
+
+		/*
+		 * If this is the first node with a given name property,
+		 * add a symlink with the name property as its name.
+		 */
+		for (sib = np->child; sib != child; sib = sib->sibling)
+			if (strcmp(sib->name, child->name) == 0)
+				break;
+		if (sib == child && strncmp(p, child->name, l) != 0) {
+			al = kmalloc(sizeof(struct proc_dir_entry),
+				     GFP_KERNEL);
+			if (al == 0)
+				break;
+			memset(al, 0, sizeof(struct proc_dir_entry));
+			al->name = child->name;
+			al->namelen = strlen(child->name);
+			al->mode = S_IFLNK | S_IRUGO | S_IXUGO;
+			al->nlink = 1;
+			al->data = (void *) ent->name;
+			al->ops = &devtree_symlink_inode_operations;
+			proc_register(de, al);
+			*lastp = al;
+			lastp = &al->next;
+		}
+
+		/*
+		 * Add another directory with the @address part as its name.
+		 */
+		al = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
+		if (al == 0)
+			break;
+		memset(al, 0, sizeof(struct proc_dir_entry));
+		al->name = at;
+		al->namelen = strlen(at);
+		al->mode = S_IFLNK | S_IRUGO | S_IXUGO;
+		al->nlink = 1;
+		al->data = (void *) ent->name;
+		al->ops = &devtree_symlink_inode_operations;
+		proc_register(de, al);
+		*lastp = al;
+		lastp = &al->next;
+	}
+	*lastp = 0;
+	de->subdir = list;
+}
+
+/*
+ * Called on initialization to set up the /proc/device-tree subtree
+ */
+void proc_device_tree_init(void)
+{
+	struct device_node *root;
+
+	proc_device_tree = create_proc_entry("device-tree", S_IFDIR, 0);
+	if (proc_device_tree == 0)
+		return;
+	root = find_path_device("/");
+	if (root == 0) {
+		printk(KERN_ERR "/proc/device-tree: can't find root\n");
+		return;
+	}
+	add_node(root, proc_device_tree);
+}
diff -u --recursive --new-file v2.1.50/linux/fs/proc/root.c linux/fs/proc/root.c
--- v2.1.50/linux/fs/proc/root.c	Mon Aug  4 16:25:39 1997
+++ linux/fs/proc/root.c	Sat Aug 16 09:53:08 1997
@@ -548,6 +548,13 @@
 	0, &proc_omirr_inode_operations
 };
 #endif
+#ifdef __powerpc__
+static struct proc_dir_entry proc_root_ppc_htab = {
+	PROC_PPC_HTAB, 8, "ppc_htab",
+	S_IFREG | S_IRUGO, 1, 0, 0,
+	0, &proc_ppc_htab_inode_operations
+};
+#endif
 
 void proc_root_init(void)
 {
@@ -619,6 +626,12 @@
 	}
 
 	proc_tty_init();
+#ifdef __powerpc__
+	proc_register(&proc_root, &proc_root_ppc_htab);
+#endif
+#ifdef CONFIG_PROC_DEVICETREE
+	proc_device_tree_init();
+#endif
 }
 
 /*
diff -u --recursive --new-file v2.1.50/linux/fs/read_write.c linux/fs/read_write.c
--- v2.1.50/linux/fs/read_write.c	Thu Jul 17 10:06:07 1997
+++ linux/fs/read_write.c	Sun Aug 17 10:03:31 1997
@@ -130,7 +130,7 @@
 		goto bad_file;
 	dentry = file->f_dentry;
 	if (!dentry)
-		goto bad_file;
+		goto out;
 	inode = dentry->d_inode;
 	if (!inode)
 		goto out;
diff -u --recursive --new-file v2.1.50/linux/fs/smbfs/file.c linux/fs/smbfs/file.c
--- v2.1.50/linux/fs/smbfs/file.c	Mon Jun 16 16:35:59 1997
+++ linux/fs/smbfs/file.c	Fri Aug 15 12:51:03 1997
@@ -126,8 +126,8 @@
 
 	if (!IS_RDONLY(inode))
 		inode->i_atime = CURRENT_TIME;
-	inode->i_dirt = 1;
-
+	mark_inode_dirty(inode);
+	
 	DPRINTK("smb_file_read: exit %s\n", SMB_FINFO(inode)->name);
 
 	return already_read;
@@ -196,8 +196,8 @@
 	}
 
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	inode->i_dirt = 1;
-
+	mark_inode_dirty(inode);
+	
 	file->f_pos = pos;
 
 	if (pos > inode->i_size)
diff -u --recursive --new-file v2.1.50/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.1.50/linux/fs/smbfs/inode.c	Thu Jun 26 12:33:39 1997
+++ linux/fs/smbfs/inode.c	Fri Aug 15 12:51:03 1997
@@ -228,7 +228,7 @@
 		sb->s_dev = 0;
 		return NULL;
 	}
-	if (!S_ISSOCK(filp->f_inode->i_mode))
+	if (!S_ISSOCK(filp->f_dentry->d_inode->i_mode))
 	{
 		printk("smb_read_super: not a socket!\n");
 		sb->s_dev = 0;
@@ -305,7 +305,8 @@
 	}
 	smb_init_root_dirent(server, &(server->root.finfo));
 
-	if (!(sb->s_mounted = iget(sb, smb_info_ino(&(server->root)))))
+	if (!(sb->s_root = d_alloc_root(iget(sb, 
+	                                smb_info_ino(&(server->root))),NULL)))
 	{
 		sb->s_dev = 0;
 		printk("smb_read_super: get root inode failed\n");
diff -u --recursive --new-file v2.1.50/linux/fs/smbfs/mmap.c linux/fs/smbfs/mmap.c
--- v2.1.50/linux/fs/smbfs/mmap.c	Thu Jul 17 10:06:07 1997
+++ linux/fs/smbfs/mmap.c	Fri Aug 15 12:51:03 1997
@@ -27,7 +27,7 @@
 smb_file_mmap_nopage(struct vm_area_struct *area,
 		     unsigned long address, int no_share)
 {
-	struct inode *inode = area->vm_inode;
+	struct inode *inode = area->vm_dentry->d_inode;
 	unsigned long page;
 	unsigned int clear;
 	unsigned long tmp;
@@ -117,7 +117,7 @@
 	if (!IS_RDONLY(inode))
 	{
 		inode->i_atime = CURRENT_TIME;
-		inode->i_dirt = 1;
+		mark_inode_dirty(inode);
 	}
 
 	vma->vm_dentry = dget(file->f_dentry);
diff -u --recursive --new-file v2.1.50/linux/fs/smbfs/sock.c linux/fs/smbfs/sock.c
--- v2.1.50/linux/fs/smbfs/sock.c	Mon Apr  7 11:35:31 1997
+++ linux/fs/smbfs/sock.c	Fri Aug 15 12:51:03 1997
@@ -128,7 +128,7 @@
 
 	if ((server == NULL)
 	    || ((file = server->sock_file) == NULL)
-	    || ((inode = file->f_inode) == NULL)
+	    || ((inode = file->f_dentry->d_inode) == NULL)
 	    || (!S_ISSOCK(inode->i_mode)))
 	{
 		printk("smb_catch_keepalive: did not get valid server!\n");
@@ -175,7 +175,7 @@
 
 	if ((server == NULL)
 	    || ((file = server->sock_file) == NULL)
-	    || ((inode = file->f_inode) == NULL)
+	    || ((inode = file->f_dentry->d_inode) == NULL)
 	    || (!S_ISSOCK(inode->i_mode)))
 	{
 		printk("smb_dont_catch_keepalive: "
@@ -322,7 +322,7 @@
 		return NULL;
 	if ((file = server->sock_file) == NULL)
 		return NULL;
-	if ((inode = file->f_inode) == NULL)
+	if ((inode = file->f_dentry->d_inode) == NULL)
 		return NULL;
 	return &(inode->u.socket_i);
 }
diff -u --recursive --new-file v2.1.50/linux/fs/super.c linux/fs/super.c
--- v2.1.50/linux/fs/super.c	Thu Aug 14 20:49:17 1997
+++ linux/fs/super.c	Mon Aug 18 13:04:41 1997
@@ -811,14 +811,12 @@
 	if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
 		if (!fs_may_remount_ro(sb))
 			return -EBUSY;
-	sb->s_flags = (flags & ~MS_RDONLY) | (sb->s_flags & MS_RDONLY);
 	if (sb->s_op && sb->s_op->remount_fs) {
 		retval = sb->s_op->remount_fs(sb, &flags, data);
 		if (retval)
 			return retval;
 	}
-	sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) |
-		(flags & MS_RMT_MASK);
+	sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
 	vfsmnt = lookup_vfsmnt(sb->s_dev);
 	if (vfsmnt)
 		vfsmnt->mnt_flags = sb->s_flags;
diff -u --recursive --new-file v2.1.50/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h
--- v2.1.50/linux/include/asm-m68k/pgtable.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-m68k/pgtable.h	Sat Aug 16 09:51:09 1997
@@ -159,6 +159,8 @@
     }
 }
 
+#define flush_icache_range(start, end)		do { } while (0)
+
 /*
  * flush all user-space atc entries.
  */
diff -u --recursive --new-file v2.1.50/linux/include/asm-mips/bitops.h linux/include/asm-mips/bitops.h
--- v2.1.50/linux/include/asm-mips/bitops.h	Thu Jun 26 12:33:39 1997
+++ linux/include/asm-mips/bitops.h	Sat Aug 16 09:51:09 1997
@@ -531,14 +531,16 @@
 #define ext2_find_next_zero_bit(addr, size, offset) \
                 find_next_zero_bit((addr), (size), (offset))
  
+#endif /* !(__MIPSEB__) */
+
 /*
  * Bitmap functions for the minix filesystem.
  * FIXME: These assume that Minix uses the native byte/bitorder.
+ * This limits the Minix filesystem's value for data exchange very much.
  */
 #define minix_set_bit(nr,addr) test_and_set_bit(nr,addr)
 #define minix_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
 #define minix_test_bit(nr,addr) test_bit(nr,addr)
 #define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
-#endif /* __KERNEL__ */
 
 #endif /* __ASM_MIPS_BITOPS_H */
diff -u --recursive --new-file v2.1.50/linux/include/asm-mips/checksum.h linux/include/asm-mips/checksum.h
--- v2.1.50/linux/include/asm-mips/checksum.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-mips/checksum.h	Sat Aug 16 09:51:09 1997
@@ -5,7 +5,9 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1995 by Ralf Baechle
+ * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
+ *
+ * $Id: checksum.h,v 1.5 1997/08/08 20:22:28 miguel Exp $
  */
 #ifndef __ASM_MIPS_CHECKSUM_H
 #define __ASM_MIPS_CHECKSUM_H
diff -u --recursive --new-file v2.1.50/linux/include/asm-mips/floppy.h linux/include/asm-mips/floppy.h
--- v2.1.50/linux/include/asm-mips/floppy.h	Thu Jun 26 12:33:39 1997
+++ linux/include/asm-mips/floppy.h	Sat Aug 16 09:51:09 1997
@@ -71,7 +71,7 @@
 {       
 #ifdef CONFIG_MIPS_JAZZ
         if (mips_machgroup == MACH_GROUP_JAZZ)
-		vdma_free(PHYSADDR(addr));
+		vdma_free(vdma_phys2log(PHYSADDR(addr)));
 #endif
 	free_pages(addr, __get_order(size));	
 }
diff -u --recursive --new-file v2.1.50/linux/include/asm-mips/gfx.h linux/include/asm-mips/gfx.h
--- v2.1.50/linux/include/asm-mips/gfx.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/gfx.h	Sat Aug 16 09:51:09 1997
@@ -0,0 +1,46 @@
+/*
+ * This is the user-visible SGI GFX interface.
+ *
+ * This must be used verbatim into the GNU libc.  It does not include
+ * any kernel-only bits on it.  
+ *
+ * miguel@nuclecu.unam.mx
+ */
+
+/* The iocls, yes, they do not make sense, but such is life */
+#define GFX_BASE             100
+#define GFX_GETNUM_BOARDS    (GFX_BASE + 1)
+#define GFX_GETBOARD_INFO    (GFX_BASE + 2)
+#define GFX_ATTACH_BOARD     (GFX_BASE + 3)
+#define GFX_DETACH_BOARD     (GFX_BASE + 4)
+#define GFX_IS_MANAGED       (GFX_BASE + 5)
+
+#define GFX_MAPALL           (GFX_BASE + 10)
+
+#define GFX_INFO_NAME_SIZE  16
+#define GFX_INFO_LABEL_SIZE 16
+
+struct gfx_info {
+	char name  [GFX_INFO_NAME_SIZE];  /* board name */
+	char label [GFX_INFO_LABEL_SIZE]; /* label name */
+	unsigned short int xpmax, ypmax;  /* screen resolution */
+	unsigned int lenght;	          /* size of a complete gfx_info for this board */
+};
+
+struct gfx_getboardinfo_args {
+	unsigned int board;     /* board number.  starting from zero */
+	void *buf;              /* pointer to gfx_info */
+	unsigned int len;       /* buffer size of buf */
+};
+
+struct gfx_attach_board_args {
+	unsigned int board;	/* board number, starting from zero */
+	void        *vaddr;	/* address where the board registers should be mapped */
+};
+
+#ifdef __KERNEL__
+/* umap.c */
+extern void remove_mapping (struct task_struct *, unsigned long, unsigned long);
+extern void *vmalloc_uncached (unsigned long size);
+extern int vmap_page_range (unsigned long from, unsigned long size, unsigned long vaddr);
+#endif
diff -u --recursive --new-file v2.1.50/linux/include/asm-mips/jazzdma.h linux/include/asm-mips/jazzdma.h
--- v2.1.50/linux/include/asm-mips/jazzdma.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-mips/jazzdma.h	Sat Aug 16 09:51:09 1997
@@ -21,6 +21,7 @@
 void vdma_set_addr(int channel, long addr);
 void vdma_set_count(int channel, int count);
 int vdma_get_residue(int channel);
+int vdma_get_enable(int channel);
 
 /*
  * some definitions used by the driver functions
diff -u --recursive --new-file v2.1.50/linux/include/asm-mips/keyboard.h linux/include/asm-mips/keyboard.h
--- v2.1.50/linux/include/asm-mips/keyboard.h	Thu Jun 26 12:33:39 1997
+++ linux/include/asm-mips/keyboard.h	Sat Aug 16 09:51:09 1997
@@ -5,9 +5,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * This file is a mess.  Put on your peril sensitive glasses.
- *
- * $Id: keyboard.h,v 1.4 1997/06/16 00:31:46 ralf Exp $
+ * $Id: keyboard.h,v 1.5 1997/08/08 20:22:31 miguel Exp $
  */
 #ifndef __ASM_MIPS_KEYBOARD_H
 #define __ASM_MIPS_KEYBOARD_H
@@ -17,6 +15,7 @@
 #include <linux/config.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
+#include <asm/bootinfo.h>
 
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
@@ -26,6 +25,7 @@
 extern char pckbd_unexpected_up(unsigned char keycode);
 extern void pckbd_leds(unsigned char leds);
 extern void pckbd_init_hw(void);
+extern unsigned char pckbd_sysrq_xlate[128];
 
 #define kbd_setkeycode		pckbd_setkeycode
 #define kbd_getkeycode		pckbd_getkeycode
@@ -34,204 +34,76 @@
 #define kbd_unexpected_up	pckbd_unexpected_up
 #define kbd_leds		pckbd_leds
 #define kbd_init_hw		pckbd_init_hw
+#define kbd_sysrq_xlate         pckbd_sysrq_xlate
 
-/*
- * The default IO slowdown is doing 'inb()'s from 0x61, which should be
- * safe. But as that is the keyboard controller chip address, we do our
- * slowdowns here by doing short jumps: the keyboard controller should
- * be able to keep up
- */
-#define REALLY_SLOW_IO
-#define SLOW_IO_BY_JUMPING
-#include <asm/io.h>
-
-/*
- * keyboard controller registers
- */
-#define KBD_STATUS_REG      (unsigned int) 0x64
-#define KBD_CNTL_REG        (unsigned int) 0x64
-#define KBD_DATA_REG        (unsigned int) 0x60
+#define SYSRQ_KEY 0x54
 
-#ifdef CONFIG_SGI
-#include <asm/segment.h>
-#include <asm/sgihpc.h>
-#endif
-#include <asm/bootinfo.h>
-#include <asm/jazz.h>
-
-#ifdef CONFIG_SGI
-#define KEYBOARD_IRQ 20
-#else
-/* Not true for Jazz machines, we cheat a bit for 'em. */
-#define KEYBOARD_IRQ 1
-#endif
+#define INIT_KBD	/* full initialization for the keyboard controller. */
 
-#ifdef CONFIG_SGI
-#define DISABLE_KBD_DURING_INTERRUPTS 1
-#else
-#define DISABLE_KBD_DURING_INTERRUPTS 0
-#endif
+/* Some stoneage hardware needs delays after some operations.  */
+#define kbd_pause() do { } while(0)
 
-#ifndef CONFIG_SGI
-#define KBD_REPORT_ERR
-#endif
-#define KBD_REPORT_UNKN
-/* #define KBD_IS_FOCUS_9000 */
+/* Pointers to keyboard hardware access and init functions.  */
+unsigned char (*kbd_read_input)(void);
+void (*kbd_write_output)(unsigned char val);
+void (*kbd_write_command)(unsigned char val);
+unsigned char (*kbd_read_status)(void);
 
-int (*kbd_inb_p)(unsigned short port);
-int (*kbd_inb)(unsigned short port);
-void (*kbd_outb_p)(unsigned char data, unsigned short port);
-void (*kbd_outb)(unsigned char data, unsigned short port);
+void (*keyboard_setup)(void);
 
 #ifdef CONFIG_MIPS_JAZZ
-#define INIT_KBD	/* full initialization for the keyboard controller. */
 
-static volatile keyboard_hardware *jazz_kh;
+/* Not true for Jazz machines, we cheat a bit for 'em. */
+#define KEYBOARD_IRQ 1
+
+/*
+ * No PS/2 style mouse support for Jazz machines
+ */
 
-static int
-jazz_kbd_inb_p(unsigned short port)
-{
-	int result;
-
-	if(port == KBD_DATA_REG)
-		result = jazz_kh->data;
-	else /* Must be KBD_STATUS_REG */
-		result = jazz_kh->command;
-	inb(0x80);
-
-	return result;
-}
-
-static int
-jazz_kbd_inb(unsigned short port)
-{
-	int result;
-
-	if(port == KBD_DATA_REG)
-		result = jazz_kh->data;
-	else /* Must be KBD_STATUS_REG */
-		result = jazz_kh->command;
-
-	return result;
-}
-
-static void
-jazz_kbd_outb_p(unsigned char data, unsigned short port)
-{
-	if(port == KBD_DATA_REG)
-		jazz_kh->data = data;
-	else if(port == KBD_CNTL_REG)
-		jazz_kh->command = data;
-	inb(0x80);
-}
-
-static void
-jazz_kbd_outb(unsigned char data, unsigned short port)
-{
-	if(port == KBD_DATA_REG)
-		jazz_kh->data = data;
-	else if(port == KBD_CNTL_REG)
-		jazz_kh->command = data;
-}
 #endif /* CONFIG_MIPS_JAZZ */
 
 #ifdef CONFIG_SGI
-#define INIT_KBD	/* full initialization for the keyboard controller. */
 
-static volatile struct hpc_keyb *sgi_kh;
+#define DISABLE_KBD_DURING_INTERRUPTS 1
+
+#define KEYBOARD_IRQ 20
+
+/*
+ * Machine specific bits for the PS/2 driver.
+ * Aux device and keyboard share the interrupt on the Indy.
+ */
+
+#define ps2_request_irq() 0
+#define ps2_free_irq(void) do { } while(0);
 
-static int
-sgi_kbd_inb(unsigned short port)
-{
-	int result;
-
-	if(port == KBD_DATA_REG)
-		result = sgi_kh->data;
-	else /* Must be KBD_STATUS_REG */
-		result = sgi_kh->command;
-
-	return result;
-}
-
-static void
-sgi_kbd_outb(unsigned char data, unsigned short port)
-{
-	if(port == KBD_DATA_REG)
-		sgi_kh->data = data;
-	else if(port == KBD_CNTL_REG)
-		sgi_kh->command = data;
-}
 #endif /* CONFIG_SGI */
 
+#if defined(CONFIG_ACER_PICA_61) || defined(CONFIG_SNI_RM200_PCI) \
+    || defined(CONFIG_DESKSTATION_RPC44) || defined(CONFIG_DESKSTATION_TYNE)
+#define CONF_KEYBOARD_USES_IO_PORTS
+#endif
+
+#ifdef CONF_KEYBOARD_USES_IO_PORTS
 /*
  * Most other MIPS machines access the keyboard controller via
- * ordinary I/O ports.
+ * memory mapped I/O ports.
  */
-static int
-port_kbd_inb_p(unsigned short port)
-{
-	return inb_p(port);
-}
-
-static int
-port_kbd_inb(unsigned short port)
-{
-	return inb(port);
-}
-
-static void
-port_kbd_outb_p(unsigned char data, unsigned short port)
-{
-	return outb_p(data, port);
-}
-
-static void
-port_kbd_outb(unsigned char data, unsigned short port)
-{
-	return outb(data, port);
-}
+#include <asm/io.h>
 
-extern __inline__ void keyboard_setup(void)
-{
-#ifdef CONFIG_MIPS_JAZZ
-        if (mips_machgroup == MACH_GROUP_JAZZ) {
-		jazz_kh = (void *) JAZZ_KEYBOARD_ADDRESS;
-		kbd_inb_p = jazz_kbd_inb_p;
-		kbd_inb = jazz_kbd_inb;
-		kbd_outb_p = jazz_kbd_outb_p;
-		kbd_outb = jazz_kbd_outb;
-		/*
-		 * Enable keyboard interrupts.
-		 */
-		*((volatile u16 *)JAZZ_IO_IRQ_ENABLE) |= JAZZ_IE_KEYBOARD;
-		set_cp0_status(IE_IRQ1, IE_IRQ1);
-	} else
-#endif
-	if (mips_machgroup == MACH_GROUP_ARC ||	/* this is for Deskstation */
-	    (mips_machgroup == MACH_GROUP_SNI_RM
-	     && mips_machtype == MACH_SNI_RM200_PCI)) {
-		/*
-		 * These machines address their keyboard via the normal
-		 * port address range.
-		 *
-		 * Also enable Scan Mode 2.
-		 */
-		kbd_inb_p = port_kbd_inb_p;
-		kbd_inb = port_kbd_inb;
-		kbd_outb_p = port_kbd_outb_p;
-		kbd_outb = port_kbd_outb;
-		request_region(0x60,16,"keyboard");
-	}
-#ifdef CONFIG_SGI
-	if (mips_machgroup == MACH_GROUP_SGI) {
-		sgi_kh = (struct hpc_keyb *) (KSEG1 + 0x1fbd9800 + 64);
-		kbd_inb_p = sgi_kbd_inb;
-		kbd_inb = sgi_kbd_inb;
-		kbd_outb_p = sgi_kbd_outb;
-		kbd_outb = sgi_kbd_outb;
-	}
-#endif
-}
+#define KEYBOARD_IRQ 1
+
+/*
+ * Machine specific bits for the PS/2 driver
+ */
+
+#define AUX_IRQ 12
+
+#define ps2_request_irq()						\
+	request_irq(AUX_IRQ, aux_interrupt, 0, "PS/2 Mouse", NULL)
+
+#define ps2_free_irq(inode) free_irq(AUX_IRQ, NULL)
+
+#endif /* CONF_KEYBOARD_USES_IO_PORTS */
 
 #endif /* __KERNEL */
 #endif /* __ASM_MIPS_KEYBOARD_H */
diff -u --recursive --new-file v2.1.50/linux/include/asm-mips/ng1.h linux/include/asm-mips/ng1.h
--- v2.1.50/linux/include/asm-mips/ng1.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/ng1.h	Sat Aug 16 09:51:09 1997
@@ -0,0 +1,26 @@
+/*
+ * SGI/Newport video card ioctl definitions
+ *
+ */
+
+typedef struct {
+        int flags;
+        u16 w, h;
+        u16 fields_sec;
+} ng1_vof_info_t;
+
+struct ng1_info {
+	struct gfx_info gfx_info;
+	u8 boardrev;
+        u8 rex3rev;
+        u8 vc2rev;
+        u8 monitortype;
+        u8 videoinstalled;
+        u8 mcrev;
+        u8 bitplanes;
+        u8 xmap9rev;
+        u8 cmaprev;
+        ng1_vof_info_t ng1_vof_info;
+        u8 bt445rev;
+        u8 paneltype;
+};
diff -u --recursive --new-file v2.1.50/linux/include/asm-mips/pgtable.h linux/include/asm-mips/pgtable.h
--- v2.1.50/linux/include/asm-mips/pgtable.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-mips/pgtable.h	Sat Aug 16 09:51:09 1997
@@ -16,6 +16,7 @@
  *  - flush_cache_page(mm, vmaddr) flushes a single page
  *  - flush_cache_range(mm, start, end) flushes a range of pages
  *  - flush_page_to_ram(page) write back kernel page to ram
+ *
  */
 extern void (*flush_cache_all)(void);
 extern void (*flush_cache_mm)(struct mm_struct *mm);
@@ -24,6 +25,7 @@
 extern void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page);
 extern void (*flush_cache_sigtramp)(unsigned long addr);
 extern void (*flush_page_to_ram)(unsigned long page);
+#define flush_icache_range(start, end)		do { } while (0)
 
 /* TLB flushing:
  *
@@ -38,6 +40,13 @@
 			       unsigned long end);
 extern void (*flush_tlb_page)(struct vm_area_struct *vma, unsigned long page);
 
+/*
+ * - add_wired_entry() add a fixed TLB entry, and move wired register
+ */
+extern void (*add_wired_entry)(unsigned long entrylo0, unsigned long entrylo1,
+			       unsigned long entryhi, unsigned long pagemask);
+
+
 /* Basically we have the same two-level (which is the logical three level
  * Linux page table layout folded) page tables as the i386.  Some day
  * when we have proper page coloring support we can have a 1% quicker
@@ -108,21 +117,25 @@
 #define _CACHE_CACHABLE_ACCELERATED (7<<9)  /* R10000 only             */
 #define _CACHE_MASK                 (7<<9)
 
-#define __READABLE	(_PAGE_READ|_PAGE_SILENT_READ|_PAGE_ACCESSED)
-#define __WRITEABLE	(_PAGE_WRITE|_PAGE_SILENT_WRITE|_PAGE_MODIFIED)
+#define __READABLE	(_PAGE_READ | _PAGE_SILENT_READ | _PAGE_ACCESSED)
+#define __WRITEABLE	(_PAGE_WRITE | _PAGE_SILENT_WRITE | _PAGE_MODIFIED)
 
 #define _PAGE_CHG_MASK  (PAGE_MASK | __READABLE | __WRITEABLE | _CACHE_MASK)
 
 #define PAGE_NONE	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \
                         _CACHE_CACHABLE_NONCOHERENT)
 #define PAGE_SHARED     __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
-			_PAGE_ACCESSED | _CACHE_CACHABLE_NONCOHERENT)
+			_CACHE_CACHABLE_NONCOHERENT)
 #define PAGE_COPY       __pgprot(_PAGE_PRESENT | _PAGE_READ | \
 			_CACHE_CACHABLE_NONCOHERENT)
 #define PAGE_READONLY   __pgprot(_PAGE_PRESENT | _PAGE_READ | \
 			_CACHE_CACHABLE_NONCOHERENT)
 #define PAGE_KERNEL	__pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \
 			_CACHE_CACHABLE_NONCOHERENT)
+#define PAGE_USERIO     __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \
+			_CACHE_UNCACHED)
+#define PAGE_KERNEL_UNCACHED __pgprot(_PAGE_PRESENT | __READABLE | __WRITEABLE | \
+			_CACHE_UNCACHED)
 
 /*
  * MIPS can't do page protection for execute, and considers that the same like
@@ -217,7 +230,7 @@
  */
 extern inline void set_pte(pte_t *ptep, pte_t pteval)
 {
-        *ptep = pteval;
+	*ptep = pteval;
 }
 
 extern inline void pte_clear(pte_t *ptep)
@@ -230,7 +243,7 @@
  */
 extern inline int pmd_none(pmd_t pmd)
 {
-	return pmd_val(pmd) == ((unsigned long) invalid_pte_table);
+	return pmd_val(pmd) == (unsigned long) invalid_pte_table;
 }
 
 extern inline int pmd_bad(pmd_t pmd)
@@ -288,7 +301,7 @@
 
 extern inline pte_t pte_mkold(pte_t pte)
 {
-	pte_val(pte) &= ~(_PAGE_ACCESSED|_PAGE_SILENT_READ|_PAGE_SILENT_WRITE);
+	pte_val(pte) &= ~(_PAGE_ACCESSED|_PAGE_SILENT_READ);
 	return pte;
 }
 
@@ -319,12 +332,8 @@
 extern inline pte_t pte_mkyoung(pte_t pte)
 {
 	pte_val(pte) |= _PAGE_ACCESSED;
-	if (pte_val(pte) & _PAGE_READ) {
+	if (pte_val(pte) & _PAGE_READ)
 		pte_val(pte) |= _PAGE_SILENT_READ;
-		if ((pte_val(pte) & (_PAGE_WRITE|_PAGE_MODIFIED)) ==
-		    (_PAGE_WRITE|_PAGE_MODIFIED))
-			pte_val(pte) |= _PAGE_SILENT_WRITE;
-	}
 	return pte;
 }
 
@@ -541,7 +550,7 @@
 		".set noreorder\n\t"
 		".set mips3\n\t"
 		"mfc0 %0, $5\n\t"
-		".set mips2\n\t"
+		".set mips0\n\t"
 		".set reorder"
 		: "=r" (val));
 	return val;
@@ -553,7 +562,7 @@
 		".set noreorder\n\t"
 		".set mips3\n\t"
 		"mtc0 %0, $5\n\t"
-		".set mips2\n\t"
+		".set mips0\n\t"
 		".set reorder"
 		: : "r" (val));
 }
@@ -567,7 +576,7 @@
 		".set noreorder\n\t"
 		".set mips3\n\t"
 		"mfc0 %0, $2\n\t"
-		".set mips2\n\t"
+		".set mips0\n\t"
 		".set reorder"
 		: "=r" (val));
 	return val;
@@ -579,7 +588,7 @@
 		".set noreorder\n\t"
 		".set mips3\n\t"
 		"mtc0 %0, $2\n\t"
-		".set mips2\n\t"
+		".set mips0\n\t"
 		".set reorder"
 		: : "r" (val));
 }
@@ -592,7 +601,7 @@
 		".set noreorder\n\t"
 		".set mips3\n\t"
 		"mfc0 %0, $3\n\t"
-		".set mips2\n\t"
+		".set mips0\n\t"
 		".set reorder" : "=r" (val));
 
 	return val;
@@ -604,7 +613,7 @@
 		".set noreorder\n\t"
 		".set mips3\n\t"
 		"mtc0 %0, $3\n\t"
-		".set mips2\n\t"
+		".set mips0\n\t"
 		".set reorder"
 		: : "r" (val));
 }
@@ -618,7 +627,7 @@
 		".set noreorder\n\t"
 		".set mips3\n\t"
 		"mfc0 %0, $10\n\t"
-		".set mips2\n\t"
+		".set mips0\n\t"
 		".set reorder"
 		: "=r" (val));
 
@@ -631,7 +640,7 @@
 		".set noreorder\n\t"
 		".set mips3\n\t"
 		"mtc0 %0, $10\n\t"
-		".set mips2\n\t"
+		".set mips0\n\t"
 		".set reorder"
 		: : "r" (val));
 }
@@ -645,7 +654,7 @@
 		".set noreorder\n\t"
 		".set mips3\n\t"
 		"mfc0 %0, $0\n\t"
-		".set mips2\n\t"
+		".set mips0\n\t"
 		".set reorder"
 		: "=r" (val));
 	return val;
@@ -657,7 +666,7 @@
 		".set noreorder\n\t"
 		".set mips3\n\t"
 		"mtc0 %0, $0\n\t"
-		".set mips2\n\t"
+		".set mips0\n\t"
 		".set reorder\n\t"
 		: : "r" (val));
 }
@@ -671,7 +680,7 @@
 		".set noreorder\n\t"
 		".set mips3\n\t"
 		"mfc0 %0, $6\n\t"
-		".set mips2\n\t"
+		".set mips0\n\t"
 		".set reorder\n\t"
 		: "=r" (val));
 	return val;
@@ -683,7 +692,7 @@
 		"\n\t.set noreorder\n\t"
 		".set mips3\n\t"
 		"mtc0 %0, $6\n\t"
-		".set mips2\n\t"
+		".set mips0\n\t"
 		".set reorder"
 		: : "r" (val));
 }
@@ -697,7 +706,7 @@
 		".set noreorder\n\t"
 		".set mips3\n\t"
 		"mfc0 %0, $28\n\t"
-		".set mips2\n\t"
+		".set mips0\n\t"
 		".set reorder"
 		: "=r" (val));
 	return val;
@@ -709,7 +718,7 @@
 		".set noreorder\n\t"
 		".set mips3\n\t"
 		"mtc0 %0, $28\n\t"
-		".set mips2\n\t"
+		".set mips0\n\t"
 		".set reorder"
 		: : "r" (val));
 }
@@ -722,7 +731,7 @@
 		".set noreorder\n\t"
 		".set mips3\n\t"
 		"mfc0 %0, $29\n\t"
-		".set mips2\n\t"
+		".set mips0\n\t"
 		".set reorder"
 		: "=r" (val));
 	return val;
@@ -734,7 +743,7 @@
 		".set noreorder\n\t"
 		".set mips3\n\t"
 		"mtc0 %0, $29\n\t"
-		".set mips2\n\t"
+		".set mips0\n\t"
 		".set reorder"
 		: : "r" (val));
 }
@@ -748,7 +757,7 @@
 		".set noreorder\n\t"
 		".set mips3\n\t"
 		"mfc0 %0, $4\n\t"
-		".set mips2\n\t"
+		".set mips0\n\t"
 		".set reorder"
 		: "=r" (val));
 
@@ -761,14 +770,11 @@
 		".set noreorder\n\t"
 		".set mips3\n\t"
 		"mtc0 %0, $4\n\t"
-		".set mips2\n\t"
+		".set mips0\n\t"
 		".set reorder"
 		: : "r" (val));
 }
 
 #endif /* !defined (__LANGUAGE_ASSEMBLY__) */
-
-#define module_map      vmalloc
-#define module_unmap    vfree
 
 #endif /* __ASM_MIPS_PGTABLE_H */
diff -u --recursive --new-file v2.1.50/linux/include/asm-mips/rrm.h linux/include/asm-mips/rrm.h
--- v2.1.50/linux/include/asm-mips/rrm.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/rrm.h	Sat Aug 16 09:51:09 1997
@@ -0,0 +1,88 @@
+/*
+ * SGI Rendering Resource Manager API (?).
+ *
+ * written by Miguel de Icaza (miguel@nuclecu.unam.mx)
+ *
+ * Ok, even if SGI choosed to do mmap trough ioctls, their
+ * kernel support for virtualizing the graphics card is nice.
+ *
+ * We should be able to make graphic applications on Linux
+ * fly.
+ *
+ * This header file should be included from GNU libc as well.
+ */
+
+
+/* Why like this you say?  Well, gdb can print enums */
+#define RRM_BASE 1000
+#define RRM_CMD_LIMIT (RRM_BASE + 100)
+
+enum {
+	RRM_OPENRN = RRM_BASE,	/* open rendering node */
+	RRM_CLOSERN,
+	RRM_BINDPROCTORN,	/* set current rendering region for node */
+	RRM_BINDRNTOCLIP,
+	RRM_UNBINDRNFROMCLIP,
+	RRM_SWAPBUF,
+	RRM_SETSWAPINTERVAL,
+	RRM_WAITFORRETRACE,
+	RRM_SETDISPLAYMODE,
+	RRM_MESSAGE,
+	RRM_INVALIDATERN,
+	RRM_VALIDATECLIP,
+	RRM_VALIDATESWAPBUF,
+	RRM_SWAPGROUP,
+	RRM_SWAPUNGROUP,
+	RRM_VALIDATEMESSAGE,
+	RRM_GETDISPLAYMODES,
+	RRM_LOADDISPLAYMODE,
+	RRM_CUSHIONBUFFER,
+	RRM_SWAPREADY,
+	RRM_MGR_SWAPBUF,
+	RRM_SETVSYNC,
+	RRM_GETVSYNC,
+	RRM_WAITVSYNC,
+	RRM_BINDRNTOREADANDCLIP,
+	RRM_MAPCLIPTOSWPBUFID
+};
+
+/* Parameters for the above ioctls
+ *
+ * All of the ioctls take as their first argument the rendering node id.
+ *
+ */
+
+/*
+ * RRM_OPENRN:
+ *
+ * This is called by the IRIX X server with:
+ * rnid = 0xffffffff rmask = 0
+ *
+ * Returns a number like this: 0x10001.
+ * If you run the X server over and over, you get a value
+ * that is of the form (n * 0x10000) + 1.
+ *
+ * The return value seems to be the RNID.
+ */
+struct RRM_OpenRN {
+	int      rnid;
+	unsigned int rmask;
+};
+
+struct RRM_CloseRN {
+	int rnid;
+};
+
+/*
+ * RRM_BINDPROCTORN:
+ *
+ * Return value when the X server calls it: 0
+ */ 
+struct RRM_BindProcToRN {
+	int      rnid;
+};
+
+#ifdef __KERNEL__
+int rrm_command (unsigned int cmd, void *arg);
+int rrm_close (struct inode *inode, struct file *file);
+#endif
diff -u --recursive --new-file v2.1.50/linux/include/asm-mips/shmiq.h linux/include/asm-mips/shmiq.h
--- v2.1.50/linux/include/asm-mips/shmiq.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-mips/shmiq.h	Sat Aug 16 09:51:09 1997
@@ -0,0 +1,195 @@
+/*
+ * Please note that the comments on this file may be out of date
+ * and that they represent what I have figured about the shmiq device
+ * so far in IRIX.
+ *
+ * This also contains some streams and idev bits.
+ *
+ * They may contain errors, please, refer to the source code of the Linux  
+ * kernel for a definitive answer on what we have implemented
+ *
+ * Miguel.
+ */
+
+/* STREAMs ioctls */
+#define STRIOC    ('S' << 8)
+#define I_STR     (STRIOC | 010)
+#define I_PUSH    (STRIOC | 02)
+#define I_LINK    (STRIOC | 014)
+#define I_UNLINK  (STRIOC | 015)
+
+/* Data structure passed on I_STR ioctls */
+struct strioctl {
+        int     ic_cmd;                 /* streams ioctl command */
+        int     ic_timout;              /* timeout */
+        int     ic_len;                 /* lenght of data */
+        void    *ic_dp;                 /* data */
+};
+
+/*
+ * For mapping the shared memory input queue, you have to:
+ *
+ * 1. Map /dev/zero for the number of bytes you want to use
+ *    for your shared memory input queue plus the size of the
+ *    sharedMemoryInputQueue structure + 4 (I still have not figured
+ *    what this one is for
+ *
+ * 2. Open /dev/shmiq
+ *
+ * 3. Open /dev/qcntlN N is [0..Nshmiqs]
+ *
+ * 4. Fill a shmiqreq structure.  user_vaddr should point to the return
+ *    address from the /dev/zero mmap.  Arg is the number of shmqevents
+ *    that fit into the /dev/zero region (remember that at the beginning there
+ *    is a sharedMemoryInputQueue header).
+ *
+ * 5. Issue the ioctl (qcntlfd, QIOCATTACH, &your_shmiqreq);
+ */
+
+struct shmiqreq {
+	char *user_vaddr;
+	int  arg;
+};
+
+/* map the shmiq into the process address space */
+#define QIOCATTACH       _IOW('Q',1,struct shmiqreq)
+
+/* remove mappings */
+#define QIOCDETACH       _IO('Q',2)
+
+/*
+ * A shared memory input queue event.
+ */
+struct shmqdata {
+	unsigned char device;          /* device major */
+        unsigned char which;           /* device minor */
+        unsigned char type;            /* event type */
+        unsigned char flags;           /* little event data */
+        union {
+            int pos;                   /* big event data */
+            short ptraxis [2];         /* event data for PTR events */
+        } un;
+};
+
+/* indetifies the shmiq and the device */
+struct shmiqlinkid {
+        short int devminor;
+        short int index;
+};
+
+struct shmqevent {
+	union {
+                int time;
+                struct shmiqlinkid id;
+        } un ;
+        struct shmqdata data ;
+};
+
+/*
+ * sharedMemoryInputQueue: this describes the shared memory input queue.
+ *
+ * head   is the user index into the events, user can modify this one.
+ * tail   is managed by the kernel.
+ * flags  is one of SHMIQ_OVERFLOW or SHMIQ_CORRUPTED
+ *        if OVERFLOW is set it seems ioctl QUIOCSERVICED should be called 
+ *        to notify the kernel.
+ * events where the kernel sticks the events.
+ */
+struct sharedMemoryInputQueue {
+	volatile int head;	     /* user's index into events */
+        volatile int tail;	     /* kernel's index into events */
+        volatile unsigned int flags; /* place for out-of-band data */
+#define SHMIQ_OVERFLOW  1
+#define SHMIQ_CORRUPTED 2
+        struct shmqevent events[1];  /* input event buffer */
+};
+
+/* have to figure this one out */
+#define QIOCGETINDX      _IOWR('Q', 8, int)
+
+
+/* acknowledge shmiq overflow */
+#define QIOCSERVICED     _IO('Q', 3)
+
+/* Double indirect I_STR ioctl, yeah, fun fun fun */
+
+struct muxioctl {
+        int index;		/* lower stream index */
+        int realcmd;		/* the actual command for the subdevice */
+};
+/* Double indirect ioctl */
+#define QIOCIISTR        _IOW('Q', 7, struct muxioctl)
+
+/* Cursor ioclts: */
+
+/* set cursor tracking mode */
+#define QIOCURSTRK      _IOW('Q', 4, int)
+
+/* set cursor filter box */
+#define QIOCURSIGN      _IOW('Q', 5, int [4])
+
+/* set cursor axes */
+struct shmiqsetcurs {
+        short index;
+        short axes;
+};
+
+#define QIOCSETCURS     _IOWR('Q',  9, struct shmiqsetcurs)
+
+/* set cursor position */
+struct shmiqsetcpos {
+        short   x;
+        short   y;
+};
+#define QIOCSETCPOS     _IOWR('Q', 10, struct shmiqsetcpos)
+
+/* get time since last event */
+#define QIOCGETITIME    _IOR('Q', 11, time_t)
+
+/* set curent screen */
+#define QIOCSETSCRN     _IOW('Q',6,int)
+
+
+/* -------------------- iDev stuff -------------------- */
+
+#define IDEV_MAX_NAME_LEN 15
+#define IDEV_MAX_TYPE_LEN 15
+
+typedef struct {
+        char            devName[IDEV_MAX_NAME_LEN+1];
+        char            devType[IDEV_MAX_TYPE_LEN+1];
+        unsigned short  nButtons;
+        unsigned short  nValuators;
+        unsigned short  nLEDs;
+        unsigned short  nStrDpys;
+        unsigned short  nIntDpys;
+        unsigned char   nBells;
+        unsigned char   flags;
+#define IDEV_HAS_KEYMAP		0x01
+#define IDEV_HAS_PROXIMITY 	0x02
+#define IDEV_HAS_PCKBD 		0x04
+} idevDesc;
+
+typedef struct {
+	char *nothing_for_now;
+} idevInfo;
+
+typedef struct {
+        char name [16];
+} idevKeymapDesc;
+
+#define IDEVINITDEVICE		_IOW('i', 51, unsigned int)
+#define IDEVGETDEVICEDESC	_IOWR('i', 0, idevDesc)
+#define IDEVGETKEYMAPDESC	_IOWR('i', 2, idevKeymapDesc)
+
+#ifdef __KERNEL__
+
+/* These are only interpreted by SHMIQ-attacheable devices and are internal
+ * to the kernel
+ */
+#define SHMIQ_OFF        _IO('Q',1)
+#define SHMIQ_ON         _IO('Q',2)
+
+void shmiq_push_event (struct shmqevent *e);
+int get_sioc (struct strioctl *sioc, unsigned long arg);
+#endif
diff -u --recursive --new-file v2.1.50/linux/include/asm-mips/string.h linux/include/asm-mips/string.h
--- v2.1.50/linux/include/asm-mips/string.h	Thu Jun 26 12:33:40 1997
+++ linux/include/asm-mips/string.h	Sat Aug 16 09:51:09 1997
@@ -5,7 +5,9 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (c) 1994, 1995, 1996 by Ralf Baechle
+ * Copyright (c) 1994, 1995, 1996, 1997 by Ralf Baechle
+ *
+ * $Id: string.h,v 1.4 1997/08/08 20:22:34 miguel Exp $
  */
 #ifndef __ASM_MIPS_STRING_H
 #define __ASM_MIPS_STRING_H
@@ -117,7 +119,7 @@
 }
 
 #define __HAVE_ARCH_MEMSET
-extern void *memset(void *__s, char __c, size_t __count);
+extern void *memset(void *__s, int __c, size_t __count);
 
 #define __HAVE_ARCH_MEMCPY
 extern void *memcpy(void *__to, __const__ void *__from, size_t __n);
diff -u --recursive --new-file v2.1.50/linux/include/asm-mips/system.h linux/include/asm-mips/system.h
--- v2.1.50/linux/include/asm-mips/system.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-mips/system.h	Sat Aug 16 09:51:09 1997
@@ -252,7 +252,7 @@
 	return x;
 }
 
-extern unsigned long IRQ_vectors[16];
+extern unsigned long IRQ_vectors[32];
 extern unsigned long exception_handlers[32];
 
 #define set_int_vector(n,addr) \
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/bitops.h linux/include/asm-ppc/bitops.h
--- v2.1.50/linux/include/asm-ppc/bitops.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/bitops.h	Sat Aug 16 09:51:09 1997
@@ -1,17 +1,26 @@
+/*
+ * $Id: bitops.h,v 1.7 1997/08/03 00:12:07 paulus Exp $
+ * bitops.h: Bit string operations on the ppc
+ */
+
 #ifndef _ASM_PPC_BITOPS_H_
 #define _ASM_PPC_BITOPS_H_
 
 #include <asm/system.h>
 #include <asm/byteorder.h>
-#include <linux/kernel.h> /* for printk */
-
-#define BIT(n) 1<<(n&0x1F)
-typedef unsigned long BITFIELD;
 
+extern void set_bit(int nr, volatile void *addr);
+extern void clear_bit(int nr, volatile void *addr);
+extern void change_bit(int nr, volatile void *addr);
+extern int test_and_set_bit(int nr, volatile void *addr);
+extern int test_and_clear_bit(int nr, volatile void *addr);
+extern int test_and_change_bit(int nr, volatile void *addr);
 
 /*
- * These are ifdef'd out here because using : "cc" as a constraing
+ * These are if'd out here because using : "cc" as a constraint
  * results in errors from gcc. -- Cort
+ * Besides, they need to be changed so we have both set_bit
+ * and test_and_set_bit, etc.
  */
 #if 0
 extern __inline__ int set_bit(int nr, void * addr)
@@ -20,9 +29,6 @@
 	unsigned long mask = 1 << (nr & 0x1f);
 	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
 	
-	if ((unsigned long)addr & 3)
-		printk("set_bit(%lx, %p)\n", nr, addr);
-
 	__asm__ __volatile__(
 		"1:lwarx %0,0,%3 \n\t"
 		"or	%1,%0,%2 \n\t"
@@ -32,7 +38,7 @@
 		: "r" (mask), "r" (p)
 		/*: "cc" */);
 
-n	return (old & mask) != 0;
+	return (old & mask) != 0;
 }
 
 extern __inline__  unsigned long clear_bit(unsigned long nr, void *addr)
@@ -41,8 +47,6 @@
 	unsigned long mask = 1 << (nr & 0x1f);
 	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
 
-	if ((unsigned long)addr & 3)
-		printk("clear_bit(%lx, %p)\n", nr, addr);
 	__asm__ __volatile__("\n\
 1:	lwarx	%0,0,%3
 	andc	%1,%0,%2
@@ -61,8 +65,6 @@
 	unsigned long mask = 1 << (nr & 0x1f);
 	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
 
-	if ((unsigned long)addr & 3)
-		printk("change_bit(%lx, %p)\n", nr, addr);
 	__asm__ __volatile__("\n\
 1:	lwarx	%0,0,%3
 	xor	%1,%0,%2
@@ -76,10 +78,19 @@
 }
 #endif
 
+extern __inline__ unsigned long test_bit(int nr, __const__ volatile void *addr)
+{
+	__const__ unsigned int *p = (__const__ unsigned int *) addr;
+
+	return (p[nr >> 5] >> (nr & 0x1f)) & 1UL;
+}
+
 extern __inline__ int ffz(unsigned int x)
 {
 	int n;
 
+	if (x == ~0)
+		return 32;
 	x = ~x & (x+1);		/* set LS zero to 1, other bits to 0 */
 	__asm__ ("cntlzw %0,%1" : "=r" (n) : "r" (x));
 	return 31 - n;
@@ -89,34 +100,11 @@
  * This implementation of find_{first,next}_zero_bit was stolen from
  * Linus' asm-alpha/bitops.h.
  */
+#define find_first_zero_bit(addr, size) \
+	find_next_zero_bit((addr), (size), 0)
 
-extern __inline__ unsigned long find_first_zero_bit(void * addr, unsigned long size)
-{
-	unsigned int * p = ((unsigned int *) addr);
-	unsigned int result = 0;
-	unsigned int tmp;
-
-	if (size == 0)
-		return 0;
-	while (size & ~31UL) {
-		if (~(tmp = *(p++)))
-			goto found_middle;
-		result += 32;
-		size -= 32;
-	}
-	if (!size)
-		return result;
-	tmp = *p;
-	tmp |= ~0UL << size;
-found_middle:
-	return result + ffz(tmp);
-}
-
-/*
- * Find next zero bit in a bitmap reasonably efficiently..
- */
-extern __inline__ unsigned long find_next_zero_bit(void * addr, unsigned long size,
-				 unsigned long offset)
+extern __inline__ unsigned long find_next_zero_bit(void * addr,
+	unsigned long size, unsigned long offset)
 {
 	unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
 	unsigned int result = offset & ~31UL;
@@ -127,17 +115,17 @@
 	size -= result;
 	offset &= 31UL;
 	if (offset) {
-		tmp = *(p++);
+		tmp = *p++;
 		tmp |= ~0UL >> (32-offset);
 		if (size < 32)
 			goto found_first;
-		if (~tmp)
+		if (tmp != ~0U)
 			goto found_middle;
 		size -= 32;
 		result += 32;
 	}
-	while (size & ~31UL) {
-		if (~(tmp = *(p++)))
+	while (size >= 32) {
+		if ((tmp = *p++) != ~0U)
 			goto found_middle;
 		result += 32;
 		size -= 32;
@@ -153,101 +141,98 @@
 
 
 #define _EXT2_HAVE_ASM_BITOPS_
-#define ext2_find_first_zero_bit(addr, size) \
-        ext2_find_next_zero_bit((addr), (size), 0)
 
+#ifdef __KERNEL__
+/*
+ * test_and_{set,clear}_bit guarantee atomicity without
+ * disabling interrupts.
+ */
+#define ext2_set_bit(nr, addr)		test_and_set_bit((nr) ^ 0x18, addr)
+#define ext2_clear_bit(nr, addr)	test_and_clear_bit((nr) ^ 0x18, addr)
 
+#else
 extern __inline__ int ext2_set_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 |= mask;
-#ifdef __KERNEL__	
-  _enable_interrupts(s);
-#endif
-  return oldbit;
+	int		mask;
+	unsigned char	*ADDR = (unsigned char *) addr;
+	int oldbit;
+
+	ADDR += nr >> 3;
+	mask = 1 << (nr & 0x07);
+	oldbit = (*ADDR & mask) ? 1 : 0;
+	*ADDR |= mask;
+	return oldbit;
 }
 
 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;
-}
+	int		mask;
+	unsigned char	*ADDR = (unsigned char *) addr;
+	int oldbit;
 
-
-/* The following routine need not be atomic. */
-extern __inline__ unsigned long test_bit(int nr, void *addr)
-{
-	return 1UL & (((__const__ unsigned int *) addr)[nr >> 5] >> (nr & 31));
+	ADDR += nr >> 3;
+	mask = 1 << (nr & 0x07);
+	oldbit = (*ADDR & mask) ? 1 : 0;
+	*ADDR = *ADDR & ~mask;
+	return oldbit;
 }
+#endif	/* __KERNEL__ */
 
 extern __inline__ int ext2_test_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);
+	return (ADDR[nr >> 3] >> (nr & 7)) & 1;
 }
 
-extern __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
+/*
+ * This implementation of ext2_find_{first,next}_zero_bit was stolen from
+ * Linus' asm-alpha/bitops.h and modified for a big-endian machine.
+ */
+
+#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)
 {
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
-	unsigned long result = offset & ~31UL;
-	unsigned long tmp;
+	unsigned int *p = ((unsigned int *) addr) + (offset >> 5);
+	unsigned int result = offset & ~31UL;
+	unsigned int tmp;
 
 	if (offset >= size)
 		return size;
 	size -= result;
 	offset &= 31UL;
-	if(offset) {
-		tmp = *(p++);
-		tmp |= le32_to_cpu(~0UL >> (32-offset));
-		if(size < 32)
+	if (offset) {
+		tmp = cpu_to_le32p(p++);
+		tmp |= ~0UL >> (32-offset);
+		if (size < 32)
 			goto found_first;
-		if(~tmp)
+		if (tmp != ~0U)
 			goto found_middle;
 		size -= 32;
 		result += 32;
 	}
-	while(size & ~31UL) {
-		if(~(tmp = *(p++)))
+	while (size >= 32) {
+		if ((tmp = cpu_to_le32p(p++)) != ~0U)
 			goto found_middle;
 		result += 32;
 		size -= 32;
 	}
-	if(!size)
+	if (!size)
 		return result;
-	tmp = *p;
-
+	tmp = cpu_to_le32p(p);
 found_first:
-	return result + ffz(le32_to_cpu(tmp) | (~0UL << size));
+	tmp |= ~0U << size;
 found_middle:
-	return result + ffz(le32_to_cpu(tmp));
+	return result + ffz(tmp);
 }
 
-#endif /* _ASM_PPC_BITOPS_H */
-
+/* Bitmap functions for the minix filesystem.  */
+#define minix_set_bit(nr,addr) ext2_set_bit(nr,addr)
+#define minix_clear_bit(nr,addr) ext2_clear_bit(nr,addr)
+#define minix_test_bit(nr,addr) ext2_test_bit(nr,addr)
+#define minix_find_first_zero_bit(addr,size) ext2_find_first_zero_bit(addr,size)
 
+#endif /* _ASM_PPC_BITOPS_H */
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/byteorder.h linux/include/asm-ppc/byteorder.h
--- v2.1.50/linux/include/asm-ppc/byteorder.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/byteorder.h	Sat Aug 16 09:51:09 1997
@@ -4,17 +4,17 @@
 #include <asm/types.h>
 
 #ifndef __BIG_ENDIAN
-#define __BIG_ENDIAN
+#define __BIG_ENDIAN	4321
 #endif
 
 #ifndef __BIG_ENDIAN_BITFIELD
 #define __BIG_ENDIAN_BITFIELD
 #endif
 
-#define ntohl(x) (x)
-#define ntohs(x) (x)
-#define htonl(x) (x)
-#define htons(x) (x)
+#define ntohl(x) ((unsigned long)(x))
+#define ntohs(x) ((unsigned short)(x))
+#define htonl(x) ((unsigned long)(x))
+#define htons(x) ((unsigned short)(x))
 
 #define __htonl(x) ntohl(x)
 #define __htons(x) ntohs(x)
@@ -54,7 +54,7 @@
 	asm volatile("stwbrx %0,0,%1" : : "r" (val), "r" (addr) : "memory");
 }
 
-
+#if 0
 extern __inline__ __u16 cpu_to_le16(__u16 value)
 {
 	return ld_le16(&value);
@@ -63,6 +63,29 @@
 {
 	return ld_le32(&value);
 }
+#else
+extern __inline__ __u16 cpu_to_le16(__u16 value)
+{
+	__u16 result;
+
+	asm("rlwimi %0,%1,8,16,23"
+	    : "=r" (result)
+	    : "r" (value), "0" (value >> 8));
+	return result;
+}
+extern __inline__ __u32 cpu_to_le32(__u32 value)
+{
+	__u32 result;
+
+	asm("rlwimi %0,%1,24,16,23\n\t"
+	    "rlwimi %0,%1,8,8,15\n\t"
+	    "rlwimi %0,%1,24,0,7"
+	    : "=r" (result)
+	    : "r" (value), "0" (value >> 24));
+	return result;
+}
+#endif /* 0 */
+
 #define cpu_to_be16(x)  (x)
 #define cpu_to_be32(x)  (x)
 
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/checksum.h linux/include/asm-ppc/checksum.h
--- v2.1.50/linux/include/asm-ppc/checksum.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/checksum.h	Sat Aug 16 09:51:09 1997
@@ -3,22 +3,6 @@
 
 
 /*
- *	This is a version of ip_compute_csum() optimized for IP headers,
- *	which always checksum on 4 octet boundaries.
- */
-extern unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl);
-
-/*
- * computes the checksum of the TCP/UDP pseudo-header
- * returns a 16-bit checksum, already complemented
- */
-extern unsigned short int csum_tcpudp_magic(unsigned long saddr,
-					   unsigned long daddr,
-					   unsigned short len,
-					   unsigned short proto,
-					   unsigned int sum);
-
-/*
  * computes the checksum of a memory block at buff, length len,
  * and adds in "sum" (32-bit)
  *
@@ -30,43 +14,76 @@
  *
  * it's best to have buff aligned on a 32-bit boundary
  */
-extern unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
+extern unsigned int csum_partial(const unsigned char * buff, int len,
+				 unsigned int sum);
 
 /*
- * the same as csum_partial, but copies from src while it
- * checksums
+ * Computes the checksum of a memory block at src, length len,
+ * and adds in "sum" (32-bit), while copying the block to dst.
+ * If an access exception occurs on src or dst, it stores -EFAULT
+ * to *src_err or *dst_err respectively (if that pointer is not
+ * NULL), and, for an error on src, zeroes the rest of dst.
  *
- * here even more important to align src and dst on a 32-bit (or even
- * better 64-bit) boundary
+ * Like csum_partial, this must be called with even lengths,
+ * except for the last fragment.
  */
-unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum);
+extern unsigned int csum_partial_copy_generic(const char *src, char *dst,
+					      int len, unsigned int sum,
+					      int *src_err, int *dst_err);
+
+#define csum_partial_copy_from_user(src, dst, len, sum, errp)	\
+	csum_partial_copy_generic((src), (dst), (len), (sum), (errp), 0)
 
 /*
- * the same as csum_partial, but copies from user space (but on the alpha
- * we have just one address space, so this is identical to the above)
+ * Old versions which ignore errors.
  */
-#define csum_partial_copy_fromuser csum_partial_copy
+#define csum_partial_copy(src, dst, len, sum)	\
+	csum_partial_copy_generic((src), (dst), (len), (sum), 0, 0)
+#define csum_partial_copy_fromuser(src, dst, len, sum)	\
+	csum_partial_copy_generic((src), (dst), (len), (sum), 0, 0)
+
 
 /*
- * this is a new version of the above that records errors it finds in *errp,
- * but continues and zeros the rest of the buffer.
- *
- * right now - it just calls csum_partial_copy()
- *   -- Cort
+ * turns a 32-bit partial checksum (e.g. from csum_partial) into a
+ * 1's complement 16-bit checksum.
  */
-extern __inline__
-unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
-						int len, int sum, int *err_ptr)
+static inline unsigned int csum_fold(unsigned int sum)
 {
-	int *dst_err_ptr=NULL;
-	return csum_partial_copy( src, dst, len, sum);
+	unsigned int tmp;
+
+	/* swap the two 16-bit halves of sum */
+	__asm__("rlwinm %0,%1,16,0,31" : "=r" (tmp) : "r" (sum));
+	/* if there is a carry from adding the two 16-bit halves,
+	   it will carry from the lower half into the upper half,
+	   giving us the correct sum in the upper half. */
+	sum = ~(sum + tmp) >> 16;
+	return sum;
 }
 
 /*
  * this routine is used for miscellaneous IP-like checksums, mainly
  * in icmp.c
-A */
+ */
+static inline unsigned short ip_compute_csum(unsigned char * buff, int len)
+{
+	return csum_fold(csum_partial(buff, len, 0));
+}
+
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.  ihl is the number
+ * of 32-bit words and is always >= 5.
+ */
+extern unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl);
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+extern unsigned short csum_tcpudp_magic(unsigned long saddr,
+					unsigned long daddr,
+					unsigned short len,
+					unsigned short proto,
+					unsigned int sum);
 
-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.50/linux/include/asm-ppc/cuda.h linux/include/asm-ppc/cuda.h
--- v2.1.50/linux/include/asm-ppc/cuda.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/cuda.h	Sat Aug 16 09:51:09 1997
@@ -0,0 +1,74 @@
+/*
+ * Definitions for talking to the CUDA.  The CUDA is a microcontroller
+ * which controls the ADB, system power, RTC, and various other things.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+/* First byte sent to or received from CUDA */
+#define ADB_PACKET	0
+#define CUDA_PACKET	1
+#define ERROR_PACKET	2
+#define TIMER_PACKET	3
+#define POWER_PACKET	4
+#define MACIIC_PACKET	5
+
+/* ADB commands (2nd byte) */
+#define ADB_BUSRESET		0
+#define ADB_FLUSH(id)		(1 + ((id) << 4))
+#define ADB_WRITEREG(id, reg)	(8 + (reg) + ((id) << 4))
+#define ADB_READREG(id, reg)	(0xc + (reg) + ((id) << 4))
+
+/* ADB default device IDs (upper 4 bits of 2nd byte) */
+#define ADB_DONGLE	1	/* "software execution control" devices */
+#define ADB_KEYBOARD	2
+#define ADB_MOUSE	3
+#define ADB_TABLET	4
+#define ADB_MODEM	5
+#define ADB_MISC	7	/* maybe a monitor */
+
+/* CUDA commands (2nd byte) */
+#define CUDA_WARM_START		0
+#define CUDA_AUTOPOLL		1
+#define CUDA_GET_6805_ADDR	2
+#define CUDA_GET_TIME		3
+#define CUDA_GET_PRAM		7
+#define CUDA_SET_6805_ADDR	8
+#define CUDA_SET_TIME		9
+#define CUDA_POWERDOWN		0xa
+#define CUDA_POWERUP_TIME	0xb
+#define CUDA_SET_PRAM		0xc
+#define CUDA_MS_RESET		0xd
+#define CUDA_SEND_DFAC		0xe
+#define CUDA_RESET_SYSTEM	0x11
+#define CUDA_SET_IPL		0x12
+#define CUDA_SET_AUTO_RATE	0x14
+#define CUDA_GET_AUTO_RATE	0x16
+#define CUDA_SET_DEVICE_LIST	0x19
+#define CUDA_GET_DEVICE_LIST	0x1a
+#define CUDA_GET_SET_IIC	0x22
+
+#ifdef __KERNEL__
+
+struct cuda_request {
+    unsigned char data[16];
+    int nbytes;
+    unsigned char reply[16];
+    int reply_len;
+    unsigned char reply_expected;
+    unsigned char sent;
+    unsigned char got_reply;
+    void (*done)(struct cuda_request *);
+    void *arg;
+    struct cuda_request *next;
+};
+
+void via_cuda_init(void);
+int cuda_request(struct cuda_request *req,
+		 void (*done)(struct cuda_request *), int nbytes, ...);
+int cuda_send_request(struct cuda_request *req);
+void cuda_poll(void);
+int adb_register(int default_id,
+		 void (*handler)(unsigned char *, int, struct pt_regs *));
+
+#endif	/* __KERNEL */
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/current.h linux/include/asm-ppc/current.h
--- v2.1.50/linux/include/asm-ppc/current.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/current.h	Sat Aug 16 09:51:09 1997
@@ -1,10 +1,9 @@
 #ifndef _PPC_CURRENT_H
 #define _PPC_CURRENT_H
 
-#include <linux/config.h>
-
-extern struct task_struct *current_set[1];
-
-register struct task_struct *current asm("r2");
+/*
+ * We keep `current' in r2 for speed.
+ */
+register struct task_struct *current asm ("r2");
 
 #endif /* !(_PPC_CURRENT_H) */
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/dbdma.h linux/include/asm-ppc/dbdma.h
--- v2.1.50/linux/include/asm-ppc/dbdma.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/dbdma.h	Sat Aug 16 09:51:09 1997
@@ -0,0 +1,92 @@
+/*
+ * Definitions for using the Apple Descriptor-Based DMA controller
+ * in Power Macintosh computers.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+#ifndef _ASM_DBDMA_H_
+#define _ASM_DBDMA_H_
+/*
+ * DBDMA control/status registers.  All little-endian.
+ */
+struct dbdma_regs {
+    unsigned int control;	/* lets you change bits in status */
+    unsigned int status;	/* DMA and device status bits (see below) */
+    unsigned int cmdptr_hi;	/* upper 32 bits of command address */
+    unsigned int cmdptr;	/* (lower 32 bits of) command address (phys) */
+    unsigned int intr_sel;	/* select interrupt condition bit */
+    unsigned int br_sel;	/* select branch condition bit */
+    unsigned int wait_sel;	/* select wait condition bit */
+    unsigned int xfer_mode;
+    unsigned int data2ptr_hi;
+    unsigned int data2ptr;
+    unsigned int res1;
+    unsigned int address_hi;
+    unsigned int br_addr_hi;
+    unsigned int res2[3];
+};
+
+/* Bits in control and status registers */
+#define RUN	0x8000
+#define PAUSE	0x4000
+#define FLUSH	0x2000
+#define WAKE	0x1000
+#define DEAD	0x0800
+#define ACTIVE	0x0400
+#define BT	0x0100
+#define DEVSTAT	0x00ff
+
+/*
+ * DBDMA command structure.  These fields are all little-endian!
+ */
+struct dbdma_cmd {
+    unsigned short req_count;	/* requested byte transfer count */
+    unsigned short command;	/* command word (has bit-fields) */
+    unsigned int   phy_addr;	/* physical data address */
+    unsigned int   cmd_dep;	/* command-dependent field */
+    unsigned short res_count;	/* residual count after completion */
+    unsigned short xfer_status;	/* transfer status */
+};
+
+/* DBDMA command values in command field */
+#define OUTPUT_MORE	0	/* transfer memory data to stream */
+#define OUTPUT_LAST	0x1000	/* ditto followed by end marker */
+#define INPUT_MORE	0x2000	/* transfer stream data to memory */
+#define INPUT_LAST	0x3000	/* ditto, expect end marker */
+#define STORE_WORD	0x4000	/* write word (4 bytes) to device reg */
+#define LOAD_WORD	0x5000	/* read word (4 bytes) from device reg */
+#define DBDMA_NOP	0x6000	/* do nothing */
+#define DBDMA_STOP	0x7000	/* suspend processing */
+
+/* Key values in command field */
+#define KEY_STREAM0	0	/* usual data stream */
+#define KEY_STREAM1	0x100	/* control/status stream */
+#define KEY_STREAM2	0x200	/* device-dependent stream */
+#define KEY_STREAM3	0x300	/* device-dependent stream */
+#define KEY_REGS	0x500	/* device register space */
+#define KEY_SYSTEM	0x600	/* system memory-mapped space */
+#define KEY_DEVICE	0x700	/* device memory-mapped space */
+
+/* Interrupt control values in command field */
+#define INTR_NEVER	0	/* don't interrupt */
+#define INTR_IFSET	0x10	/* intr if condition bit is 1 */
+#define INTR_IFCLR	0x20	/* intr if condition bit is 0 */
+#define INTR_ALWAYS	0x30	/* always interrupt */
+
+/* Branch control values in command field */
+#define BR_NEVER	0	/* don't branch */
+#define BR_IFSET	0x4	/* branch if condition bit is 1 */
+#define BR_IFCLR	0x8	/* branch if condition bit is 0 */
+#define BR_ALWAYS	0xc	/* always branch */
+
+/* Wait control values in command field */
+#define WAIT_NEVER	0	/* don't wait */
+#define WAIT_IFSET	1	/* wait if condition bit is 1 */
+#define WAIT_IFCLR	2	/* wait if condition bit is 0 */
+#define WAIT_ALWAYS	3	/* always wait */
+
+/* Align an address for a DBDMA command structure */
+#define DBDMA_ALIGN(x)	(((unsigned)(x) + sizeof(struct dbdma_cmd) - 1) \
+			 & -sizeof(struct dbdma_cmd))
+#endif /* _ASM_DBDMA_H_ */
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/dma.h linux/include/asm-ppc/dma.h
--- v2.1.50/linux/include/asm-ppc/dma.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/dma.h	Sat Aug 16 09:51:09 1997
@@ -23,6 +23,12 @@
 #ifndef _ASM_DMA_H
 #define _ASM_DMA_H
 
+#define MAX_DMA_CHANNELS	8
+
+/* The maximum address that we can perform a DMA transfer to on this platform */
+/* Doesn't really apply... */
+#define MAX_DMA_ADDRESS      0xFFFFFFFF
+
 #ifdef CONFIG_PREP
 #include <asm/io.h>		/* need byte IO */
 
@@ -83,11 +89,8 @@
  *
  */
 
-#define MAX_DMA_CHANNELS	8
-
-/* The maximum address that we can perform a DMA transfer to on this platform */
-/* Doesn't really apply... */
-#define MAX_DMA_ADDRESS      0xFFFFFFFF
+#define POWERSTACK_SND_DMA 6
+#define POWERSTACK_SND_DMA2 7
 
 /* 8237 DMA controllers */
 #define IO_DMA1_BASE	0x00	/* 8 bit slave DMA, channels 0..3 */
@@ -150,6 +153,9 @@
 #define DMA_HI_PAGE_6              0x489
 #define DMA_HI_PAGE_7              0x48A
 
+#define DMA1_EXT_REG               0x40B
+#define DMA2_EXT_REG               0x4D6
+
 #define DMA_MODE_READ	0x44	/* I/O to memory, no autoinit, increment, single mode */
 #define DMA_MODE_WRITE	0x48	/* memory to I/O, no autoinit, increment, single mode */
 #define DMA_MODE_CASCADE 0xC0   /* pass thru DREQ->HRQ, DACK<-HLDA only */
@@ -214,9 +220,11 @@
 	switch(dmanr) {
 		case 0:
 			dma_outb(pagenr, DMA_LO_PAGE_0);
+                        dma_outb(pagenr>>8, DMA_HI_PAGE_0);
 			break;
 		case 1:
 			dma_outb(pagenr, DMA_LO_PAGE_1);
+                        dma_outb(pagenr>>8, DMA_HI_PAGE_1);
 			break;
 		case 2:
 			dma_outb(pagenr, DMA_LO_PAGE_2);
@@ -225,15 +233,24 @@
 		case 3:
 			dma_outb(pagenr, DMA_LO_PAGE_3);
 			break;
-		case 5:
+	        case 5:
 			dma_outb(pagenr & 0xfe, DMA_LO_PAGE_5);
+                        dma_outb(pagenr>>8, DMA_HI_PAGE_5);
 			break;
 		case 6:
-			dma_outb(pagenr & 0xfe, DMA_LO_PAGE_6);
+		        if (POWERSTACK_SND_DMA == 6 || POWERSTACK_SND_DMA2 == 6)
+				dma_outb(pagenr, DMA_LO_PAGE_6);
+			else
+				dma_outb(pagenr & 0xfe, DMA_LO_PAGE_6);
+			dma_outb(pagenr>>8, DMA_HI_PAGE_6);
 			break;
 		case 7:
-			dma_outb(pagenr & 0xfe, DMA_LO_PAGE_7);
-			break;
+			if (POWERSTACK_SND_DMA == 7 || POWERSTACK_SND_DMA2 == 7)
+				dma_outb(pagenr, DMA_LO_PAGE_7);
+			else
+				dma_outb(pagenr & 0xfe, DMA_LO_PAGE_7);
+			dma_outb(pagenr>>8, DMA_HI_PAGE_7);
+		  break;
 	}
 }
 
@@ -247,8 +264,14 @@
 	    dma_outb( phys & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
             dma_outb( (phys>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
 	}  else  {
+	  if (dmanr == POWERSTACK_SND_DMA || dmanr == POWERSTACK_SND_DMA2) {
+	    dma_outb( phys  & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
+	    dma_outb( (phys>>8)  & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
+	    dma_outb( (dmanr&3), DMA2_EXT_REG);
+	  } else {
 	    dma_outb( (phys>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
 	    dma_outb( (phys>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
+	  }
 	}
 	set_dma_page(dmanr, phys>>16);
 }
@@ -269,8 +292,13 @@
 	    dma_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
 	    dma_outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
         } else {
+	  if (dmanr == POWERSTACK_SND_DMA || dmanr == POWERSTACK_SND_DMA2) {
+	    dma_outb( count & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
+	    dma_outb( (count>>8) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
+	  } else {
 	    dma_outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
 	    dma_outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
+	  }
         }
 }
 
@@ -297,10 +325,14 @@
 	return (dmanr<=3)? count : (count<<1);
 }
 
+#else /* CONFIG_PREP */
 
-/* These are in kernel/dma.c: */
-extern void free_dma(unsigned int dmanr);	/* release it again */
+#define DMA_MODE_READ	1
+#define DMA_MODE_WRITE	2
 
 #endif /* CONFIG_PREP */
+
+/* These are in kernel/dma.c: */
+extern void free_dma(unsigned int dmanr);	/* release it again */
 
 #endif /* _ASM_DMA_H */
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/elf.h linux/include/asm-ppc/elf.h
--- v2.1.50/linux/include/asm-ppc/elf.h	Wed Dec 18 00:54:09 1996
+++ linux/include/asm-ppc/elf.h	Sat Aug 16 09:51:09 1997
@@ -6,8 +6,8 @@
  */
 #include <asm/ptrace.h>
 
-#define ELF_NGREG	32
-#define ELF_NFPREG	32
+#define ELF_NGREG	48	/* includes nip, msr, lr, etc. */
+#define ELF_NFPREG	33	/* includes fpscr */
 
 /*
  * This is used to ensure we don't load something for the wrong architecture.
@@ -29,5 +29,10 @@
 
 typedef double elf_fpreg_t;
 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+#define ELF_CORE_COPY_REGS(gregs, regs) \
+	memcpy(gregs, regs, \
+	       sizeof(struct pt_regs) < sizeof(elf_gregset_t)? \
+	       sizeof(struct pt_regs): sizeof(elf_gregset_t));
 
 #endif
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/ide.h linux/include/asm-ppc/ide.h
--- v2.1.50/linux/include/asm-ppc/ide.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/ide.h	Sat Aug 16 09:51:09 1997
@@ -107,7 +107,7 @@
 	return index;
 }
 
-extern void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
+void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
 
 typedef union {
 	unsigned all			: 8;	/* all of the bits together */
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/io.h linux/include/asm-ppc/io.h
--- v2.1.50/linux/include/asm-ppc/io.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/io.h	Sat Aug 16 09:51:09 1997
@@ -5,7 +5,6 @@
 #include <asm/page.h>
 #include <asm/byteorder.h>
 
-#ifdef CONFIG_PREP
 /* from the Carolina Technical Spec -- Cort */
 #define IBM_ACORN 0x82A
 #define SIO_CONFIG_RA	0x398
@@ -17,68 +16,49 @@
 #define IBM_L2_INVALIDATE 0x814
 #define IBM_SYS_CTL       0x81c
 
+extern unsigned long io_base;
 #define SLOW_DOWN_IO
 
-#ifndef PCI_DRAM_OFFSET
-#define PCI_DRAM_OFFSET  0x80000000
-#endif
+#define _IO_BASE io_base
+#undef PCI_DRAM_OFFSET
+#define PCI_DRAM_OFFSET  _IO_BASE
 
 #define readb(addr) (*(volatile unsigned char *) (addr))
-#define readw(addr) (*(volatile unsigned short *) (addr))
-#define readl(addr) (*(volatile unsigned int *) (addr))
+#define readw(addr) ld_le16((volatile unsigned short *)(addr))
+#define readl(addr) ld_le32(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))
+#define writew(b,addr) st_le16((volatile unsigned short *)(addr),(b))
+#define writel(b,addr) st_le32((addr),(b))
 
-void outsl(int port, long *ptr, int len);
-
-__inline__ unsigned char outb(unsigned char val, int port);
-__inline__ unsigned short outw(unsigned short val, int port);
-__inline__ unsigned long outl(unsigned long val, int port);
-__inline__ unsigned char inb(int port);
-__inline__ unsigned short inw(int port);
-__inline__ unsigned long inl(int port);
-
-#define inb_p inb
-#define inw_p inw
-#define inl_p inl
-#define outb_p outb
-#define outw_p outw
-#define outl_p outl
-
-#endif /* CONFIG_PREP */
-
-#ifdef CONFIG_PMAC
-/*
- * Read and write the non-volatile RAM.
- */
-extern int nvram_readb(int addr);
-extern void nvram_writeb(int addr, int val);
-
-#ifndef PCI_DRAM_OFFSET
-#define PCI_DRAM_OFFSET  0
-#endif
-
-#define inb(port)		in_8((unsigned char *)(port))
-#define outb(val, port)		out_8((unsigned char *)(port), (val))
-#define inw(port)		in_le16((unsigned short *)(port))
-#define outw(val, port)		out_le16((unsigned short *)(port), (val))
-#define inl(port)		in_le32((unsigned long *)(port))
-#define outl(val, port)		out_le32((unsigned long *)(port), (val))
-
-#define inb_p(port)		in_8((unsigned char *)(port))
-#define outb_p(val, port)	out_8((unsigned char *)(port), (val))
-#define inw_p(port)		in_le16((unsigned short *)(port))
-#define outw_p(val, port)	out_le16((unsigned short *)(port), (val))
-#define inl_p(port)		in_le32(((unsigned long *)port))
-#define outl_p(val, port)	out_le32((unsigned long *)(port), (val))
-
-#define insw(port, buf, ns)	_insw((unsigned short *)(port), (buf), (ns))
-#define outsw(port, buf, ns)	_outsw((unsigned short *)(port), (buf), (ns))
-#define insl(port, buf, nl)	_insl((unsigned long *)(port), (buf), (nl))
-#define outsl(port, buf, nl)	_outsl((unsigned long *)(port), (buf), (nl))
-#endif /* CONFIG_PMAC */
+#define insb(port, buf, ns)	_insb((unsigned char *)((port)+_IO_BASE), (buf), (ns))
+#define outsb(port, buf, ns)	_outsb((unsigned char *)((port)+_IO_BASE), (buf), (ns))
+#define insw(port, buf, ns)	_insw((unsigned short *)((port)+_IO_BASE), (buf), (ns))
+#define outsw(port, buf, ns)	_outsw((unsigned short *)((port)+_IO_BASE), (buf), (ns))
+#define insl(port, buf, nl)	_insl((unsigned long *)((port)+_IO_BASE), (buf), (nl))
+#define outsl(port, buf, nl)	_outsl((unsigned long *)((port)+_IO_BASE), (buf), (nl))
+
+#define inb(port)		in_8((unsigned char *)((port)+_IO_BASE))
+#define outb(val, port)		out_8((unsigned char *)((port)+_IO_BASE), (val))
+#define inw(port)		in_le16((unsigned short *)((port)+_IO_BASE))
+#define outw(val, port)		out_le16((unsigned short *)((port)+_IO_BASE), (val))
+#define inl(port)		in_le32((unsigned *)((port)+_IO_BASE))
+#define outl(val, port)		out_le32((unsigned *)((port)+_IO_BASE), (val))
+
+#define inb_p(port)		in_8((unsigned char *)((port)+_IO_BASE))
+#define outb_p(val, port)	out_8((unsigned char *)((port)+_IO_BASE), (val))
+#define inw_p(port)		in_le16((unsigned short *)((port)+_IO_BASE))
+#define outw_p(val, port)	out_le16((unsigned short *)((port)+_IO_BASE), (val))
+#define inl_p(port)		in_le32(((unsigned *)port))
+#define outl_p(val, port)	out_le32((unsigned *)((port)+_IO_BASE), (val))
+
+extern void _insb(volatile unsigned char *port, void *buf, int ns);
+extern void _outsb(volatile unsigned char *port, const void *buf, int ns);
+extern void _insw(volatile unsigned short *port, void *buf, int ns);
+extern void _outsw(volatile unsigned short *port, const void *buf, int ns);
+extern void _insl(volatile unsigned long *port, void *buf, int nl);
+extern void _outsl(volatile unsigned long *port, const void *buf, int nl);
 
+#ifdef __KERNEL__
 /*
  * The PCI bus is inherently Little-Endian.  The PowerPC is being
  * run Big-Endian.  Thus all values which cross the [PCI] barrier
@@ -88,14 +68,16 @@
  */
 extern inline unsigned long virt_to_bus(volatile void * address)
 {
-        if (address == (void *)0) return 0;
-        return ((unsigned long)((long)address - KERNELBASE + PCI_DRAM_OFFSET));
+        if (address == (void *)0)
+		return 0;
+        return (unsigned long)address - KERNELBASE + PCI_DRAM_OFFSET;
 }
 
 extern inline void * bus_to_virt(unsigned long address)
 {
-        if (address == 0) return 0;
-        return ((void *)(address - PCI_DRAM_OFFSET + KERNELBASE));
+        if (address == 0)
+		return 0;
+        return (void *)(address - PCI_DRAM_OFFSET + KERNELBASE);
 }
 
 /*
@@ -105,29 +87,20 @@
 extern void *ioremap(unsigned long address, unsigned long size);
 
 /*
- * Change virtual addresses to physical addresses and vv.
- * These are trivial on the 1:1 Linux/i386 mapping (but if we ever
- * make the kernel segment mapped at 0, we need to do translation
- * on the i386 as well)
+ * Change virtual addresses to physical addresses and vv, for
+ * addresses in the area where the kernel has the RAM mapped.
  */
 extern inline unsigned long virt_to_phys(volatile void * address)
 {
-	return (unsigned long) address;
+	return (unsigned long) address - KERNELBASE;
 }
 
 extern inline void * phys_to_virt(unsigned long address)
 {
-	return (void *) address;
+	return (void *) (address + KERNELBASE);
 }
 
-#define _IO_BASE ((unsigned long)0x80000000)
-
-/*
- * These are much more useful le/be io functions from Paul
- * than leXX_to_cpu() style functions since the ppc has
- * load/store byte reverse instructions
- *  -- Cort
- */
+#endif /* __KERNEL__ */
 
 /*
  * Enforce In-order Execution of I/O:
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/ioctls.h linux/include/asm-ppc/ioctls.h
--- v2.1.50/linux/include/asm-ppc/ioctls.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/ioctls.h	Sat Aug 16 09:51:09 1997
@@ -83,8 +83,8 @@
 #define TIOCGETD	0x5424
 #define TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
 #define TIOCTTYGSTRUCT	0x5426  /* For debugging only */
-#define TIOCSBRK       0x5427  /* BSD compatibility */
-#define TIOCCBRK       0x5428  /* BSD compatibility */
+#define TIOCSBRK	0x5427  /* BSD compatibility */
+#define TIOCCBRK	0x5428  /* BSD compatibility */
 
 #define TIOCSERCONFIG	0x5453
 #define TIOCSERGWILD	0x5454
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/ipc.h linux/include/asm-ppc/ipc.h
--- v2.1.50/linux/include/asm-ppc/ipc.h	Wed Dec 18 00:54:09 1996
+++ linux/include/asm-ppc/ipc.h	Sat Aug 16 09:51:09 1997
@@ -1,10 +1,10 @@
-#ifndef __i386_IPC_H__
-#define __i386_IPC_H__
+#ifndef __PPC_IPC_H__
+#define __PPC_IPC_H__
 
 /* 
- * These are used to wrap system calls on x86.
+ * These are used to wrap system calls on PowerPC.
  *
- * See arch/i386/kernel/sys_i386.c for ugly details..
+ * See arch/ppc/kernel/syscalls.c for ugly details..
  */
 struct ipc_kludge {
 	struct msgbuf *msgp;
@@ -25,4 +25,4 @@
 
 #define IPCCALL(version,op)	((version)<<16 | (op))
 
-#endif
+#endif /* __PPC_IPC_H__ */
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/irq.h linux/include/asm-ppc/irq.h
--- v2.1.50/linux/include/asm-ppc/irq.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/irq.h	Sat Aug 16 09:51:09 1997
@@ -3,11 +3,7 @@
 
 #include <linux/config.h>
 
-#ifdef CONFIG_PMAC
-#define NR_IRQS	32
-#else
-#define NR_IRQS	16
-#endif
+#define NR_IRQS 32
 
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/linux_logo.h linux/include/asm-ppc/linux_logo.h
--- v2.1.50/linux/include/asm-ppc/linux_logo.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/linux_logo.h	Sat Aug 16 09:51:09 1997
@@ -0,0 +1,914 @@
+/*
+ * include/asm-ppc/linux_logo.h: A linux logo to be displayed on boot
+ * (pinched from the sparc port).
+ *
+ * Copyright (C) 1996 Larry Ewing (lewing@isc.tamu.edu)
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * You can put anything here, but:
+ * LINUX_LOGO_COLORS has to be less than 224
+ * values have to start from 0x20
+ * (i.e. linux_logo_{red,green,blue}[0] is color 0x20)
+ */
+ 
+#include <linux/init.h>
+
+#define LINUX_LOGO_HEIGHT	80
+#define LINUX_LOGO_WIDTH	80
+#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,
+};
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/mmu.h linux/include/asm-ppc/mmu.h
--- v2.1.50/linux/include/asm-ppc/mmu.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/mmu.h	Sat Aug 16 09:51:09 1997
@@ -144,7 +144,7 @@
       pte	**pmap;		/* Two-level page-map structure */
    } MMU_context;
 
-/* Used to set up SDR register */
+/* Used to set up SDR1 register */
 #define HASH_TABLE_SIZE_64K	0x00010000
 #define HASH_TABLE_SIZE_128K	0x00020000
 #define HASH_TABLE_SIZE_256K	0x00040000
@@ -159,5 +159,13 @@
 #define HASH_TABLE_MASK_1M	0x00F   
 #define HASH_TABLE_MASK_2M	0x01F   
 #define HASH_TABLE_MASK_4M	0x03F   
+
+/* invalidate a TLB entry */
+extern inline void _tlbie(unsigned long va)
+{
+	asm volatile ("tlbie %0" : : "r"(va));
+}
+
+extern void _tlbia(void);		/* invalidate all TLB entries */
 
 #endif
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/mmu_context.h linux/include/asm-ppc/mmu_context.h
--- v2.1.50/linux/include/asm-ppc/mmu_context.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/mmu_context.h	Sat Aug 16 09:51:09 1997
@@ -29,7 +29,6 @@
 do { 								\
 	struct mm_struct *mm = (tsk)->mm;			\
 	if (mm->context == NO_CONTEXT) {			\
-	        int i; \
 		if (next_mmu_context == LAST_CONTEXT)		\
 			mmu_context_overflow();			\
 		mm->context = MUNGE_CONTEXT(++next_mmu_context);\
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/namei.h linux/include/asm-ppc/namei.h
--- v2.1.50/linux/include/asm-ppc/namei.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/namei.h	Sat Aug 16 09:51:09 1997
@@ -1,11 +1,12 @@
-/* $Id: namei.h,v 1.1 1997/07/25 09:28:40 cort Exp $
- * linux/include/asm-i386/namei.h
+/* $Id: namei.h,v 1.2 1997/07/31 07:10:55 paulus Exp $
+ * linux/include/asm-ppc/namei.h
+ * Adapted from linux/include/asm-alpha/namei.h
  *
  * Included from linux/fs/namei.c
  */
 
-#ifndef __I386_NAMEI_H
-#define __I386_NAMEI_H
+#ifndef __PPC_NAMEI_H
+#define __PPC_NAMEI_H
 
 /* These dummy routines maybe changed to something useful
  * for /usr/gnemul/ emulation stuff.
@@ -18,4 +19,4 @@
 #define translate_open_namei(pathname, flag, mode, res_inode, base) \
 	do { } while (0)
 
-#endif /* __I386_NAMEI_H */
+#endif /* __PPC_NAMEI_H */
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/nvram.h linux/include/asm-ppc/nvram.h
--- v2.1.50/linux/include/asm-ppc/nvram.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/nvram.h	Sat Aug 16 09:51:09 1997
@@ -12,15 +12,15 @@
 
 /* RTC Offsets */
 
-#define RTC_SECONDS		0x1FF9
-#define RTC_MINUTES		0x1FFA
-#define RTC_HOURS		0x1FFB
-#define RTC_DAY_OF_WEEK		0x1FFC
-#define RTC_DAY_OF_MONTH	0x1FFD
-#define RTC_MONTH		0x1FFE
-#define RTC_YEAR		0x1FFF
-#define RTC_CONTROLA            0x1FF8
-#define RTC_CONTROLB            0x1FF9
+#define MOTO_RTC_SECONDS		0x1FF9
+#define MOTO_RTC_MINUTES		0x1FFA
+#define MOTO_RTC_HOURS		0x1FFB
+#define MOTO_RTC_DAY_OF_WEEK		0x1FFC
+#define MOTO_RTC_DAY_OF_MONTH	0x1FFD
+#define MOTO_RTC_MONTH		0x1FFE
+#define MOTO_RTC_YEAR		0x1FFF
+#define MOTO_RTC_CONTROLA            0x1FF8
+#define MOTO_RTC_CONTROLB            0x1FF9
 
 #ifndef BCD_TO_BIN
 #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/page.h linux/include/asm-ppc/page.h
--- v2.1.50/linux/include/asm-ppc/page.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/page.h	Sat Aug 16 09:51:09 1997
@@ -81,14 +81,14 @@
 
 #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 */
+/* map phys->virtual and virtual->phys for RAM pages */
 #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)
+#define MAP_NR(addr)		(__pa(addr) >> PAGE_SHIFT)
 #define MAP_PAGE_RESERVED	(1<<15)
 
-extern __inline__ unsigned long get_prezerod_page(void);
+extern unsigned long get_prezerod_page(void);
 
 #endif /* __KERNEL__ */
 #endif /* __ASSEMBLY__ */
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/pci-bridge.h linux/include/asm-ppc/pci-bridge.h
--- v2.1.50/linux/include/asm-ppc/pci-bridge.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/pci-bridge.h	Sat Aug 16 09:51:09 1997
@@ -0,0 +1,20 @@
+#ifndef _ASM_PCI_BRIDGE_H
+#define _ASM_PCI_BRIDGE_H
+
+unsigned long pmac_find_bridges(unsigned long, unsigned long);
+
+/*
+ * pci_io_base returns the memory address at which you can access
+ * the I/O space for PCI bus number `bus' (or NULL on error).
+ */
+void *pci_io_base(unsigned int bus);
+
+/*
+ * pci_device_loc returns the bus number and device/function number
+ * for a device on a PCI bus, given its device_node struct.
+ * It returns 0 if OK, -1 on error.
+ */
+int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
+		   unsigned char *devfn_ptr);
+
+#endif
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/pgtable.h linux/include/asm-ppc/pgtable.h
--- v2.1.50/linux/include/asm-ppc/pgtable.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/pgtable.h	Sat Aug 16 09:51:09 1997
@@ -1,22 +1,25 @@
 #ifndef _PPC_PGTABLE_H
 #define _PPC_PGTABLE_H
 
-#include <linux/config.h>
-#include <asm/page.h>
-#include <asm/mmu.h>
+#include <linux/mm.h>
 
 extern void flush_tlb_all(void);
 extern void flush_tlb_mm(struct mm_struct *mm);
 extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr);
 extern void flush_tlb_range(struct mm_struct *mm, unsigned long start,
 			    unsigned long end);
-extern void flush_tlb(void);
 
-/* Caches aren't brain-dead on the ppc. */
-#define flush_cache_all()			
-#define flush_cache_mm(mm)			
-#define flush_cache_range(mm, start, end)	
-#define flush_cache_page(vma, vmaddr)		
+/*
+ * No cache flushing is required when address mappings are
+ * changed, because the caches on PowerPCs are physically
+ * addressed.
+ */
+#define flush_cache_all()		do { } while (0)
+#define flush_cache_mm(mm)		do { } while (0)
+#define flush_cache_range(mm, a, b)	do { } while (0)
+#define flush_cache_page(vma, p)	do { } while (0)
+extern void flush_icache_range(unsigned long, unsigned long);
+
 /*
  * For the page specified, write modified lines in the data cache
  * out to memory, and invalidate lines in the instruction cache.
@@ -25,6 +28,20 @@
 
 extern unsigned long va_to_phys(unsigned long address);
 
+/*
+ * The PowerPC MMU uses a hash table containing PTEs, together with
+ * a set of 16 segment registers (on 32-bit implementations), to define
+ * the virtual to physical address mapping.
+ *
+ * We use the hash table as an extended TLB, i.e. a cache of currently
+ * active mappings.  We maintain a two-level page table tree, much like
+ * that used by the i386, for the sake of the Linux memory management code.
+ * Low-level assembler code in head.S (procedure hash_page) is responsible
+ * for extracting ptes from the tree and putting them into the hash table
+ * when necessary, and updating the accessed and modified bits in the
+ * page table tree.
+ */
+
 /* PMD_SHIFT determines the size of the area mapped by the second-level page tables */
 #define PMD_SHIFT	22
 #define PMD_SIZE	(1UL << PMD_SHIFT)
@@ -133,9 +150,7 @@
 
 /* to set the page-dir */
 /* tsk is a task_struct and pgdir is a pte_t */
-#define SET_PAGE_DIR(tsk,pgdir) ({ \
-	((tsk)->tss.pg_tables = (unsigned long *)(pgdir)); \
-})
+#define SET_PAGE_DIR(tsk,pgdir) 
 
 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; }
@@ -146,7 +161,7 @@
 extern inline int pmd_present(pmd_t pmd)	{ return (pmd_val(pmd) & PAGE_MASK) != 0; }
 extern inline void pmd_clear(pmd_t * pmdp)	{ pmd_val(*pmdp) = 0; }
 
-     
+
 /*
  * The "pgd_xxx()" functions here are trivial for a folded two-level
  * setup: the pgd is never bad, and a pmd always exists (as it's folded
@@ -370,13 +385,27 @@
  * as entries are faulted into the hash table by the low-level
  * data/instruction access exception handlers.
  */
-#define update_mmu_cache(vma,address,pte) while(0){}
+#define update_mmu_cache(vma, addr, pte)	do { } while (0)
 
+/*
+ * When flushing the tlb entry for a page, we also need to flush the
+ * hash table entry.  flush_hash_page is assembler (for speed) in head.S.
+ */
+extern void flush_hash_segments(unsigned low_vsid, unsigned high_vsid);
+extern void flush_hash_page(unsigned context, unsigned long va);
+
+extern inline void
+flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
+{
+	if (vmaddr < TASK_SIZE)
+		flush_hash_page(vma->vm_mm->context, vmaddr);
+}
 
 #define SWP_TYPE(entry) (((entry) >> 1) & 0x7f)
 #define SWP_OFFSET(entry) ((entry) >> 8)
 #define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << 8))
 
+#define module_map      vmalloc
+#define module_unmap    vfree
 
-
-#endif /* _PPC_PAGE_H */
+#endif /* _PPC_PGTABLE_H */
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/poll.h linux/include/asm-ppc/poll.h
--- v2.1.50/linux/include/asm-ppc/poll.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/poll.h	Sat Aug 16 09:51:09 1997
@@ -1,15 +1,12 @@
-#ifndef __i386_POLL_H
-#define __i386_POLL_H
+#ifndef __PPC_POLL_H
+#define __PPC_POLL_H
 
-/* These are specified by iBCS2 */
 #define POLLIN		0x0001
 #define POLLPRI		0x0002
 #define POLLOUT		0x0004
 #define POLLERR		0x0008
 #define POLLHUP		0x0010
 #define POLLNVAL	0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
 #define POLLRDNORM	0x0040
 #define POLLRDBAND	0x0080
 #define POLLWRNORM	0x0100
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
--- v2.1.50/linux/include/asm-ppc/processor.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/processor.h	Sat Aug 16 09:51:09 1997
@@ -1,8 +1,7 @@
 #ifndef __ASM_PPC_PROCESSOR_H
 #define __ASM_PPC_PROCESSOR_H
 
-#include <linux/config.h>
-
+#include <asm/ptrace.h>
 
 /* Bit encodings for Machine State Register (MSR) */
 #define MSR_POW		(1<<18)		/* Enable Power Management */
@@ -22,11 +21,12 @@
 #define MSR_RI		(1<<1)		/* Recoverable Exception */
 #define MSR_LE		(1<<0)		/* Little-Endian enable */
 
-#define MSR_		MSR_FE0|MSR_FE1|MSR_ME
+#define MSR_		MSR_ME|MSR_FE0|MSR_FE1|MSR_RI
 #define MSR_KERNEL      MSR_|MSR_IR|MSR_DR
-#define MSR_USER	MSR_FE0|MSR_FE1|MSR_ME|MSR_PR|MSR_EE|MSR_IR|MSR_DR
+#define MSR_USER	MSR_KERNEL|MSR_PR|MSR_EE
 
-/* Bit encodings for Hardware Implementation Register (HID0) */
+/* Bit encodings for Hardware Implementation Register (HID0)
+   on PowerPC 603, 604, etc. processors (not 601). */
 #define HID0_EMCP	(1<<31)		/* Enable Machine Check pin */
 #define HID0_EBA	(1<<29)		/* Enable Bus Address Parity */
 #define HID0_EBD	(1<<28)		/* Enable Bus Data Parity */
@@ -46,15 +46,19 @@
 #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)
 
+
 #ifndef __ASSEMBLY__
 /*
  * PowerPC machine specifics
  */
-extern inline void start_thread(struct pt_regs *, unsigned long, unsigned long );
+struct task_struct;
+void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp);
+void release_thread(struct task_struct *);
 
 /*
  * Bus types
@@ -70,49 +74,37 @@
 #define wp_works_ok 1
 #define wp_works_ok__is_a_macro /* for versions in ksyms.c */
 
+/*
+ * User space process size: 2GB. This is hardcoded into a few places,
+ * so don't change it unless you know what you are doing.
+ */
 #define TASK_SIZE	(0x80000000UL)
+
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
-#define TASK_UNMAPPED_BASE	(TASK_SIZE / 3)
-struct thread_struct 
-{
+#define TASK_UNMAPPED_BASE     (TASK_SIZE / 8 * 3)
+
+struct thread_struct {
 	unsigned long	ksp;		/* Kernel stack pointer */
-	unsigned long	*pg_tables;	/* MMU information */
-#ifdef CONFIG_PMAC
-	unsigned long	last_pc;	/* PC when last entered system */
-	unsigned long	user_stack;	/* [User] Stack when entered kernel */
-#endif  
-	unsigned long	fpscr_pad;	/* (so we can save fpscr with stfd) */
-	unsigned long   fpscr;		/* fp status reg */
-	double       	fpr[32];	/* Complete floating point set */
-	unsigned long   fp_used;
 	unsigned long	wchan;		/* Event task is sleeping on */
-	struct pt_regs  *regs;		/* Pointer to saved register state */
+	struct pt_regs	*regs;		/* Pointer to saved register state */
 	unsigned long   fs;		/* for get_fs() validation */
 	signed long     last_syscall;
-	unsigned long   pad[2];	/* pad to 16-byte boundry */
+	double		fpr[32];	/* Complete floating point set */
+	unsigned long	fpscr_pad;	/* fpr ... fpscr must be contiguous */
+	unsigned long	fpscr;		/* Floating point status */
 };
 
-/* Points to the thread_struct of the thread (if any) which
-   currently owns the FPU. */
-#define fpu_tss (&(last_task_used_math->tss))
-
-#ifdef CONFIG_PMAC
-#define LAZY_TSS_FPR_INIT 0,0,0,0,{0},
-#endif
-#ifdef CONFIG_PREP
-#define LAZY_TSS_FPR_INIT 0,0,{0},
-#endif
+#define INIT_SP		(sizeof(init_stack) + (unsigned long) &init_stack)
 
 #define INIT_TSS  { \
-	sizeof(init_stack) + (long) &init_stack, /* ksp */ \
-	(long *)swapper_pg_dir, /* pg_tables */ \
-	LAZY_TSS_FPR_INIT \
-	0, /*fp_used*/ 0, /*wchan*/ \
-	sizeof(init_stack) + (long)&init_stack - \
-		sizeof(struct pt_regs), /* regs */ \
-	KERNEL_DS /*fs*/, 0 /*last_syscall*/ \
+	INIT_SP, /* ksp */ \
+	0, /* wchan */ \
+	(struct pt_regs *)INIT_SP - 1, /* regs */ \
+	KERNEL_DS, /*fs*/ \
+	0, /* last_syscall */ \
+	{0}, 0, 0 \
 }
 
 #define INIT_MMAP { &init_mm, KERNELBASE/*0*/, 0xffffffff/*0x40000000*/, \
@@ -124,15 +116,8 @@
 static inline unsigned long thread_saved_pc(struct thread_struct *t)
 {
 	return (t->regs) ? t->regs->nip : 0;
-	/*return (t->last_pc);*/
 }
 
-extern int _machine;
-#define _MACH_Motorola 0
-#define _MACH_IBM      1
-#define _MACH_Be       2
-#define _MACH_Pmac     3
-
 /*
  * NOTE! The task struct and the stack go together
  */
@@ -144,7 +129,15 @@
 int ll_printk(const char *, ...);
 void ll_puts(const char *);
 
+extern int _machine;
 #endif /* ndef ASSEMBLY*/
+
+#define _MACH_Motorola 1 /* motorola prep */
+#define _MACH_IBM      2 /* ibm prep */
+#define _MACH_Pmac     4 /* pmac or pmac clone */
+#define _MACH_chrp     8 /* chrp machine */
+
+#define is_prep ((_machine == _MACH_Motorola)||(_machine == _MACH_IBM))
 
 #define init_task	(init_task_union.task)
 #define init_stack	(init_task_union.stack)
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/prom.h linux/include/asm-ppc/prom.h
--- v2.1.50/linux/include/asm-ppc/prom.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/prom.h	Sat Aug 16 09:51:09 1997
@@ -0,0 +1,65 @@
+/*
+ * Definitions for talking to the Open Firmware PROM on
+ * Power Macintosh computers.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+
+typedef void *phandle;
+typedef void *ihandle;
+
+extern ihandle prom_stdout;
+extern ihandle prom_chosen;
+extern phandle cpu_node;
+extern char prom_display_path[];
+
+struct reg_property {
+	unsigned int address;
+	unsigned int size;
+};
+
+struct translation_property {
+	unsigned int virt;
+	unsigned int size;
+	unsigned int phys;
+	unsigned int flags;
+};
+
+struct property {
+	char	*name;
+	int	length;
+	unsigned char *value;
+	struct property *next;
+};
+
+struct device_node {
+	char	*name;
+	char	*type;
+	phandle	node;
+	int	n_addrs;
+	struct	reg_property *addrs;
+	int	n_intrs;
+	int	*intrs;
+	char	*full_name;
+	struct	property *properties;
+	struct	device_node *parent;
+	struct	device_node *child;
+	struct	device_node *sibling;
+	struct	device_node *next;	/* next device of same type */
+	struct	device_node *allnext;	/* next in list of all nodes */
+};
+
+/* Prototypes */
+void abort(void);
+void prom_exit(void);
+void *call_prom(const char *service, int nargs, int nret, ...);
+void prom_print(const char *msg);
+void prom_init(char *params, int unused, void (*)(void *));
+void set_prom_callback(void);
+unsigned long copy_device_tree(unsigned long, unsigned long);
+struct device_node *find_devices(const char *name);
+struct device_node *find_type_devices(const char *type);
+struct device_node *find_path_device(const char *path);
+unsigned char *get_property(struct device_node *node, const char *name,
+	int *lenp);
+void print_properties(struct device_node *node);
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/ptrace.h linux/include/asm-ppc/ptrace.h
--- v2.1.50/linux/include/asm-ppc/ptrace.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/ptrace.h	Sat Aug 16 09:51:09 1997
@@ -2,63 +2,52 @@
 #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.
+ *
  * this should only contain volatile regs
  * since we can keep non-volatile in the tss
  * should set this up when only volatiles are saved
  * by intr code.
  *
- * I can't find any reference to the above comment (from Gary Thomas)
- * about _underhead/_overhead in the sys V abi for the ppc
- * dated july 25, 1994.
+ * Since this is going on the stack, *CARE MUST BE TAKEN* to insure
+ * that the overall structure is a multiple of 16 bytes in length.
  *
- * the stack must be kept to a size that is a multiple of 16
- * so this includes the stack frame overhead 
- * -- Cort.
- */
-
-/*
- * GCC sometimes accesses words at negative offsets from the stack
- * pointer, although the SysV ABI says it shouldn't.  To cope with
- * this, we leave this much untouched space on the stack on exception
- * entry.
+ * Note that the offsets of the fields in this struct correspond with
+ * the PT_* values below.  This simplifies arch/ppc/kernel/ptrace.c.
  */
-#define STACK_FRAME_OVERHEAD 16
-#define STACK_UNDERHEAD	64
 
 #ifndef __ASSEMBLY__
 struct pt_regs {
 	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;
-#if 0  
-	unsigned long srr1;
-	unsigned long srr0;
-	unsigned long hash1, hash2;
-	unsigned long imiss, dmiss;
-	unsigned long icmp, dcmp;
-#endif  
+	unsigned long nip;
+	unsigned long msr;
 	unsigned long orig_gpr3; /* Used for restarting system calls */
-	unsigned long result;	/* Result of a system call */
+	unsigned long ctr;
+	unsigned long link;
+	unsigned long xer;
+	unsigned long ccr;
+	unsigned long mq;	/* 601 only (not used at present) */
 	unsigned long trap;	/* Reason for being here */
-	unsigned long marker;	/* Should have DEADDEAD */
+	unsigned long dar;	/* Fault registers */
+	unsigned long dsisr;
+	unsigned long result;   /* Result of a system call */
 };
+#endif
+
+#define STACK_FRAME_OVERHEAD	16	/* size of minimum stack frame */
 
+/* Size of stack frame allocated when calling signal handler. */
+#define __SIGNAL_FRAMESIZE	64
 
 #define instruction_pointer(regs) ((regs)->nip)
 #define user_mode(regs) ((regs)->msr & 0x4000)
-#ifdef KERNEL
-extern void show_regs(struct pt_regs *);
-#endif
 
-/* should include and generate these in ppc_defs.h -- Cort */
-/* Offsets used by 'ptrace' system call interface */
-/* Note: these should correspond to gpr[x]        */
+/*
+ * Offsets used by 'ptrace' system call interface.
+ * These can't be changed without breaking binary compatibility
+ * with MkLinux, etc.
+ */
 #define PT_R0	0
 #define PT_R1	1
 #define PT_R2	2
@@ -94,14 +83,18 @@
 
 #define PT_NIP	32
 #define PT_MSR	33
+#ifdef __KERNEL__
 #define PT_ORIG_R3 34
+#endif
 #define PT_CTR	35
 #define PT_LNK	36
 #define PT_XER	37
 #define PT_CCR	38
+#define PT_MQ	39
 
-#define PT_FPR0	48
-#endif /* __ASSEMBLY__ */
+#define PT_FPR0	48	/* each FP reg occupies 2 slots in this space */
+#define PT_FPR31 (PT_FPR0 + 2*31)
+#define PT_FPSCR (PT_FPR0 + 2*32 + 1)
 
-#endif /* _PPC_PTRACE_H */
+#endif
 
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/residual.h linux/include/asm-ppc/residual.h
--- v2.1.50/linux/include/asm-ppc/residual.h	Wed Dec 18 00:54:10 1996
+++ linux/include/asm-ppc/residual.h	Sat Aug 16 09:51:09 1997
@@ -311,5 +311,7 @@
   unsigned char DevicePnPHeap[2*MAX_DEVICES*AVE_PNP_SIZE];
   } RESIDUAL;
 
+
+extern RESIDUAL res;
 #endif  /* ndef _RESIDUAL_ */
 
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/resource.h linux/include/asm-ppc/resource.h
--- v2.1.50/linux/include/asm-ppc/resource.h	Wed Dec 18 00:54:10 1996
+++ linux/include/asm-ppc/resource.h	Sat Aug 16 09:51:09 1997
@@ -7,10 +7,10 @@
 #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_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 RLIMIT_NPROC	6		/* max number of processes */
+#define RLIMIT_NOFILE	7		/* max number of open files */
+#define RLIMIT_MEMLOCK	8		/* max locked-in-memory address space */
+#define RLIMIT_AS	9		/* address space limit(?) */
 
 #define RLIM_NLIMITS	10
 
@@ -24,10 +24,10 @@
     {_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 */	\
+    { NR_OPEN,  NR_OPEN},			/* RLIMIT_NOFILE */	\
     {LONG_MAX, LONG_MAX},			/* RLIMIT_MEMLOCK */	\
+    {LONG_MAX, LONG_MAX},			/* RLIMIT_AS */		\
 }
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/scatterlist.h linux/include/asm-ppc/scatterlist.h
--- v2.1.50/linux/include/asm-ppc/scatterlist.h	Mon Dec 30 03:01:10 1996
+++ linux/include/asm-ppc/scatterlist.h	Sat Aug 16 09:51:09 1997
@@ -1,6 +1,8 @@
 #ifndef _PPC_SCATTERLIST_H
 #define _PPC_SCATTERLIST_H
 
+#include <linux/config.h>
+
 struct scatterlist {
     char *  address;    /* Location data is to be transferred to */
     char * alt_address; /* Location of actual if address is a 
@@ -8,6 +10,18 @@
     unsigned int length;
 };
 
+#ifdef CONFIG_PMAC
+/*
+ * This is used in the scsi code to decide if bounce buffers are needed.
+ * Fortunately the dma controllers on the PowerMac are a bit better
+ * than on PCs...
+ */
+#define ISA_DMA_THRESHOLD (~0UL)
+#endif
+
+#ifdef CONFIG_PREP
+/* PReP systems are like PCs */
 #define ISA_DMA_THRESHOLD (0x00ffffff)
+#endif
 
 #endif /* !(_PPC_SCATTERLIST_H) */
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/semaphore.h linux/include/asm-ppc/semaphore.h
--- v2.1.50/linux/include/asm-ppc/semaphore.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/semaphore.h	Sat Aug 16 09:51:09 1997
@@ -44,13 +44,13 @@
 	__asm__ __volatile__(
 		"1:	lwarx %1,0,%2\n"
 		"	cmpwi 0,%1,0\n"
-		"	addi %1,%1,-1\n"
+		"	addic %1,%1,-1\n"
 		"	ble- 2f\n"
 		"	stwcx. %1,0,%2\n"
 		"	bne- 1b\n"
-		"	mr %0,%1\n"
+		"	li %0,1\n"
 		"2:"
-		: "=r" (ret), "=r" (tmp)
+		: "=r" (ret), "=&r" (tmp)
 		: "r" (&sem->waking), "0" (0)
 		: "cr0", "memory");
 
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/socket.h linux/include/asm-ppc/socket.h
--- v2.1.50/linux/include/asm-ppc/socket.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/socket.h	Sat Aug 16 09:51:09 1997
@@ -34,4 +34,9 @@
 #define SO_PASSCRED	20
 #define SO_PEERCRED	21
 
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION		22
+#define SO_SECURITY_ENCRYPTION_TRANSPORT	23
+#define SO_SECURITY_ENCRYPTION_NETWORK		24
+
 #endif /* _ASM_SOCKET_H */
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/string.h linux/include/asm-ppc/string.h
--- v2.1.50/linux/include/asm-ppc/string.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/string.h	Sat Aug 16 09:51:09 1997
@@ -12,16 +12,7 @@
 #define __HAVE_ARCH_MEMMOVE
 #define __HAVE_ARCH_MEMCMP
 #define __HAVE_ARCH_MEMCHR
-/*#define bzero(addr,size) memset((addr),(int)(0),(size))*/
-extern inline void * memchr(const void * cs,int c,size_t count)
-{
-	unsigned long i = 0;
-	while ( count != i )
-	{
-		if ( (char)c == *(char *)(cs + i) )
-			return (void *)(cs + i);
-		i--;
-	}
-	return NULL;
-}
+
+extern int strcasecmp(const char *, const char *);
+
 #endif
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/system.h linux/include/asm-ppc/system.h
--- v2.1.50/linux/include/asm-ppc/system.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/system.h	Sat Aug 16 09:51:09 1997
@@ -1,40 +1,67 @@
 #ifndef __PPC_SYSTEM_H
 #define __PPC_SYSTEM_H
 
-#include <linux/delay.h>
+#include <linux/kdev_t.h>
+#include <asm/processor.h>
 
 #define mb()  __asm__ __volatile__ ("sync" : : : "memory")
 
 #define __save_flags(flags)	({\
 	__asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory"); })
-/* using Paul's in misc.S now -- Cort */
-extern void __restore_flags(unsigned long flags);
+extern __inline__ void __restore_flags(unsigned long flags)
+{
+        extern unsigned lost_interrupts;
+	extern void do_lost_interrupts(unsigned long);
 
+        if ((flags & MSR_EE) && lost_interrupts != 0) {
+                do_lost_interrupts(flags);
+        } else {
+                __asm__ __volatile__ ("sync; mtmsr %0; isync"
+                              : : "r" (flags) : "memory");
+        }
+}
+
+
+#if 0
 /*
-  #define __sti() _soft_sti(void)
-  #define __cli() _soft_cli(void)
+ * Gcc bug prevents us from using this inline func so for now
+ * it lives in misc.S
  */
+void __inline__ __restore_flags(unsigned long flags)
+{
+	extern unsigned lost_interrupts;
+	__asm__ __volatile__ (
+		"andi.	0,%0,%2 \n\t"
+		"beq	2f \n\t"
+		"cmpi	0,%1,0 \n\t"
+		"bne	do_lost_interrupts \n\t"
+		"2:	sync \n\t"
+		"mtmsr	%0 \n\t"
+		"isync \n\t"
+		: 
+		: "r" (flags), "r"(lost_interrupts), "i" (1<<15)/*MSR_EE*/
+		: "0", "cc");
+}
+#endif
+
 extern void __sti(void);
 extern void __cli(void);
-
-extern void _hard_sti(void);
-extern void _hard_cli(void);
-extern void _soft_sti(void);
-extern void _soft_cli(void);
 extern int _disable_interrupts(void);
 extern void _enable_interrupts(int);
 
+extern void print_backtrace(unsigned long *);
+extern void show_regs(struct pt_regs * regs);
 extern void flush_instruction_cache(void);
 extern void hard_reset_now(void);
 extern void poweroff_now(void);
-extern void find_scsi_boot(void);
+/*extern void note_bootable_part(kdev_t, int);*/
 extern int sd_find_target(void *, int);
 extern int _get_PVR(void);
 extern void via_cuda_init(void);
+extern void pmac_nvram_init(void);
 extern void read_rtc_time(void);
 extern void pmac_find_display(void);
 extern void giveup_fpu(void);
-extern void store_cache_range(unsigned long, unsigned long);
 extern void cvt_fd(float *from, double *to);
 extern void cvt_df(double *from, float *to);
 
diff -u --recursive --new-file v2.1.50/linux/include/asm-ppc/termbits.h linux/include/asm-ppc/termbits.h
--- v2.1.50/linux/include/asm-ppc/termbits.h	Mon Aug  4 16:25:39 1997
+++ linux/include/asm-ppc/termbits.h	Sat Aug 16 09:51:09 1997
@@ -125,6 +125,7 @@
 #define  B57600   00020
 #define  B115200  00021
 #define  B230400  00022
+#define  B460800  00023
 
 #define CSIZE	00001400
 #define   CS5	00000000
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc/pgtable.h linux/include/asm-sparc/pgtable.h
--- v2.1.50/linux/include/asm-sparc/pgtable.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-sparc/pgtable.h	Sat Aug 16 09:51:10 1997
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.62 1997/06/27 14:55:00 jj Exp $ */
+/* $Id: pgtable.h,v 1.63 1997/08/13 04:44:15 paulus Exp $ */
 #ifndef _SPARC_PGTABLE_H
 #define _SPARC_PGTABLE_H
 
@@ -298,6 +298,7 @@
 extern void (*flush_cache_range)(struct mm_struct *, unsigned long start,
 				 unsigned long end);
 extern void (*flush_cache_page)(struct vm_area_struct *, unsigned long address);
+#define flush_icache_range(start, end)		do { } while (0)
 
 extern void (*flush_tlb_all)(void);
 extern void (*flush_tlb_mm)(struct mm_struct *);
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/atomic.h linux/include/asm-sparc64/atomic.h
--- v2.1.50/linux/include/asm-sparc64/atomic.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-sparc64/atomic.h	Sat Aug 16 09:51:10 1997
@@ -1,4 +1,4 @@
-/* $Id: atomic.h,v 1.15 1997/07/03 09:18:09 davem Exp $
+/* $Id: atomic.h,v 1.18 1997/08/07 03:38:31 davem Exp $
  * atomic.h: Thankfully the V9 is at least reasonable for this
  *           stuff.
  *
@@ -23,29 +23,29 @@
 extern __inline__ void atomic_add(int i, atomic_t *v)
 {
 	__asm__ __volatile__("
-1:	lduw		[%1], %%g1
-	add		%%g1, %0, %%g2
-	cas		[%1], %%g1, %%g2
-	sub		%%g1, %%g2, %%g1
-	brnz,pn		%%g1, 1b
+1:	lduw		[%1], %%g5
+	add		%%g5, %0, %%g7
+	cas		[%1], %%g5, %%g7
+	sub		%%g5, %%g7, %%g5
+	brnz,pn		%%g5, 1b
 	 nop"
 	: /* No outputs */
 	: "HIr" (i), "r" (__atomic_fool_gcc(v))
-	: "g1", "g2");
+	: "g5", "g7", "memory");
 }
 
 extern __inline__ void atomic_sub(int i, atomic_t *v)
 {
 	__asm__ __volatile__("
-1:	lduw		[%1], %%g1
-	sub		%%g1, %0, %%g2
-	cas		[%1], %%g1, %%g2
-	sub		%%g1, %%g2, %%g1
-	brnz,pn		%%g1, 1b
+1:	lduw		[%1], %%g5
+	sub		%%g5, %0, %%g7
+	cas		[%1], %%g5, %%g7
+	sub		%%g5, %%g7, %%g5
+	brnz,pn		%%g5, 1b
 	 nop"
 	: /* No outputs */
 	: "HIr" (i), "r" (__atomic_fool_gcc(v))
-	: "g1", "g2");
+	: "g5", "g7", "memory");
 }
 
 /* Same as above, but return the result value. */
@@ -53,15 +53,15 @@
 {
 	unsigned long oldval;
 	__asm__ __volatile__("
-1:	lduw		[%2], %%g1
-	add		%%g1, %1, %%g2
-	cas		[%2], %%g1, %%g2
-	sub		%%g1, %%g2, %%g1
-	brnz,pn		%%g1, 1b
-	 add		%%g2, %1, %0"
+1:	lduw		[%2], %%g5
+	add		%%g5, %1, %%g7
+	cas		[%2], %%g5, %%g7
+	sub		%%g5, %%g7, %%g5
+	brnz,pn		%%g5, 1b
+	 add		%%g7, %1, %0"
 	: "=&r" (oldval)
 	: "HIr" (i), "r" (__atomic_fool_gcc(v))
-	: "g1", "g2");
+	: "g5", "g7", "memory");
 	return (int)oldval;
 }
 
@@ -69,15 +69,15 @@
 {
 	unsigned long oldval;
 	__asm__ __volatile__("
-1:	lduw		[%2], %%g1
-	sub		%%g1, %1, %%g2
-	cas		[%2], %%g1, %%g2
-	sub		%%g1, %%g2, %%g1
-	brnz,pn		%%g1, 1b
-	 sub		%%g2, %1, %0"
+1:	lduw		[%2], %%g5
+	sub		%%g5, %1, %%g7
+	cas		[%2], %%g5, %%g7
+	sub		%%g5, %%g7, %%g5
+	brnz,pn		%%g5, 1b
+	 sub		%%g7, %1, %0"
 	: "=&r" (oldval)
 	: "HIr" (i), "r" (__atomic_fool_gcc(v))
-	: "g1", "g2");
+	: "g5", "g7", "memory");
 	return (int)oldval;
 }
 
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/bitops.h linux/include/asm-sparc64/bitops.h
--- v2.1.50/linux/include/asm-sparc64/bitops.h	Thu Jul 17 10:06:08 1997
+++ linux/include/asm-sparc64/bitops.h	Sat Aug 16 09:51:10 1997
@@ -1,7 +1,7 @@
-/* $Id: bitops.h,v 1.19 1997/07/08 10:17:37 davem Exp $
+/* $Id: bitops.h,v 1.22 1997/08/07 02:54:04 davem Exp $
  * bitops.h: Bit string operations on the V9.
  *
- * Copyright 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #ifndef _SPARC64_BITOPS_H
@@ -21,84 +21,117 @@
 
 extern __inline__ unsigned long test_and_set_bit(unsigned long nr, void *addr)
 {
-	unsigned long oldbit;
-	unsigned long temp0, temp1;
 	unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
+	unsigned long oldbit;
 
 	__asm__ __volatile__("
-	ldx		[%4], %0
-1:
-	andcc		%0, %3, %2
+1:	ldx		[%2], %%g7
+	andcc		%%g7, %1, %0
 	bne,pn		%%xcc, 2f
-	 xor		%0, %3, %1
-	casx 		[%4], %0, %1
-	cmp		%0, %1
-	bne,a,pn	%%xcc, 1b
-	 ldx		[%4], %0
+	 xor		%%g7, %1, %%g5
+	casx 		[%2], %%g7, %%g5
+	cmp		%%g7, %%g5
+	bne,pn		%%xcc, 1b
+	 nop
 2:
-"	: "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+"	: "=&r" (oldbit)
 	: "HIr" (1UL << (nr & 63)), "r" (m)
-	: "cc");
+	: "g5", "g7", "cc", "memory");
 	return oldbit != 0;
 }
 
 extern __inline__ void set_bit(unsigned long nr, void *addr)
 {
-	(void) test_and_set_bit(nr, addr);
+	unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
+
+	__asm__ __volatile__("
+1:	ldx		[%1], %%g7
+	andcc		%%g7, %0, %%g0
+	bne,pn		%%xcc, 2f
+	 xor		%%g7, %0, %%g5
+	casx 		[%1], %%g7, %%g5
+	cmp		%%g7, %%g5
+	bne,pn		%%xcc, 1b
+	 nop
+2:
+"	: /* no outputs */
+	: "HIr" (1UL << (nr & 63)), "r" (m)
+	: "g5", "g7", "cc", "memory");
 }
 
 extern __inline__ unsigned long test_and_clear_bit(unsigned long nr, void *addr)
 {
-	unsigned long oldbit;
-	unsigned long temp0, temp1;
 	unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
+	unsigned long oldbit;
 
 	__asm__ __volatile__("
-	ldx		[%4], %0
-1:
-	andcc		%0, %3, %2
+1:	ldx		[%2], %%g7
+	andcc		%%g7, %1, %0
 	be,pn		%%xcc, 2f
-	 xor		%0, %3, %1
-	casx 		[%4], %0, %1
-	cmp		%0, %1
-	bne,a,pn	%%xcc, 1b
-	 ldx		[%4], %0
+	 xor		%%g7, %1, %%g5
+	casx 		[%2], %%g7, %%g5
+	cmp		%%g7, %%g5
+	bne,pn		%%xcc, 1b
+	 nop
 2:
-"	: "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+"	: "=&r" (oldbit)
 	: "HIr" (1UL << (nr & 63)), "r" (m)
-	: "cc");
+	: "g5", "g7", "cc", "memory");
 	return oldbit != 0;
 }
 
 extern __inline__ void clear_bit(unsigned long nr, void *addr)
 {
-	(void) test_and_clear_bit(nr, addr);
+	unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
+
+	__asm__ __volatile__("
+1:	ldx		[%1], %%g7
+	andcc		%%g7, %0, %%g0
+	be,pn		%%xcc, 2f
+	 xor		%%g7, %0, %%g5
+	casx 		[%1], %%g7, %%g5
+	cmp		%%g7, %%g5
+	bne,pn		%%xcc, 1b
+	 nop
+2:
+"	: /* no outputs */
+	: "HIr" (1UL << (nr & 63)), "r" (m)
+	: "g5", "g7", "cc", "memory");
 }
 
 extern __inline__ unsigned long test_and_change_bit(unsigned long nr, void *addr)
 {
-	unsigned long oldbit;
-	unsigned long temp0, temp1;
 	unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
+	unsigned long oldbit;
 
 	__asm__ __volatile__("
-	ldx		[%4], %0
-1:
-	and		%0, %3, %2
-	xor		%0, %3, %1
-	casx 		[%4], %0, %1
-	cmp		%0, %1
-	bne,a,pn	%%xcc, 1b
-	 ldx		[%4], %0
-"	: "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+1:	ldx		[%2], %%g7
+	and		%%g7, %1, %0
+	xor		%%g7, %1, %%g5
+	casx 		[%2], %%g7, %%g5
+	cmp		%%g7, %%g5
+	bne,pn		%%xcc, 1b
+	 nop
+"	: "=&r" (oldbit)
 	: "HIr" (1UL << (nr & 63)), "r" (m)
-	: "cc");
+	: "g5", "g7", "cc", "memory");
 	return oldbit != 0;
 }
 
 extern __inline__ void change_bit(unsigned long nr, void *addr)
 {
-	(void) test_and_change_bit(nr, addr);
+	unsigned long * m = ((unsigned long *) addr) + (nr >> 6);
+
+	__asm__ __volatile__("
+1:	ldx		[%1], %%g7
+	xor		%%g7, %0, %%g5
+	casx 		[%1], %%g7, %%g5
+	cmp		%%g7, %%g5
+	bne,pn		%%xcc, 1b
+	 nop
+"	: /* no outputs */
+	: "HIr" (1UL << (nr & 63)), "r" (m)
+	: "g5", "g7", "cc", "memory");
 }
 
 extern __inline__ unsigned long test_bit(int nr, __const__ void *addr)
@@ -201,47 +234,43 @@
  */
 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);
+	unsigned long oldbit;
 
 	__asm__ __volatile__("
-	lduwa		[%4] %5, %0
-1:
-	andcc		%0, %3, %2
+1:	lduwa		[%2] %3, %%g7
+	andcc		%%g7, %1, %0
 	bne,pn		%%icc, 2f
-	 xor		%0, %3, %1
-	casa 		[%4] %5, %0, %1
-	cmp		%0, %1
-	bne,a,pn	%%icc, 1b
-	 lduwa		[%4] %5, %0
+	 xor		%%g7, %1, %%g5
+	casa 		[%2] %3, %%g7, %%g5
+	cmp		%%g7, %%g5
+	bne,pn		%%icc, 1b
+	 nop
 2:
-"	: "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+"	: "=&r" (oldbit)
 	: "HIr" (1UL << (nr & 31)), "r" (m), "i" (ASI_PL)
-	: "cc");
+	: "g5", "g7", "cc", "memory");
 	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);
+	unsigned long oldbit;
 
 	__asm__ __volatile__("
-	lduwa		[%4] %5, %0
-1:
-	andcc		%0, %3, %2
+1:	lduwa		[%2] %3, %%g7
+	andcc		%%g7, %1, %0
 	be,pn		%%icc, 2f
-	 xor		%0, %3, %1
-	casa 		[%4] %5, %0, %1
-	cmp		%0, %1
-	bne,a,pn	%%icc, 1b
-	 lduwa		[%4] %5, %0
+	 xor		%%g7, %1, %%g5
+	casa 		[%2] %3, %%g7, %%g5
+	cmp		%%g7, %%g5
+	bne,pn		%%icc, 1b
+	 nop
 2:
-"	: "=&r" (temp0), "=&r" (temp1), "=&r" (oldbit)
+"	: "=&r" (oldbit)
 	: "HIr" (1UL << (nr & 31)), "r" (m), "i" (ASI_PL)
-	: "cc");
+	: "g5", "g7", "cc", "memory");
 	return oldbit != 0;
 }
 
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/checksum.h linux/include/asm-sparc64/checksum.h
--- v2.1.50/linux/include/asm-sparc64/checksum.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-sparc64/checksum.h	Sat Aug 16 09:51:10 1997
@@ -1,4 +1,4 @@
-/* $Id: checksum.h,v 1.9 1997/06/26 04:05:17 davem Exp $ */
+/* $Id: checksum.h,v 1.10 1997/08/09 18:09:03 jj Exp $ */
 #ifndef __SPARC64_CHECKSUM_H
 #define __SPARC64_CHECKSUM_H
 
@@ -42,47 +42,25 @@
 			csum_partial_copy_nocheck(src,dst,len,sum)
 #define csum_partial_copy_fromuser(s, d, l, w)  \
 			csum_partial_copy_from_user((char *) (s), (d), (l), (w), NULL)
+
+extern unsigned int csum_partial_copy_sparc64(const char *src, char *dst, int len, unsigned int sum);
 			
 extern __inline__ unsigned int 
 csum_partial_copy_nocheck (const char *src, char *dst, int len, 
 			   unsigned int sum)
 {
-	register unsigned long ret asm("o0") = (unsigned long)src;
-	register char *d asm("o1") = dst;
-	register unsigned long l asm("g1") = len;
-
-	__asm__ __volatile__ ("
-		wr	%%g0, %5, %%asi
-		call __csum_partial_copy_sparc_generic
-		 mov %4, %%g7
-		srl	%%o0, 0, %%o0
-	" : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (sum), "i" (ASI_P) :
-	"o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
-	return (unsigned int)ret;
+	__asm__ __volatile__ ("wr	%%g0, %0, %%asi" : : "i" (ASI_P));
+	return csum_partial_copy_sparc64(src, dst, len, sum);
 }
 
 extern __inline__ unsigned int 
 csum_partial_copy_from_user(const char *src, char *dst, int len, 
 			    unsigned int sum, int *err)
 {
-	register unsigned long ret asm("o0") = (unsigned long)src;
-	register char *d asm("o1") = dst;
-	register unsigned long l asm("g1") = len;
-	register unsigned long s asm("g7") = sum;
-
-	__asm__ __volatile__ ("
-	.section __ex_table,#alloc
-	.align 8
-	.xword 1f,2
-	.previous
-	wr	%%g0, %6, %%asi
-1:
-	call __csum_partial_copy_sparc_generic
-	 stx %5, [%%sp + 0x7ff + 128]
-	srl	%%o0, 0, %%o0
-	" : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err), "i" (ASI_S) :
-	"o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
-	return (unsigned int)ret;
+	__asm__ __volatile__ ("wr	%%g0, %0, %%asi
+			       stx	%1, [%%sp + 0x7ff + 128]
+			      " : : "i" (ASI_S), "r" (err));
+	return csum_partial_copy_sparc64(src, dst, len, sum);
 }
 
 #if 0
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/delay.h linux/include/asm-sparc64/delay.h
--- v2.1.50/linux/include/asm-sparc64/delay.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-sparc64/delay.h	Sat Aug 16 09:51:10 1997
@@ -1,4 +1,4 @@
-/* $Id: delay.h,v 1.5 1997/06/18 12:36:23 jj Exp $
+/* $Id: delay.h,v 1.6 1997/07/29 21:11:22 davem Exp $
  * delay.h: Linux delay routines on the V9.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu).
@@ -7,7 +7,9 @@
 #ifndef __SPARC64_DELAY_H
 #define __SPARC64_DELAY_H
 
-extern unsigned long loops_per_sec;
+#ifdef __SMP__
+#include <asm/smp.h>
+#endif 
 
 extern __inline__ void __delay(unsigned long loops)
 {
@@ -23,7 +25,7 @@
 	: "cc");
 }
 
-extern __inline__ void udelay(unsigned long usecs)
+extern __inline__ void __udelay(unsigned long usecs, unsigned long lps)
 {
 	usecs *= 0x00000000000010c6UL;		/* 2**32 / 1000000 */
 
@@ -31,10 +33,18 @@
 	mulx	%1, %2, %0
 	srlx	%0, 32, %0
 "	: "=r" (usecs)
-	: "r" (usecs), "r" (loops_per_sec));
+	: "r" (usecs), "r" (lps));
 
 	__delay(usecs);
 }
+
+#ifdef __SMP__
+#define __udelay_val cpu_data[smp_processor_id()].udelay_val
+#else
+#define __udelay_val loops_per_sec
+#endif
+
+#define udelay(usecs) __udelay((usecs),__udelay_val)
 
 extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
 {
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/ebus.h linux/include/asm-sparc64/ebus.h
--- v2.1.50/linux/include/asm-sparc64/ebus.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/ebus.h	Sat Aug 16 09:51:10 1997
@@ -0,0 +1,51 @@
+/* $Id: ebus.h,v 1.1 1997/08/12 04:13:12 ecd Exp $
+ * ebus.h: PCI to Ebus pseudo driver software state.
+ *
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ */
+
+#ifndef __SPARC64_EBUS_H
+#define __SPARC64_EBUS_H
+
+#include <asm/oplib.h>
+
+struct linux_ebus_device {
+	struct linux_ebus_device	*next;
+	struct linux_ebus		*parent;
+	int				 prom_node;
+	char				 prom_name[64];
+	struct linux_prom_registers	 regs[PROMREG_MAX];
+	int				 num_registers;
+	struct linux_prom_irqs		 irqs[PROMINTR_MAX];
+	int				 num_irqs;
+};
+	
+struct linux_ebus {
+	struct linux_ebus		*next;
+	struct linux_ebus_device	*devices;
+	struct linux_pbm_info		*parent;
+	int				 prom_node;
+	char				 prom_name[64];
+	struct linux_prom_ranges	 ebus_ranges[PROMREG_MAX];
+	int				 num_ebus_ranges;
+};
+
+extern struct linux_ebus		*ebus_chain;
+
+extern unsigned long ebus_init(unsigned long, unsigned long);
+extern void prom_apply_ebus_ranges(struct linux_ebus *ebus,
+				   struct linux_prom_registers *regs,
+				   int nregs);
+
+#define for_each_ebus(bus)						\
+        for((bus) = ebus_chain; (bus); (bus) = (bus)->next)
+
+#define for_each_ebusdev(dev, bus)					\
+        for((dev) = (bus)->devices; (dev); (dev) = (dev)->next)
+
+#define for_all_ebusdev(dev, bus)					\
+	for ((bus) = ebus_chain, ((dev) = (bus) ? (bus)->devices : 0);	\
+	     (bus); ((dev) = (dev)->next ? (dev)->next :		\
+	     ((bus) = (bus)->next, (bus) ? (bus)->devices : 0)))
+
+#endif /* !(__SPARC64_EBUS_H) */
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/fhc.h linux/include/asm-sparc64/fhc.h
--- v2.1.50/linux/include/asm-sparc64/fhc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/fhc.h	Sat Aug 16 09:51:10 1997
@@ -0,0 +1,45 @@
+/* $Id: fhc.h,v 1.1 1997/08/08 04:26:40 davem Exp $
+ * fhc.h: Structures for central/fhc pseudo driver on Sunfire/Starfire/Wildfire.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC64_FHC_H
+#define _SPARC64_FHC_H
+
+#include <asm/firehose.h>
+#include <asm/oplib.h>
+
+struct linux_fhc;
+
+struct linux_central {
+	struct linux_fhc		*child;
+	int				prom_node;
+	char				prom_name[64];
+
+	struct linux_prom_ranges	central_ranges[PROMREG_MAX];
+	int				num_central_ranges;
+};
+
+struct linux_fhc {
+	struct linux_fhc		*next;
+	struct linux_central		*parent;	/* NULL if not central FHC */
+	struct fhc_regs			fhc_regs;
+	int				prom_node;
+	char				prom_name[64];
+
+	struct linux_prom_ranges	fhc_ranges[PROMREG_MAX];
+	int				num_fhc_ranges;
+};
+
+extern struct linux_central *central_bus;
+
+extern void prom_apply_central_ranges(struct linux_central *central, 
+				      struct linux_prom_registers *regs,
+				      int nregs);
+
+extern void prom_apply_fhc_ranges(struct linux_fhc *fhc, 
+				   struct linux_prom_registers *regs,
+				  int nregs);
+
+#endif /* !(_SPARC64_FHC_H) */
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/firehose.h linux/include/asm-sparc64/firehose.h
--- v2.1.50/linux/include/asm-sparc64/firehose.h	Mon Apr 14 16:28:22 1997
+++ linux/include/asm-sparc64/firehose.h	Sat Aug 16 09:51:10 1997
@@ -1,6 +1,6 @@
-/* $Id: firehose.h,v 1.1 1997/04/11 02:38:47 davem Exp $
+/* $Id: firehose.h,v 1.2 1997/08/08 04:26:31 davem Exp $
  * firehose.h: Defines for the Fire Hose Controller (FHC) found
- *             on Sunfire/Wildfire systems.
+ *             on Sunfire/Starfire/Wildfire systems.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  */
@@ -33,38 +33,38 @@
  * for the FHC, thus we have the following few structs...
  */
 struct fhc_ign_reg {
-/*0x2000*/	u64	fhc_ign;	/* FHC Interrupt Group Number		*/
+/*0x2000*/	u64	fhc_ign;		/* FHC Interrupt Group Number	*/
 };
 
 struct fhc_fanfail_regs {
-/*0x4000*/	u64	fhc_ff_imap;	/* FHC FanFail Interrupt Map		*/
-		u64	_unused1;
-/*0x4010*/	u64	fhc_ff_istate;	/* FHC FanFail Interrupt State		*/
+/*0x4000*/	u32	_pad0, fhc_ff_imap;	/* FHC FanFail Interrupt Map	*/
+		u64	_pad1;
+/*0x4010*/	u32	_pad2, fhc_ff_iclr;	/* FHC FanFail Interrupt Clear	*/
 };
 
 struct fhc_system_regs {
-/*0x6000*/	u64	fhc_sys_imap;	/* FHC System Interrupt Map		*/
-		u64	_unused1;
-/*0x6010*/	u64	fhc_sys_istate;	/* FHC System Interrupt State		*/
+/*0x6000*/	u32	_pad0, fhc_sys_imap;	/* FHC System Interrupt Map	*/
+		u64	_pad1;
+/*0x6010*/	u32	_pad2, fhc_sys_iclr;	/* FHC System Interrupt Clear	*/
 };
 
 struct fhc_uart_regs {
-/*0x8000*/	u64	fhc_uart_imap;	/* FHC UART Interrupt Map		*/
-		u64	_unused1;
-/*0x8010*/	u64	fhc_uart_istate;/* FHC UART Interrupt State		*/
+/*0x8000*/	u32	_pad0, fhc_uart_imap;	/* FHC UART Interrupt Map	*/
+		u64	_pad1;
+/*0x8010*/	u32	_pad2, fhc_uart_iclr;	/* FHC UART Interrupt Clear	*/
 };
 
 struct fhc_tod_regs {
-/*0xa000*/	u64	fhc_tod_imap;	/* FHC TOD Interrupt Map		*/
-		u64	_unused1;
-/*0xa010*/	u64	fhc_tod_istate;	/* FHC TOD Interrupt State		*/
+/*0xa000*/	u32	_pad0, fhc_tod_imap;	/* FHC TOD Interrupt Map	*/
+		u64	_pad1;
+/*0xa010*/	u32	_pad2, fhc_tod_iclr;	/* FHC TOD Interrupt Clear	*/
 };
 
 /* All of the above. */
 struct fhc_regs {
 	struct fhc_internal_regs	*pregs;
 	struct fhc_ign_reg		*ireg;
-	struct fhc_fanfil_regs		*ffregs;
+	struct fhc_fanfail_regs		*ffregs;
 	struct fhc_system_regs		*sregs;
 	struct fhc_uart_regs		*uregs;
 	struct fhc_tod_regs		*tregs;
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/hardirq.h linux/include/asm-sparc64/hardirq.h
--- v2.1.50/linux/include/asm-sparc64/hardirq.h	Thu Jul 17 10:06:08 1997
+++ linux/include/asm-sparc64/hardirq.h	Sat Aug 16 09:51:10 1997
@@ -8,16 +8,20 @@
 
 #include <linux/tasks.h>
 
-extern unsigned int local_irq_count[NR_CPUS];
-#define in_interrupt()	(local_irq_count[smp_processor_id()] != 0)
+#ifndef __SMP__
+extern unsigned int local_irq_count;
+#else
+#define local_irq_count		(cpu_data[smp_processor_id()].irq_count)
+#endif
+#define in_interrupt()		(local_irq_count != 0)
 
 #ifndef __SMP__
 
-#define hardirq_trylock(cpu)	(local_irq_count[cpu] == 0)
+#define hardirq_trylock(cpu)	(local_irq_count == 0)
 #define hardirq_endlock(cpu)	do { } while(0)
 
-#define hardirq_enter(cpu)	(local_irq_count[cpu]++)
-#define hardirq_exit(cpu)	(local_irq_count[cpu]--)
+#define hardirq_enter(cpu)	(local_irq_count++)
+#define hardirq_exit(cpu)	(local_irq_count--)
 
 #define synchronize_irq()	do { } while(0)
 
@@ -43,14 +47,16 @@
 
 static inline void hardirq_enter(int cpu)
 {
-	++local_irq_count[cpu];
+	++cpu_data[cpu].irq_count;
 	atomic_inc(&global_irq_count);
+	membar("#StoreLoad | #StoreStore");
 }
 
 static inline void hardirq_exit(int cpu)
 {
+	membar("#StoreStore | #LoadStore");
 	atomic_dec(&global_irq_count);
-	--local_irq_count[cpu];
+	--cpu_data[cpu].irq_count;
 }
 
 static inline int hardirq_trylock(int cpu)
@@ -58,13 +64,14 @@
 	unsigned long flags;
 
 	__save_and_cli(flags);
-	if(atomic_add_return(1, &global_irq_count) != 1 ||
-	   *(((unsigned char *)(&global_irq_lock)))) {
+	atomic_inc(&global_irq_count);
+	if(atomic_read(&global_irq_count) != 1 ||
+	   (*(((unsigned char *)(&global_irq_lock)))) != 0) {
 		atomic_dec(&global_irq_count);
 		__restore_flags(flags);
 		return 0;
 	}
-	++local_irq_count[cpu];
+	++cpu_data[cpu].irq_count;
 	return 1;
 }
 
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/head.h linux/include/asm-sparc64/head.h
--- v2.1.50/linux/include/asm-sparc64/head.h	Thu Jul 17 10:06:08 1997
+++ linux/include/asm-sparc64/head.h	Sat Aug 16 09:51:10 1997
@@ -1,324 +1,9 @@
-/* $Id: head.h,v 1.27 1997/07/13 17:30:43 davem Exp $ */
+/* $Id: head.h,v 1.30 1997/08/08 08:34:33 jj Exp $ */
 #ifndef _SPARC64_HEAD_H
 #define _SPARC64_HEAD_H
 
 #include <asm/pstate.h>
 
 #define KERNBASE    0x400000
-#define BOOT_KERNEL b sparc64_boot; nop; nop; nop; nop; nop; nop; nop;
-
-/* We need a "cleaned" instruction... */
-#define CLEAN_WINDOW							\
-	rdpr	%cleanwin, %l0;		add	%l0, 1, %l0;		\
-	wrpr	%l0, 0x0, %cleanwin;					\
-	clr	%o0;	clr	%o1;	clr	%o2;	clr	%o3;	\
-	clr	%o4;	clr	%o5;	clr	%o6;	clr	%o7;	\
-	clr	%l0;	clr	%l1;	clr	%l2;	clr	%l3;	\
-	clr	%l4;	clr	%l5;	clr	%l6;	clr	%l7;	\
-	retry;								\
-	nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
-
-#define TRAP(routine)					\
-	ba,pt	%xcc, etrap;				\
-	 rd	%pc, %g7;				\
-	call	routine;				\
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
-	ba,pt	%xcc, rtrap;				\
-	 clr	%l6;					\
-	nop;						\
-	nop;
-
-#define TRAP_NOSAVE(routine)				\
-	ba,pt	%xcc, routine;				\
-	 nop;						\
-	nop; nop; nop; nop; nop; nop;
-
-#define TRAPTL1(routine)				\
-	ba,pt	%xcc, etraptl1;				\
-	 rd	%pc, %g7;				\
-	call	routine;				\
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
-	ba,pt	%xcc, rtrap;				\
-	 clr	%l6;					\
-	nop;						\
-	nop;
-	
-#define TRAP_ARG(routine, arg)				\
-	ba,pt	%xcc, etrap;				\
-	 rd	%pc, %g7;				\
-	add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
-	call	routine;				\
-	 mov	arg, %o1;				\
-	ba,pt	%xcc, rtrap;				\
-	 clr	%l6;					\
-	nop;
-	
-#define TRAPTL1_ARG(routine, arg)			\
-	ba,pt	%xcc, etraptl1;				\
-	 rd	%pc, %g7;				\
-	add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
-	call	routine;				\
-	 mov	arg, %o1;				\
-	ba,pt	%xcc, rtrap;				\
-	 clr	%l6;					\
-	nop;
-	
-#define SYSCALL_TRAP(routine, systbl)			\
-	ba,pt	%xcc, etrap;				\
-	 rd	%pc, %g7;				\
-	sethi	%hi(systbl), %l7;			\
-	call	routine;				\
-	 or	%l7, %lo(systbl), %l7;			\
-	nop; nop; nop;
-	
-#define ACCESS_EXCEPTION_TRAP(routine)			\
-	rdpr	%pstate, %g1;				\
-	wrpr	%g1, PSTATE_MG|PSTATE_AG, %pstate;	\
-	ba,pt	%xcc, etrap;				\
-	 rd	%pc, %g7;				\
-	call	routine;				\
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
-	ba,pt	%xcc, rtrap;				\
-	 clr	%l6;
-
-#define ACCESS_EXCEPTION_TRAPTL1(routine)		\
-	rdpr	%pstate, %g1;				\
-	wrpr	%g1, PSTATE_MG|PSTATE_AG, %pstate;	\
-	ba,pt	%xcc, etraptl1;				\
-	 rd	%pc, %g7;				\
-	call	routine;				\
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
-	ba,pt	%xcc, rtrap;				\
-	 clr	%l6;
-
-#define SUNOS_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sunos_sys_table)
-#define	LINUX_32BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table32)
-#define LINUX_64BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table64)
-#define GETCC_TRAP TRAP(getcc)
-#define SETCC_TRAP TRAP(setcc)
-/* FIXME: Write these actually */	
-#define NETBSD_SYSCALL_TRAP TRAP(netbsd_syscall)
-#define SOLARIS_SYSCALL_TRAP TRAP(solaris_syscall)
-#define BREAKPOINT_TRAP TRAP(breakpoint_trap)
-#define INDIRECT_SOLARIS_SYSCALL(tlvl) TRAP_ARG(indirect_syscall, tlvl)
-
-#define TRAP_IRQ(routine, level)			\
-	rdpr	%pil, %g2;				\
-	wrpr	%g0, 15, %pil;				\
-	ba,pt	%xcc, etrap_irq;			\
-	 rd	%pc, %g7;				\
-	mov	level, %o0;				\
-	call	routine;				\
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o1;	\
-	ba,a,pt	%xcc, rtrap_clr_l6;
-
-/* On UP this is ok, and worth the effort, for SMP we need
- * a different mechanism and thus cannot do it all in trap table. -DaveM
- */
-#ifndef __SMP__
-#define TRAP_IVEC				\
-	ldxa	[%g2] ASI_UDB_INTR_R, %g3;	\
-	and	%g3, 0x7ff, %g3;		\
-	sllx	%g3, 3, %g3;			\
-	ldx	[%g1 + %g3], %g5;		\
-	wr	%g5, 0x0, %set_softint;		\
-	stxa	%g0, [%g0] ASI_INTR_RECEIVE;	\
-	membar	#Sync;				\
-	retry;
-#else
-#define TRAP_IVEC TRAP_NOSAVE(do_ivec)
-#endif
-
-#define BTRAP(lvl) TRAP_ARG(bad_trap, lvl)
-
-#define BTRAPTL1(lvl) TRAPTL1_ARG(bad_trap_tl1, lvl)
-
-#define FLUSH_WINDOW_TRAP						\
-	ba,pt	%xcc, etrap;						\
-	 rd	%pc, %g7;						\
-	flushw;								\
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1;	\
-	add	%l1, 4, %l2;						\
-	stx	%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC];	\
-	ba,pt	%xcc, rtrap_clr_l6;					\
-	 stx	%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC];
-	        
-/* Before touching these macros, you owe it to yourself to go and
- * see how arch/sparc64/kernel/winfixup.S works... -DaveM
- */
-
-/* Normal kernel spill */
-#define SPILL_0_NORMAL					\
-	stx	%l0, [%sp + STACK_BIAS + 0x00];		\
-	stx	%l1, [%sp + STACK_BIAS + 0x08];		\
-	stx	%l2, [%sp + STACK_BIAS + 0x10];		\
-	stx	%l3, [%sp + STACK_BIAS + 0x18];		\
-	stx	%l4, [%sp + STACK_BIAS + 0x20];		\
-	stx	%l5, [%sp + STACK_BIAS + 0x28];		\
-	stx	%l6, [%sp + STACK_BIAS + 0x30];		\
-	stx	%l7, [%sp + STACK_BIAS + 0x38];		\
-	stx	%i0, [%sp + STACK_BIAS + 0x40];		\
-	stx	%i1, [%sp + STACK_BIAS + 0x48];		\
-	stx	%i2, [%sp + STACK_BIAS + 0x50];		\
-	stx	%i3, [%sp + STACK_BIAS + 0x58];		\
-	stx	%i4, [%sp + STACK_BIAS + 0x60];		\
-	stx	%i5, [%sp + STACK_BIAS + 0x68];		\
-	stx	%i6, [%sp + STACK_BIAS + 0x70];		\
-	stx	%i7, [%sp + STACK_BIAS + 0x78];		\
-	saved; retry; nop; nop; nop; nop; nop; nop;	\
-	nop; nop; nop; nop; nop; nop; nop; nop;
-
-/* Normal 64bit spill */
-#define SPILL_1_GENERIC(xxx)				\
-	wr	%g0, xxx, %asi;				\
-	stxa	%l0, [%sp + STACK_BIAS + 0x00] %asi;	\
-	stxa	%l1, [%sp + STACK_BIAS + 0x08] %asi;	\
-	stxa	%l2, [%sp + STACK_BIAS + 0x10] %asi;	\
-	stxa	%l3, [%sp + STACK_BIAS + 0x18] %asi;	\
-	stxa	%l4, [%sp + STACK_BIAS + 0x20] %asi;	\
-	stxa	%l5, [%sp + STACK_BIAS + 0x28] %asi;	\
-	stxa	%l6, [%sp + STACK_BIAS + 0x30] %asi;	\
-	stxa	%l7, [%sp + STACK_BIAS + 0x38] %asi;	\
-	stxa	%i0, [%sp + STACK_BIAS + 0x40] %asi;	\
-	stxa	%i1, [%sp + STACK_BIAS + 0x48] %asi;	\
-	stxa	%i2, [%sp + STACK_BIAS + 0x50] %asi;	\
-	stxa	%i3, [%sp + STACK_BIAS + 0x58] %asi;	\
-	stxa	%i4, [%sp + STACK_BIAS + 0x60] %asi;	\
-	stxa	%i5, [%sp + STACK_BIAS + 0x68] %asi;	\
-	stxa	%i6, [%sp + STACK_BIAS + 0x70] %asi;	\
-	stxa	%i7, [%sp + STACK_BIAS + 0x78] %asi;	\
-	saved; retry; nop; nop; nop; nop; nop; nop;	\
-	nop; nop; nop; nop; nop;			\
-	b,a,pt	%xcc, spill_fixup_mna;			\
-	b,a,pt	%xcc, spill_fixup;
-
-/* Normal 32bit spill */
-#define SPILL_2_GENERIC(xxx)				\
-	wr	%g0, xxx, %asi;				\
-	srl	%sp, 0, %sp;				\
-	stwa	%l0, [%sp + 0x00] %asi;			\
-	stwa	%l1, [%sp + 0x04] %asi;			\
-	stwa	%l2, [%sp + 0x08] %asi;			\
-	stwa	%l3, [%sp + 0x0c] %asi;			\
-	stwa	%l4, [%sp + 0x10] %asi;			\
-	stwa	%l5, [%sp + 0x14] %asi;			\
-	stwa	%l6, [%sp + 0x18] %asi;			\
-	stwa	%l7, [%sp + 0x1c] %asi;			\
-	stwa	%i0, [%sp + 0x20] %asi;			\
-	stwa	%i1, [%sp + 0x24] %asi;			\
-	stwa	%i2, [%sp + 0x28] %asi;			\
-	stwa	%i3, [%sp + 0x2c] %asi;			\
-	stwa	%i4, [%sp + 0x30] %asi;			\
-	stwa	%i5, [%sp + 0x34] %asi;			\
-	stwa	%i6, [%sp + 0x38] %asi;			\
-	stwa	%i7, [%sp + 0x3c] %asi;			\
-	saved; retry; nop; nop; nop; nop;		\
-	nop; nop; nop; nop; nop; nop;			\
-	b,a,pt	%xcc, spill_fixup_mna;			\
-	b,a,pt	%xcc, spill_fixup;
-
-#define SPILL_1_NORMAL SPILL_1_GENERIC(ASI_AIUP)
-#define SPILL_2_NORMAL SPILL_2_GENERIC(ASI_AIUP)
-#define SPILL_3_NORMAL SPILL_0_NORMAL
-#define SPILL_4_NORMAL SPILL_0_NORMAL
-#define SPILL_5_NORMAL SPILL_0_NORMAL
-#define SPILL_6_NORMAL SPILL_0_NORMAL
-#define SPILL_7_NORMAL SPILL_0_NORMAL
-
-#define SPILL_0_OTHER SPILL_0_NORMAL
-#define SPILL_1_OTHER SPILL_1_GENERIC(ASI_AIUS)
-#define SPILL_2_OTHER SPILL_2_GENERIC(ASI_AIUS)
-#define SPILL_3_OTHER SPILL_3_NORMAL
-#define SPILL_4_OTHER SPILL_4_NORMAL
-#define SPILL_5_OTHER SPILL_5_NORMAL
-#define SPILL_6_OTHER SPILL_6_NORMAL
-#define SPILL_7_OTHER SPILL_7_NORMAL
-
-/* Normal kernel fill */
-#define FILL_0_NORMAL					\
-	ldx	[%sp + STACK_BIAS + 0x00], %l0;		\
-	ldx	[%sp + STACK_BIAS + 0x08], %l1;		\
-	ldx	[%sp + STACK_BIAS + 0x10], %l2;		\
-	ldx	[%sp + STACK_BIAS + 0x18], %l3;		\
-	ldx	[%sp + STACK_BIAS + 0x20], %l4;		\
-	ldx	[%sp + STACK_BIAS + 0x28], %l5;		\
-	ldx	[%sp + STACK_BIAS + 0x30], %l6;		\
-	ldx	[%sp + STACK_BIAS + 0x38], %l7;		\
-	ldx	[%sp + STACK_BIAS + 0x40], %i0;		\
-	ldx	[%sp + STACK_BIAS + 0x48], %i1;		\
-	ldx	[%sp + STACK_BIAS + 0x50], %i2;		\
-	ldx	[%sp + STACK_BIAS + 0x58], %i3;		\
-	ldx	[%sp + STACK_BIAS + 0x60], %i4;		\
-	ldx	[%sp + STACK_BIAS + 0x68], %i5;		\
-	ldx	[%sp + STACK_BIAS + 0x70], %i6;		\
-	ldx	[%sp + STACK_BIAS + 0x78], %i7;		\
-	restored; retry; nop; nop; nop; nop; nop; nop;	\
-	nop; nop; nop; nop; nop; nop; nop; nop;
-
-/* Normal 64bit fill */
-#define FILL_1_GENERIC(xxx)				\
-	wr	%g0, xxx, %asi;				\
-	ldxa	[%sp + STACK_BIAS + 0x00] %asi, %l0;	\
-	ldxa	[%sp + STACK_BIAS + 0x08] %asi, %l1;	\
-	ldxa	[%sp + STACK_BIAS + 0x10] %asi, %l2;	\
-	ldxa	[%sp + STACK_BIAS + 0x18] %asi, %l3;	\
-	ldxa	[%sp + STACK_BIAS + 0x20] %asi, %l4;	\
-	ldxa	[%sp + STACK_BIAS + 0x28] %asi, %l5;	\
-	ldxa	[%sp + STACK_BIAS + 0x30] %asi, %l6;	\
-	ldxa	[%sp + STACK_BIAS + 0x38] %asi, %l7;	\
-	ldxa	[%sp + STACK_BIAS + 0x40] %asi, %i0;	\
-	ldxa	[%sp + STACK_BIAS + 0x48] %asi, %i1;	\
-	ldxa	[%sp + STACK_BIAS + 0x50] %asi, %i2;	\
-	ldxa	[%sp + STACK_BIAS + 0x58] %asi, %i3;	\
-	ldxa	[%sp + STACK_BIAS + 0x60] %asi, %i4;	\
-	ldxa	[%sp + STACK_BIAS + 0x68] %asi, %i5;	\
-	ldxa	[%sp + STACK_BIAS + 0x70] %asi, %i6;	\
-	ldxa	[%sp + STACK_BIAS + 0x78] %asi, %i7;	\
-	restored; retry; nop; nop; nop; nop; nop; nop;	\
-	nop; nop; nop; nop; nop;			\
-	b,a,pt	%xcc, fill_fixup_mna;			\
-	b,a,pt	%xcc, fill_fixup;
-
-/* Normal 32bit fill */
-#define FILL_2_GENERIC(xxx)				\
-	wr	%g0, xxx, %asi;				\
-	srl	%sp, 0, %sp;				\
-	lduwa	[%sp + 0x00] %asi, %l0;			\
-	lduwa	[%sp + 0x04] %asi, %l1;			\
-	lduwa	[%sp + 0x08] %asi, %l2;			\
-	lduwa	[%sp + 0x0c] %asi, %l3;			\
-	lduwa	[%sp + 0x10] %asi, %l4;			\
-	lduwa	[%sp + 0x14] %asi, %l5;			\
-	lduwa	[%sp + 0x18] %asi, %l6;			\
-	lduwa	[%sp + 0x1c] %asi, %l7;			\
-	lduwa	[%sp + 0x20] %asi, %i0;			\
-	lduwa	[%sp + 0x24] %asi, %i1;			\
-	lduwa	[%sp + 0x28] %asi, %i2;			\
-	lduwa	[%sp + 0x2c] %asi, %i3;			\
-	lduwa	[%sp + 0x30] %asi, %i4;			\
-	lduwa	[%sp + 0x34] %asi, %i5;			\
-	lduwa	[%sp + 0x38] %asi, %i6;			\
-	lduwa	[%sp + 0x3c] %asi, %i7;			\
-	restored; retry; nop; nop; nop; nop;		\
-	nop; nop; nop; nop; nop; nop;			\
-	b,a,pt	%xcc, fill_fixup_mna;			\
-	b,a,pt	%xcc, fill_fixup;
-
-#define FILL_1_NORMAL FILL_1_GENERIC(ASI_AIUP)
-#define FILL_2_NORMAL FILL_2_GENERIC(ASI_AIUP)
-#define FILL_3_NORMAL FILL_0_NORMAL
-#define FILL_4_NORMAL FILL_0_NORMAL
-#define FILL_5_NORMAL FILL_0_NORMAL
-#define FILL_6_NORMAL FILL_0_NORMAL
-#define FILL_7_NORMAL FILL_0_NORMAL
-
-#define FILL_0_OTHER FILL_0_NORMAL
-#define FILL_1_OTHER FILL_1_GENERIC(ASI_AIUS)
-#define FILL_2_OTHER FILL_2_GENERIC(ASI_AIUS)
-#define FILL_3_OTHER FILL_3_NORMAL
-#define FILL_4_OTHER FILL_4_NORMAL
-#define FILL_5_OTHER FILL_5_NORMAL
-#define FILL_6_OTHER FILL_6_NORMAL
-#define FILL_7_OTHER FILL_7_NORMAL
 
 #endif /* !(_SPARC64_HEAD_H) */
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/ioctls.h linux/include/asm-sparc64/ioctls.h
--- v2.1.50/linux/include/asm-sparc64/ioctls.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-sparc64/ioctls.h	Sat Aug 16 09:51:10 1997
@@ -1,4 +1,4 @@
-/* $Id: ioctls.h,v 1.4 1997/06/23 07:26:03 davem Exp $ */
+/* $Id: ioctls.h,v 1.5 1997/08/12 04:13:13 ecd Exp $ */
 #ifndef _ASM_SPARC64_IOCTLS_H
 #define _ASM_SPARC64_IOCTLS_H
 
@@ -105,6 +105,8 @@
 #define TIOCSERGETLSR   0x5459 /* Get line status register */
 #define TIOCSERGETMULTI 0x545A /* Get multiport config  */
 #define TIOCSERSETMULTI 0x545B /* Set multiport config */
+#define TIOCMIWAIT	0x545C /* Wait for change on serial input line(s) */
+#define TIOCGICOUNT	0x545D /* Read serial port inline interrupt counts */
 
 /* Kernel definitions */
 #ifdef __KERNEL__
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/iommu.h linux/include/asm-sparc64/iommu.h
--- v2.1.50/linux/include/asm-sparc64/iommu.h	Mon Apr 14 16:28:22 1997
+++ linux/include/asm-sparc64/iommu.h	Sat Aug 16 09:51:10 1997
@@ -7,6 +7,7 @@
 
 #include <asm/page.h>
 #include <asm/sysio.h>
+#include <asm/spinlock.h>
 
 /* The iommu handles all virtual to physical address translations
  * that occur between the SYSIO and physical memory.  Access by
@@ -43,8 +44,12 @@
 #define IOPTE_WRITE         0x0000000000000002 /* Writeable                        */
 
 struct iommu_struct {
-	struct sysio_regs *sysio_regs;
-	iopte_t *page_table;
+	struct sysio_regs	*sysio_regs;
+	unsigned int		*sbuf_flushflag_va;
+	unsigned long		sbuf_flushflag_pa;
+	spinlock_t		iommu_lock;
+
+	iopte_t			*page_table;
 
 	/* For convenience */
 	unsigned long start; /* First managed virtual address */
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/irq.h linux/include/asm-sparc64/irq.h
--- v2.1.50/linux/include/asm-sparc64/irq.h	Mon Apr 14 16:28:22 1997
+++ linux/include/asm-sparc64/irq.h	Sat Aug 16 09:51:10 1997
@@ -1,4 +1,4 @@
-/* $Id: irq.h,v 1.4 1997/04/04 00:50:20 davem Exp $
+/* $Id: irq.h,v 1.6 1997/08/07 08:06:40 davem Exp $
  * irq.h: IRQ registers on the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -9,7 +9,31 @@
 
 #include <linux/linkage.h>
 
-#include <asm/system.h>     /* For NCPUS */
+/* Sparc64 extensions to the interrupt registry flags.  Mostly this is
+ * for passing along what bus type the device is on and also the true
+ * format of the dev_id cookie, see below.
+ */
+#define SA_BUSMASK	0x0f000
+#define SA_SBUS		0x01000
+#define SA_PCI		0x02000
+#define SA_FHC		0x03000
+#define SA_EBUS		0x04000
+#define SA_BUS(mask)	((mask) & SA_BUSMASK)
+
+struct devid_cookie {
+	/* Caller specifies these. */
+	void		*real_dev_id;		/* What dev_id would usually contain. */
+	unsigned int	*imap;			/* Anonymous IMAP register */
+	unsigned int	*iclr;			/* Anonymous ICLR register */
+	int		pil;			/* Anonymous PIL */
+	void		*bus_cookie;		/* SYSIO regs, PSYCHO regs, etc. */
+
+	/* Return values. */
+	unsigned int	ret_ino;
+	unsigned int	ret_pil;
+};
+
+#define SA_DCOOKIE	0x10000
 
 #define NR_IRQS    15
 
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/mmu_context.h linux/include/asm-sparc64/mmu_context.h
--- v2.1.50/linux/include/asm-sparc64/mmu_context.h	Thu Jul 17 10:06:08 1997
+++ linux/include/asm-sparc64/mmu_context.h	Sat Aug 16 09:51:10 1997
@@ -1,4 +1,4 @@
-/* $Id: mmu_context.h,v 1.17 1997/07/13 19:13:39 davem Exp $ */
+/* $Id: mmu_context.h,v 1.19 1997/08/07 02:54:08 davem Exp $ */
 #ifndef __SPARC64_MMU_CONTEXT_H
 #define __SPARC64_MMU_CONTEXT_H
 
@@ -11,20 +11,33 @@
 
 #ifndef __ASSEMBLY__
 
-#define destroy_context(mm)	do { } while(0)
-
 extern unsigned long tlb_context_cache;
 
 #define CTX_VERSION_SHIFT	PAGE_SHIFT
 #define CTX_VERSION_MASK	((~0UL) << CTX_VERSION_SHIFT)
 #define CTX_FIRST_VERSION	((1UL << CTX_VERSION_SHIFT) + 1UL)
 
-extern void get_new_mmu_context(struct mm_struct *mm, unsigned long ctx);
+extern void get_new_mmu_context(struct mm_struct *mm, unsigned long *ctx);
 
-/* Initialize the context related info for a new mm_struct
+/* Initialize/destroy the context related info for a new mm_struct
  * instance.
  */
-#define init_new_context(mm)	get_new_mmu_context((mm), tlb_context_cache)
+#define init_new_context(mm)	((mm)->context = NO_CONTEXT)
+#define destroy_context(mm)	((mm)->context = NO_CONTEXT)
+
+#ifdef __SMP__
+#define LOCAL_FLUSH_PENDING(cpu)	\
+	((cpu_data[(cpu)].last_tlbversion_seen ^ tlb_context_cache) & CTX_VERSION_MASK)
+#define DO_LOCAL_FLUSH(cpu)		do { __flush_tlb_all();				\
+					     cpu_data[cpu].last_tlbversion_seen =	\
+					     tlb_context_cache & CTX_VERSION_MASK;	\
+					} while(0)
+#else
+#define LOCAL_FLUSH_PENDING(cpu)	0
+#define DO_LOCAL_FLUSH(cpu)		do { __flush_tlb_all(); } while(0)
+#endif
+
+extern void __flush_tlb_all(void);
 
 extern __inline__ void get_mmu_context(struct task_struct *tsk)
 {
@@ -32,11 +45,13 @@
 	struct mm_struct *mm = tsk->mm;
 
 	flushw_user();
+	if(LOCAL_FLUSH_PENDING(current->processor))
+		DO_LOCAL_FLUSH(current->processor);
 	if(!(tsk->tss.flags & SPARC_FLAG_KTHREAD)	&&
 	   !(tsk->flags & PF_EXITING)) {
 		unsigned long ctx = tlb_context_cache;
 		if((mm->context ^ ctx) & CTX_VERSION_MASK)
-			get_new_mmu_context(mm, ctx);
+			get_new_mmu_context(mm, &tlb_context_cache);
 
 		/* Don't worry, set_fs() will restore it... */
 		tsk->tss.ctx = (tsk->tss.current_ds ?
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/openprom.h linux/include/asm-sparc64/openprom.h
--- v2.1.50/linux/include/asm-sparc64/openprom.h	Mon Apr 14 16:28:23 1997
+++ linux/include/asm-sparc64/openprom.h	Sat Aug 16 09:51:10 1997
@@ -1,4 +1,4 @@
-/* $Id: openprom.h,v 1.4 1997/03/24 06:42:08 davem Exp $ */
+/* $Id: openprom.h,v 1.5 1997/08/15 06:44:51 davem Exp $ */
 #ifndef __SPARC64_OPENPROM_H
 #define __SPARC64_OPENPROM_H
 
@@ -208,6 +208,28 @@
 	unsigned int ot_parent_space;
 	unsigned int ot_parent_base;		/* CPU looks from here */
 	unsigned int or_size;
+};
+
+/* Ranges and reg properties are a bit different for PCI. */
+struct linux_prom_pci_registers {
+	unsigned int phys_hi;
+	unsigned int phys_mid;
+	unsigned int phys_lo;
+
+	unsigned int size_hi;
+	unsigned int size_lo;
+};
+
+struct linux_prom_pci_ranges {
+	unsigned int child_phys_hi;	/* Only certain bits are encoded here. */
+	unsigned int child_phys_mid;
+	unsigned int child_phys_lo;
+
+	unsigned int parent_phys_hi;
+	unsigned int parent_phys_lo;
+
+	unsigned int size_hi;
+	unsigned int size_lo;
 };
 
 #endif /* !(__ASSEMBLY__) */
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/page.h linux/include/asm-sparc64/page.h
--- v2.1.50/linux/include/asm-sparc64/page.h	Mon Jul  7 08:18:55 1997
+++ linux/include/asm-sparc64/page.h	Sat Aug 16 09:51:10 1997
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.14 1997/06/26 22:32:03 davem Exp $ */
+/* $Id: page.h,v 1.15 1997/08/09 04:56:54 davem Exp $ */
 
 #ifndef _SPARC64_PAGE_H
 #define _SPARC64_PAGE_H
@@ -82,13 +82,11 @@
 
 #endif /* (STRICT_MM_TYPECHECKS) */
 
-#endif /* !(__ASSEMBLY__) */
+#define TASK_UNMAPPED_BASE	((current->tss.flags & SPARC_FLAG_32BIT) ? \
+				 (0x0000000070000000UL) : \
+				 (0x0000030000000000UL))
 
-#ifndef __ASSEMBLY__
-#define TASK_UNMAPPED_BASE	0x0000000070000000UL
-#else
-#define TASK_UNMAPPED_BASE	0x0000000070000000
-#endif
+#endif /* !(__ASSEMBLY__) */
 
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/pbm.h linux/include/asm-sparc64/pbm.h
--- v2.1.50/linux/include/asm-sparc64/pbm.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/pbm.h	Sat Aug 16 09:51:10 1997
@@ -0,0 +1,46 @@
+/* $Id: pbm.h,v 1.4 1997/08/15 06:44:52 davem Exp $
+ * pbm.h: U2P PCI bus module pseudo driver software state.
+ *
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef __SPARC64_PBM_H
+#define __SPARC64_PBM_H
+
+#include <linux/bios32.h>
+#include <linux/pci.h>
+
+#include <asm/psycho.h>
+#include <asm/oplib.h>
+
+struct linux_psycho;
+
+struct linux_pbm_info {
+	struct linux_psycho		*parent;
+	unsigned long			*pbm_IO;
+	unsigned long			*pbm_mem;
+	int				prom_node;
+	char				prom_name[64];
+	struct linux_prom_pci_ranges	pbm_ranges[PROMREG_MAX];
+	int				num_pbm_ranges;
+
+	/* Now things for the actual PCI bus probes. */
+	unsigned int			pci_first_busno;
+	unsigned int			pci_last_busno;
+	struct pci_bus			pci_bus;
+};
+
+struct linux_psycho {
+	struct linux_psycho		*next;
+	struct psycho_regs		*psycho_regs;
+	unsigned long			*pci_config_space;
+	unsigned long			*pci_IO_space;
+	unsigned long			*pci_mem_space;
+	u32				upa_portid;
+	struct linux_pbm_info		pbm_A;
+	struct linux_pbm_info		pbm_B;
+};
+
+extern struct linux_psycho *psycho_root;
+
+#endif /* !(__SPARC64_PBM_H) */
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.1.50/linux/include/asm-sparc64/pgtable.h	Mon Aug  4 16:25:40 1997
+++ linux/include/asm-sparc64/pgtable.h	Sat Aug 16 09:51:10 1997
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.50 1997/07/24 16:48:31 davem Exp $
+/* $Id: pgtable.h,v 1.57 1997/08/13 04:44:20 paulus Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -159,12 +159,13 @@
 /* Cache and TLB flush operations. */
 
 /* These are the same regardless of whether this is an SMP kernel or not. */
-#define flush_cache_mm(mm)			do { } while(0)
-#define flush_cache_range(mm, start, end)	do { } while(0)
-#define flush_cache_page(vma, page)		do { } while(0)
+#define flush_cache_mm(mm)			flushw_user()
+#define flush_cache_range(mm, start, end)	flushw_user()
+#define flush_cache_page(vma, page)		flushw_user()
 
 /* This operation in unnecessary on the SpitFire since D-CACHE is write-through. */
 #define flush_page_to_ram(page)			do { } while (0)
+#define flush_icache_range(start, end)		do { } while (0)
 
 extern void __flush_cache_all(void);
 
@@ -207,7 +208,7 @@
 extern void smp_flush_tlb_mm(struct mm_struct *mm);
 extern void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start,
 				unsigned long end);
-extern void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page);
+extern void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page);
 
 #define flush_cache_all()	smp_flush_cache_all()
 #define flush_tlb_all()		smp_flush_tlb_all()
@@ -230,7 +231,7 @@
 	struct mm_struct *mm = vma->vm_mm;
 
 	if(mm->context != NO_CONTEXT)
-		smp_flush_tlb_page(vma, page);
+		smp_flush_tlb_page(mm, page & PAGE_MASK);
 }
 
 #endif
@@ -259,18 +260,21 @@
 extern inline unsigned long pgd_page(pgd_t pgd)
 { return (unsigned long) __va(pgd_val(pgd)); }
 
+#define PMD_NONE_MAGIC		0x80
+#define PGD_NONE_MAGIC		0x40
+
 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_clear(pte_t *pte)	{ pte_val(*pte) = 0; }
 
-extern inline int pmd_none(pmd_t pmd)		{ return pmd_val(pmd)==null_pte_table; }
-extern inline int pmd_bad(pmd_t pmd)		{ return (pmd_val(pmd) & ~PAGE_MASK); }
-extern inline int pmd_present(pmd_t pmd)	{ return pmd_val(pmd)!=null_pte_table; }
+extern inline int pmd_none(pmd_t pmd)		{ return pmd_val(pmd)&PMD_NONE_MAGIC; }
+extern inline int pmd_bad(pmd_t pmd)		{ return 0; }
+extern inline int pmd_present(pmd_t pmd)	{ return !(pmd_val(pmd)&PMD_NONE_MAGIC);}
 extern inline void pmd_clear(pmd_t *pmdp)	{ pmd_val(*pmdp) = null_pte_table; }
 
-extern inline int pgd_none(pgd_t pgd)		{ return pgd_val(pgd)==null_pmd_table; }
-extern inline int pgd_bad(pgd_t pgd)		{ return (pgd_val(pgd) & ~PAGE_MASK); }
-extern inline int pgd_present(pgd_t pgd)	{ return pgd_val(pgd)!=null_pmd_table; }
+extern inline int pgd_none(pgd_t pgd)		{ return pgd_val(pgd) & PGD_NONE_MAGIC; }
+extern inline int pgd_bad(pgd_t pgd)		{ return 0; }
+extern inline int pgd_present(pgd_t pgd)	{ return !(pgd_val(pgd)&PGD_NONE_MAGIC);}
 extern inline void pgd_clear(pgd_t *pgdp)	{ pgd_val(*pgdp) = null_pmd_table; }
 
 /* The following only work if pte_present() is true.
@@ -332,148 +336,127 @@
 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)); }
 
-extern __inline__ void __init_pmd(pmd_t *pmdp)
+/* Very stupidly, we used to get new pgd's and pmd's, init their contents
+ * to point to the NULL versions of the next level page table, later on
+ * completely re-init them the same way, then free them up.  This wasted
+ * a lot of work and caused unnecessary memory traffic.  How broken...
+ * We fix this by caching them.
+ */
+
+#ifdef __SMP__
+/* Sliiiicck */
+#define pgd_quicklist		(cpu_data[smp_processor_id()].pgd_cache)
+#define pmd_quicklist		(cpu_data[smp_processor_id()].pmd_cache)
+#define pte_quicklist		(cpu_data[smp_processor_id()].pte_cache)
+#define pgtable_cache_size	(cpu_data[smp_processor_id()].pgcache_size)
+#else
+extern unsigned long *pgd_quicklist;
+extern unsigned long *pmd_quicklist;
+extern unsigned long *pte_quicklist;
+extern unsigned long pgtable_cache_size;
+#endif
+
+extern pgd_t *get_pgd_slow(void);
+
+extern __inline__ pgd_t *get_pgd_fast(void)
 {
-	extern void __bfill64(void *, unsigned long *);
-	
-	__bfill64((void *)pmdp, &null_pte_table);
+	pgd_t *ret;
+
+	if((ret = (pgd_t *)pgd_quicklist) != NULL) {
+		pgd_quicklist = (unsigned long *)pgd_val(*ret);
+		pgd_val(ret[0]) = pgd_val(ret[1]);
+		(pgtable_cache_size)--;
+	} else
+		ret = get_pgd_slow();
+	return ret;
 }
 
-/* Turning this off makes things much faster, but eliminates some
- * sanity checking as well.
- */
-/* #define PGTABLE_SANITY_CHECKS */
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
+{
+	pgd_val(*pgd) = (unsigned long) pgd_quicklist;
+	pgd_quicklist = (unsigned long *) pgd;
+	(pgtable_cache_size)++;
+}
 
-/* 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 pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long address_premasked);
 
-extern inline pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
+extern __inline__ pmd_t *get_pmd_fast(void)
 {
-	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, BAD_PTE);
-			return NULL;
-		}
-		free_page((unsigned long) page);
-	}
-#ifdef PGTABLE_SANITY_CHECKS
-	if (pmd_bad(*pmd)) {
-		printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
-		pmd_set(pmd, BAD_PTE);
-		return NULL;
+	pmd_t *ret;
+
+	if((ret = (pmd_t *)pmd_quicklist) != NULL) {
+		pmd_quicklist = (unsigned long *)pmd_val(*ret);
+		pmd_val(ret[0]) = pmd_val(ret[1]);
+		(pgtable_cache_size)--;
 	}
-#endif
-	return (pte_t *) pmd_page(*pmd) + address;
+	return ret;
 }
 
-extern inline void pmd_free_kernel(pmd_t *pmd)
-{ free_page((unsigned long) pmd); }
+extern __inline__ void free_pmd_fast(pgd_t *pmd)
+{
+	pmd_val(*pmd) = (unsigned long) pmd_quicklist;
+	pmd_quicklist = (unsigned long *) pmd;
+	(pgtable_cache_size)++;
+}
+
+extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
 
-extern inline pmd_t * pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
+extern __inline__ pte_t *get_pte_fast(void)
 {
-	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) {
-				__init_pmd(page);
-				pgd_set(pgd, page);
-				return page + address;
-			}
-			pgd_set(pgd, BAD_PMD);
-			return NULL;
-		}
-		free_page((unsigned long) page);
-	}
-#ifdef PGTABLE_SANITY_CHECKS
-	if (pgd_bad(*pgd)) {
-		printk("Bad pgd in pmd_alloc_kernel: %08lx\n", pgd_val(*pgd));
-		pgd_set(pgd, BAD_PMD);
-		return NULL;
+	pte_t *ret;
+
+	if((ret = (pte_t *)pte_quicklist) != NULL) {
+		pte_quicklist = (unsigned long *)pte_val(*ret);
+		pte_val(ret[0]) = pte_val(ret[1]);
+		(pgtable_cache_size)--;
 	}
-#endif
-	return (pmd_t *) pgd_page(*pgd) + address;
+	return ret;
 }
 
-extern inline void pte_free(pte_t * pte)
-{ free_page((unsigned long)pte); }
+extern __inline__ void free_pte_fast(pte_t *pte)
+{
+	pte_val(*pte) = (unsigned long) pte_quicklist;
+	pte_quicklist = (unsigned long *) pte;
+	(pgtable_cache_size)++;
+}
+
+#define pte_free_kernel(pte)	free_pte_fast(pte)
+#define pte_free(pte)		free_pte_fast(pte)
+#define pmd_free_kernel(pmd)	free_pmd_fast(pmd)
+#define pmd_free(pmd)		free_pmd_fast(pmd)
+#define pgd_free(pgd)		free_pgd_fast(pgd)
+#define pgd_alloc()		get_pgd_fast()
 
 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, BAD_PTE);
-			return NULL;
-		}
-		free_page((unsigned long) page);
-	}
-#ifdef PGTABLE_SANITY_CHECKS
-	if (pmd_bad(*pmd)) {
-		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-		pmd_set(pmd, BAD_PTE);
-		return NULL;
+		pte_t *page = get_pte_fast();
+
+		if (!page)
+			return get_pte_slow(pmd, address);
+		pmd_set(pmd, page);
+		return page + address;
 	}
-#endif
 	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) {
-				__init_pmd(page);
-				pgd_set(pgd, page);
-				return page + address;
-			}
-			pgd_set(pgd, BAD_PMD);
-			return NULL;
-		}
-		free_page((unsigned long) page);
-	}
-#ifdef PGTABLE_SANITY_CHECKS
-	if (pgd_bad(*pgd)) {
-		printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
-		pgd_set(pgd, BAD_PMD);
-		return NULL;
+		pmd_t *page = get_pmd_fast();
+
+		if (!page)
+			return get_pmd_slow(pgd, address);
+		pgd_set(pgd, page);
+		return page + address;
 	}
-#endif
 	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)
-{
-	extern void __bfill64(void *, unsigned long *);
-	pgd_t *pgd = (pgd_t *) __get_free_page(GFP_KERNEL);
-	
-	if (pgd)
-		__bfill64((void *)pgd, &null_pmd_table);
-	return pgd;
-}
+#define pte_alloc_kernel(pmd, addr)	pte_alloc(pmd, addr)
+#define pmd_alloc_kernel(pgd, addr)	pmd_alloc(pgd, addr)
 
 extern pgd_t swapper_pg_dir[1024];
 
@@ -505,22 +488,18 @@
 extern __u32 mmu_get_scsi_one(char *, unsigned long, struct linux_sbus *sbus);
 extern void  mmu_get_scsi_sgl(struct mmu_sglist *, int, struct linux_sbus *sbus);
 
+extern void mmu_release_scsi_one(u32 vaddr, unsigned long len,
+				 struct linux_sbus *sbus);
+extern void mmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus);
+
+#define NEED_DMA_SYNCHRONIZATION
+#define mmu_sync_dma(dma_addr, len, sbus_instance)	\
+	mmu_release_scsi_one((dma_addr), (len), (sbus_instance))
+
 /* These do nothing with the way I have things setup. */
-#define mmu_release_scsi_one(vaddr, len, sbus)	do { } while(0)
-#define mmu_release_scsi_sgl(sg, sz, sbus)	do { } while(0)
 #define mmu_lockarea(vaddr, len)		(vaddr)
 #define mmu_unlockarea(vaddr, len)		do { } while(0)
-
-extern void fixup_dcache_alias(struct vm_area_struct *vma, unsigned long address,
-			       pte_t pte);
-
-extern inline void update_mmu_cache(struct vm_area_struct * vma,
-	unsigned long address, pte_t pte)
-{
-	/* Find and fix bad virutal cache aliases. */
-	if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED))
-		fixup_dcache_alias(vma, address, pte);
-}
+#define update_mmu_cache(vma, address, pte)	do { } while(0)
 
 /* Make a non-present pseudo-TTE. */
 extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/psycho.h linux/include/asm-sparc64/psycho.h
--- v2.1.50/linux/include/asm-sparc64/psycho.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/psycho.h	Sat Aug 16 09:51:10 1997
@@ -0,0 +1,350 @@
+/* $Id: psycho.h,v 1.2 1997/08/11 14:35:40 davem Exp $
+ * psycho.h: UltraSparc AX specific PCI definitions.
+ *
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ */
+
+#ifndef __SPARC64_PSYCHO_H
+#define __SPARC64_PSYCHO_H
+
+#include <linux/types.h>
+
+/* Ultra AX PSYCHO Register Set, one per controller probed. */
+struct psycho_regs {
+/*0x0000*/	u64	upa_id;		/* PSYCHO UPA Port ID Register	*/
+/*0x0008*/	u64	upa_cfg;	/* PSYCHO UPA Config Register	*/
+/*0x0010*/	u64	control;	/* PSYCHO Control Register	*/
+/*0x0018*/	u64	__pad0;
+/*0x0020*/	u64	ecc_control;	/* ECC Control Register		*/
+/*0x0028*/	u64	__pad1;
+
+		/* Uncorrectable Error Fault Registers */
+/*0x0030*/	u64	ue_afsr;	/* UE Async Fault Status	*/
+/*0x0038*/	u64	ue_afar;	/* UE Async Fault Address	*/
+
+		/* Correctable Error Fault Registers */
+/*0x0040*/	u64	ce_afsr;	/* CE Async Fault Status	*/
+/*0x0048*/	u64	ce_afar;	/* CE Async Fault Address	*/
+
+		u64	__pad2[0x16];
+
+		/* Performance Monitoring Registers */
+/*0x0100*/	u64	pmon_control;
+/*0x0108*/	u64	pmon_counter;
+
+		u64	__pad3[0x1e];
+
+		/* PCI Bus IOMMU lives here */
+/*0x0200*/	u64	iommu_control;	/* IOMMU Control		*/
+/*0x0208*/	u64	iommu_tsbbase;	/* IOMMU TSB Base		*/
+/*0x0210*/	u64	iommu_flush;	/* IOMMU Flush Register		*/
+
+		u64	__pad4[0x13d];
+
+		/* Interrupt mapping/control registers */
+/*0x0c00*/	u64	imap_a_slot0;	/* PCI A Slot 0 Int Mapping */
+/*0x0c08*/	u64	imap_a_slot1;	/* PCI A Slot 1 Int Mapping */
+
+		u64	__pad5[0x2];
+
+/*0x0c20*/	u64	imap_b_slot0;	/* PCI B Slot 0 Int Mapping */
+/*0x0c28*/	u64	imap_b_slot1;	/* PCI B Slot 1 Int Mapping */
+/*0x0c30*/	u64	imap_b_slot2;	/* PCI B Slot 2 Int Mapping */
+/*0x0c38*/	u64	imap_b_slot3;	/* PCI B Slot 3 Int Mapping */
+
+		u64	__pad6[0x78];
+
+/*0x1000*/	u64	imap_scsi;	/* SCSI Int Mapping	*/
+/*0x1008*/	u64	imap_eth;	/* Ethernet Int Mapping	*/
+/*0x1010*/	u64	imap_bpp;	/* Parallel Port Int Mapping */
+/*0x1018*/	u64	imap_au_rec;	/* Audio Record Int Mapping */
+/*0x1020*/	u64	imap_au_play;	/* Audio Playback Int Mapping */
+/*0x1028*/	u64	imap_pfail;	/* Power Fail Int Mapping */
+/*0x1030*/	u64	imap_kms;	/* Kbd/Mouse/Ser Int Mapping */
+/*0x1038*/	u64	imap_flpy;	/* Floppy Int Mapping	 */
+/*0x1040*/	u64	imap_shw;	/* Spare HW Int Mapping	*/
+/*0x1048*/	u64	imap_kbd;	/* Kbd Only Int Mapping	*/
+/*0x1050*/	u64	imap_ms;	/* Mouse Only Int Mapping */
+/*0x1058*/	u64	imap_ser;	/* Serial Only Int Mapping */
+/*0x1060*/	u64	imap_tim0;	/* Timer 0 Int Mapping	*/
+/*0x1068*/	u64	imap_tim1;	/* Timer 1 Int Mapping	*/
+/*0x1070*/	u64	imap_ue;	/* UE Int Mapping	*/
+/*0x1078*/	u64	imap_ce;	/* CE Int Mapping	*/
+/*0x1080*/	u64	imap_a_err;	/* PCI A Err Int Mapping */
+/*0x1088*/	u64	imap_b_err;	/* PCI B Err Int Mapping */
+/*0x1090*/	u64	imap_pmgmt;	/* Power Mgmt Int Mapping */
+/*0x1098*/	u64	imap_gfx;	/* OB Graphics Int Mapping */
+/*0x10a0*/	u64	imap_eupa;	/* UPA Expansion Int Mapping */
+
+		u64	__pad7[0x6b];
+
+		/* Interrupt Clear Registers */
+/*0x1400*/	u64	iclr_a_slot0[4];	/* PCI A Slot 0 Clear Int Reg */
+/*0x1420*/	u64	iclr_a_slot1[4];	/* PCI A Slot 1 Clear Int Reg */
+
+		u64	__pad8[0x8];
+
+/*0x1480*/	u64	iclr_b_slot0[4];	/* PCI B Slot 0 Clear Int Reg */
+/*0x14a0*/	u64	iclr_b_slot1[4];	/* PCI B Slot 1 Clear Int Reg */
+/*0x14c0*/	u64	iclr_b_slot2[4];	/* PCI B Slot 2 Clear Int Reg */
+/*0x14e0*/	u64	iclr_b_slot3[4];	/* PCI B Slot 3 Clear Int Reg */
+
+		u64	__pad9[0x60];
+
+/*0x1800*/	u64	iclr_scsi;
+/*0x1808*/	u64	iclr_eth;
+/*0x1810*/	u64	iclr_bpp;
+/*0x1818*/	u64	iclr_au_rec;
+/*0x1820*/	u64	iclr_au_play;
+/*0x1828*/	u64	iclr_pfail;
+/*0x1830*/	u64	iclr_kms;
+/*0x1838*/	u64	iclr_flpy;
+/*0x1840*/	u64	iclr_shw;
+/*0x1848*/	u64	iclr_kbd;
+/*0x1850*/	u64	iclr_ms;
+/*0x1858*/	u64	iclr_ser;
+/*0x1860*/	u64	iclr_tim0;
+/*0x1868*/	u64	iclr_tim1;
+/*0x1870*/	u64	iclr_ue;
+/*0x1878*/	u64	iclr_ce;
+/*0x1880*/	u64	iclr_a_err;
+/*0x1888*/	u64	iclr_b_err;
+/*0x1890*/	u64	iclr_pmgmt;
+
+		u64	__pad10[0x2d];
+
+		/* Interrupt Retry Timer. */
+/*0x1a00*/	u64	irq_retry;
+
+		u64	__pad11[0x3f];
+
+		/* Counters/Timers */
+/*0x1c00*/	u64	tim0_cnt;
+/*0x1c08*/	u64	tim0_lim;
+/*0x1c10*/	u64	tim1_cnt;
+/*0x1c18*/	u64	tim1_lim;
+
+		u64	__pad12[0x7c];
+
+		/* PCI Bus A Registers */
+/*0x2000*/	u64	pci_a_control;	/* PCI Bus A Control Register	*/
+/*0x2008*/	u64	__pad13;
+/*0x2010*/	u64	pci_a_afsr;	/* PCI Bus A Async Fault Status	*/
+/*0x2018*/	u64	pci_a_afar;	/* PCI Bus A Async Fault Address*/
+/*0x2020*/	u64	pci_a_diag;	/* PCI Bus A Diag Register	*/
+
+		u64	__pad14[0xfb];
+
+		/* PCI Bus A/IOMMU Streaming Buffer Registers */
+/*0x2800*/	u64	sbuf_a_control;	/* StrBuffer Control		*/
+/*0x2808*/	u64	sbuf_a_pflush;	/* StrBuffer Page Flush		*/
+/*0x2810*/	u64	sbuf_a_fsync;	/* StrBuffer Flush Sync Reg	*/
+
+		u64	__pad15[0x2fd];
+
+		/* PCI Bus B Registers */
+/*0x4000*/	u64	pci_b_control;	/* PCI Bus B Control Register	*/
+/*0x4008*/	u64	__pad16;
+/*0x4010*/	u64	pci_b_afsr;	/* PCI Bus B Async Fault Status	*/
+/*0x4018*/	u64	pci_b_afar;	/* PCI Bus B Async Fault Address*/
+/*0x4020*/	u64	pci_b_diag;	/* PCI Bus B Diag Register	*/
+
+		u64	__pad17[0x7b];
+
+		/* IOMMU diagnostic things */
+/*0x4400*/	u64	iommu_vdiag;	/* VADDR Diagnostic Register	*/
+/*0x4408*/	u64	iommu_tcompare;	/* IOMMU TLB Tag Compare	*/
+
+		u64	__pad18[0x7e];
+
+		/* PCI Bus B/IOMMU Streaming Buffer Registers */
+/*0x4800*/	u64	sbuf_b_control;	/* StrBuffer Control		*/
+/*0x4808*/	u64	sbuf_b_pflush;	/* StrBuffer Page Flush		*/
+/*0x4810*/	u64	sbuf_b_fsync;	/* StrBuffer Flush Sync Reg	*/
+
+		u64	__pad19[0xafd];
+
+		/* DMA Scoreboard Diagnostic Registers */
+/*0xa000*/	u64	dscore_reg0;	/* DMA Scoreboard Diag Reg 0	*/
+/*0xa008*/	u64	dscore_reg1;	/* DMA Scoreboard Diag Reg 1	*/
+
+		u64	__pad20[0x9e];
+
+		/* More IOMMU diagnostic things */
+/*0xa500*/	u64	iommu_lru[16];	/* IOMMU LRU Queue Diag		*/
+/*0xa580*/	u64	iommu_tag[16];	/* IOMMU TLB Tag Diag		*/
+/*0xa600*/	u64	iommu_data[16];	/* IOMMU TLB Data RAM Diag	*/
+
+		u64	__pad21[0x30];
+
+		/* Interrupt State Diagnostics */
+/*0xa800*/	u64	pci_istate;
+/*0xa808*/	u64	obio_istate;
+
+		u64	__pad22[0xfe];
+
+		/* Streaming Buffer A Diagnostic Area */
+/*0xb000*/	u64	sbuf_a_data[128]; /* StrBuffer Data Ram Diag	*/
+/*0xb400*/	u64	sbuf_a_errs[128]; /* StrBuffer Error Status Diag*/
+/*0xb800*/	u64	sbuf_a_ptag[16]; /* StrBuffer Page Tag Diag	*/
+/*0xb880*/	u64	__pad23[16];
+/*0xb900*/	u64	sbuf_a_ltag[16]; /* StrBuffer Line Tag Diag	*/
+
+		u64	__pad24[0xd0];
+
+		/* Streaming Buffer B Diagnostic Area */
+/*0xc000*/	u64	sbuf_b_data[128]; /* StrBuffer Data Ram Diag	*/
+/*0xc400*/	u64	sbuf_b_errs[128]; /* StrBuffer Error Status Diag*/
+/*0xc800*/	u64	sbuf_b_ptag[16]; /* StrBuffer Page Tag Diag	*/
+/*0xc880*/	u64	__pad25[16];
+/*0xc900*/	u64	sbuf_b_ltag[16]; /* StrBuffer Line Tag Diag	*/
+};
+
+/* PSYCHO UPA Port ID */
+#define PSYCHO_UPPID_FESC	0xff00000000000000 /* FCode escape, 0xfc           */
+#define PSYCHO_UPPID_RESV1	0x00fffff800000000 /* Reserved                     */
+#define PSYCHO_UPPID_ENV	0x0000000400000000 /* Cannot generate ECC          */
+#define PSYCHO_UPPID_ORD	0x0000000200000000 /* One Outstanding Read         */
+#define PSYCHO_UPPID_RESV2	0x0000000180000000 /* Reserved                     */
+#define PSYCHO_UPPID_PDQ	0x000000007e000000 /* Data Queue size              */
+#define PSYCHO_UPPID_PRQ	0x0000000001e00000 /* Request Queue size           */
+#define PSYCHO_UPPID_UCAP	0x00000000001f0000 /* UPA Capabilities             */
+#define PSYCHO_UPPID_JEDEC	0x000000000000ffff /* JEDEC ID for PSYCHO          */
+
+/* PSYCHO UPA Configuration Register */
+#define PSYCHO_UPCFG_RESV	0xffffffffffffff00 /* Reserved                     */
+#define PSYCHO_UPCFG_SCIQ1	0x00000000000000f0 /* Unused, always zero          */
+#define PSYCHO_UPCFG_SCIQ2	0x000000000000000f /* Requests Queue size 0x2 	   */
+
+/* PSYCHO Control Register */
+#define PSYCHO_CONTROL_IMPL	0xf000000000000000 /* Implementation of this PSYCHO*/
+#define PSYCHO_CONTROL_VER	0x0f00000000000000 /* Version of this PSYCHO       */
+#define PSYCHO_CONTROL_MID	0x00f8000000000000 /* UPA Module ID of PSYCHO      */
+#define PSYCHO_CONTROL_IGN	0x0007c00000000000 /* Interrupt Group Number       */
+#define PSYCHO_CONTROL_RESV     0x00003ffffffffff0 /* Reserved                     */
+#define PSYCHO_CONTROL_APCKEN	0x0000000000000008 /* Address Parity Check Enable  */
+#define PSYCHO_CONTROL_APERR	0x0000000000000004 /* Incoming System Addr Parerr  */
+#define PSYCHO_CONTROL_IAP	0x0000000000000002 /* Invert UPA Parity            */
+#define PSYCHO_CONTROL_MODE	0x0000000000000001 /* PSYCHO clock mode            */
+
+/* PSYCHO ECC Control Register */
+#define PSYCHO_ECNTRL_ECCEN	0x8000000000000000 /* Enable ECC Checking	   */
+#define PSYCHO_ECNTRL_UEEN	0x4000000000000000 /* Enable UE Interrupts         */
+#define PSYCHO_ECNTRL_CEEN	0x2000000000000000 /* Enable CE Interrupts         */
+
+/* Uncorrectable Error AFSR, AFAR holds low 40bits of faulting physical address. */
+#define PSYCHO_UEAFSR_PPIO	0x8000000000000000 /* Primary PIO is cause         */
+#define PSYCHO_UEAFSR_PDRD	0x4000000000000000 /* Primary DVMA read is cause   */
+#define PSYCHO_UEAFSR_PDWR	0x2000000000000000 /* Primary DVMA write is cause  */
+#define PSYCHO_UEAFSR_SPIO	0x1000000000000000 /* Secondary PIO is cause       */
+#define PSYCHO_UEAFSR_SDRD	0x0800000000000000 /* Secondary DVMA read is cause */
+#define PSYCHO_UEAFSR_SDWR	0x0400000000000000 /* Secondary DVMA write is cause*/
+#define PSYCHO_UEAFSR_RESV1	0x03ff000000000000 /* Reserved                     */
+#define PSYCHO_UEAFSR_BMSK	0x0000ffff00000000 /* Bytemask of failed transfer  */
+#define PSYCHO_UEAFSR_DOFF	0x00000000e0000000 /* Doubleword Offset            */
+#define PSYCHO_UEAFSR_MID	0x000000001f000000 /* UPA MID causing the fault    */
+#define PSYCHO_UEAFSR_BLK	0x0000000000800000 /* Trans was block operation    */
+#define PSYCHO_UEAFSR_RESV2	0x00000000007fffff /* Reserved                     */
+
+/* Correctable Error AFSR, AFAR holds low 40bits of faulting physical address. */
+#define PSYCHO_CEAFSR_PPIO	0x8000000000000000 /* Primary PIO is cause         */
+#define PSYCHO_CEAFSR_PDRD	0x4000000000000000 /* Primary DVMA read is cause   */
+#define PSYCHO_CEAFSR_PDWR	0x2000000000000000 /* Primary DVMA write is cause  */
+#define PSYCHO_CEAFSR_SPIO	0x1000000000000000 /* Secondary PIO is cause       */
+#define PSYCHO_CEAFSR_SDRD	0x0800000000000000 /* Secondary DVMA read is cause */
+#define PSYCHO_CEAFSR_SDWR	0x0400000000000000 /* Secondary DVMA write is cause*/
+#define PSYCHO_CEAFSR_RESV1	0x0300000000000000 /* Reserved                     */
+#define PSYCHO_CEAFSR_ESYND	0x00ff000000000000 /* Syndrome Bits                */
+#define PSYCHO_UEAFSR_SIZE	0x0000ffff00000000 /* Bytemask of failed transfer  */
+#define PSYCHO_CEAFSR_DOFF	0x00000000e0000000 /* Double Offset                */
+#define PSYCHO_CEAFSR_MID	0x000000001f000000 /* UPA MID causing the fault    */
+#define PSYCHO_CEAFSR_BLK	0x0000000000800000 /* Trans was block operation    */
+#define PSYCHO_CEAFSR_RESV2	0x00000000007fffff /* Reserved                     */
+
+/* DMA Scoreboard Diagnostic Register(s) */
+#define PSYCHO_DSCORE_VALID	0x8000000000000000 /* Entry is valid               */
+#define PSYCHO_DSCORE_C		0x4000000000000000 /* Transaction cacheable        */
+#define PSYCHO_DSCORE_READ	0x2000000000000000 /* Transaction was a read       */
+#define PSYCHO_DSCORE_TAG	0x1f00000000000000 /* Transaction ID               */
+#define PSYCHO_DSCORE_ADDR	0x00fffffffff80000 /* Transaction PADDR            */
+#define PSYCHO_DSCORE_BMSK	0x000000000007fff8 /* Bytemask of pending transfer */
+#define PSYCHO_DSCORE_SRC	0x0000000000000007 /* Transaction source           */
+
+/* PSYCHO PCI Control Register */
+#define PSYCHO_PCICTRL_RESV1	0xfffffff000000000 /* Reserved                     */
+#define PSYCHO_PCICTRL_SBH_ERR	0x0000000800000000 /* Streaming byte hole error    */
+#define PSYCHO_PCICTRL_SERR	0x0000000400000000 /* SERR signal asserted         */
+#define PSYCHO_PCICTRL_SPEED	0x0000000200000000 /* PCI speed (1 is U2P clock)   */
+#define PSYCHO_PCICTRL_RESV2	0x00000001ffc00000 /* Reserved                     */
+#define PSYCHO_PCICTRL_ARB_PARK	0x0000000000200000 /* PCI arbitration parking      */
+#define PSYCHO_PCICTRL_RESV3	0x00000000001ff800 /* Reserved                     */
+#define PSYCHO_PCICTRL_SBH_INT	0x0000000000000400 /* Streaming byte hole int enab */
+#define PSYCHO_PCICTRL_WEN	0x0000000000000200 /* Power Mgmt Wake Enable       */
+#define PSYCHO_PCICTRL_EEN	0x0000000000000100 /* PCI Error Interrupt Enable   */
+#define PSYCHO_PCICTRL_RESV4	0x00000000000000c0 /* Reserved                     */
+#define PSYCHO_PCICTRL_AEN	0x000000000000003f /* PCI DVMA Arbitration Enable  */
+
+/* PSYCHO PCI AFSR, AFAR holds low 40 bits of physical address causing the fault. */
+#define PSYCHO_PCIAFSR_PMA	0x8000000000000000 /* Primary Master Abort Error   */
+#define PSYCHO_PCIAFSR_PTA	0x4000000000000000 /* Primary Target Abort Error   */
+#define PSYCHO_PCIAFSR_PRTRY	0x2000000000000000 /* Primary Excessive Retries    */
+#define PSYCHO_PCIAFSR_PPERR	0x1000000000000000 /* Primary Parity Error         */
+#define PSYCHO_PCIAFSR_SMA	0x0800000000000000 /* Secondary Master Abort Error */
+#define PSYCHO_PCIAFSR_STA	0x0400000000000000 /* Secondary Target Abort Error */
+#define PSYCHO_PCIAFSR_SRTRY	0x0200000000000000 /* Secondary Excessive Retries  */
+#define PSYCHO_PCIAFSR_SPERR	0x0100000000000000 /* Secondary Parity Error       */
+#define PSYCHO_PCIAFSR_RESV1	0x00ff000000000000 /* Reserved                     */
+#define PSYCHO_PCIAFSR_SIZE	0x0000ffff00000000 /* Bytemask of failed transfer  */
+#define PSYCHO_PCIAFSR_BLK	0x0000000080000000 /* Trans was block operation    */
+#define PSYCHO_PCIAFSR_RESV2	0x0000000040000000 /* Reserved                     */
+#define PSYCHO_PCIAFSR_MID	0x000000003e000000 /* MID causing the error        */
+#define PSYCHO_PCIAFSR_RESV3	0x0000000001ffffff /* Reserved                     */
+
+/* IOMMU things defined fully in asm-sparc64/iommu.h */
+
+/* Streaming Buffer Control Register */
+#define PSYCHO_SBUFCTRL_RESV	0xffffffffffffff80 /* Reserved                     */
+#define PSYCHO_SBUFCTRL_LRU_LP	0x0000000000000070 /* LRU Lock Pointer             */
+#define PSYCHO_SBUFCTRL_LRU_LE	0x0000000000000008 /* LRU Lock Enable              */
+#define PSYCHO_SBUFCTRL_RR_DIS	0x0000000000000004 /* Rerun Disable                */
+#define PSYCHO_SBUFCTRL_DE	0x0000000000000002 /* Diag Mode Enable             */
+#define PSYCHO_SBUFCTRL_SB_EN	0x0000000000000001 /* Streaming Buffer Enable      */
+
+/* Streaming Buffer Page Invalidate/Flush Register */
+#define PSYCHO_SBUFFLUSH_ADDR	0x00000000ffffe000 /* DVMA Page to be flushed      */
+#define PSYCHO_SBUFFLUSH_RESV	0x0000000000001fff /* Ignored bits                 */
+
+/* Streaming Buffer Flush Synchronization Register */
+#define PSYCHO_SBUFSYNC_ADDR	0x000001ffffffffc0 /* Physical address to update   */
+#define PSYCHO_SBUFSYNC_RESV	0x000000000000003f /* Ignored bits                 */
+
+/* PSYCHO Interrupt mapping register(s). */
+#define PSYCHO_IMAP_RESV1	0xffffffff00000000 /* Reserved                     */
+#define PSYCHO_IMAP_VALID	0x0000000080000000 /* This enables delivery.	   */
+#define PSYCHO_IMAP_TID		0x000000007c000000 /* Target ID (MID to send it to)*/
+#define PSYCHO_IMAP_RESV2	0x0000000003fff800 /* Reserved 			   */
+#define PSYCHO_IMAP_IGN		0x00000000000007c0 /* Interrupt Group Number.	   */
+#define PSYCHO_IMAP_INO		0x000000000000003f /* Interrupt Number Offset.	   */
+#define PSYCHO_IMAP_INR		0x00000000000007ff /* Interrupt # (Gfx/UPA_slave)  */
+
+/* PSYCHO Interrupt clear pseudo register(s). */
+#define PSYCHO_ICLR_RESV1 	0xfffffffffffffff0 /* Reserved			   */
+#define PSYCHO_ICLR_IDLE	0x0000000000000000 /* Transition to idle state.	   */
+#define PSYCHO_ICLR_TRANSMIT	0x0000000000000001 /* Transition to transmit state */
+#define PSYCHO_ICLR_RESV2	0x0000000000000002 /* Reserved.			   */
+#define PSYCHO_ICLR_PENDING	0x0000000000000003 /* Transition to pending state. */
+
+/* PSYCHO Interrupt Retry Timer register. */
+#define PSYCHO_IRETRY_LIMIT	0x00000000000fffff /* The retry interval.	   */
+
+/* PSYCHO Interrupt State registers. XXX fields to be documented later */
+
+/* PSYCHO Counter register. XXX fields to be documented later */
+
+/* PSYCHO Limit register. XXX fields to be documented later */
+
+/* PSYCHO Performance Monitor Control register. XXX fields to be documented later */
+
+/* PSYCHO Performance Monitor Counter register. XXX fields to be documented later */
+
+#endif /* !(__SPARC64_PSYCHO_H) */
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/sab82532.h linux/include/asm-sparc64/sab82532.h
--- v2.1.50/linux/include/asm-sparc64/sab82532.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/sab82532.h	Sat Aug 16 09:51:10 1997
@@ -0,0 +1,371 @@
+/* $Id: sab82532.h,v 1.2 1997/08/12 04:13:15 ecd Exp $
+ * sab82532.h: Register Definitions for the Siemens SAB82532 DUSCC
+ *
+ * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
+ */
+
+#ifndef _SPARC64_SAB82532_H
+#define _SPARC64_SAB82532_H
+
+#include <linux/types.h>
+#include <linux/serial.h>
+
+struct sab82532_async_rd_regs {
+	u8	rfifo[0x20];	/* Receive FIFO				*/
+	u8	star;		/* Status Register			*/
+	u8	__pad1;
+	u8	mode;		/* Mode Register			*/
+	u8	timr;		/* Timer Register			*/
+	u8	xon;		/* XON Character			*/
+	u8	xoff;		/* XOFF Character			*/
+	u8	tcr;		/* Termination Character Register	*/
+	u8	dafo;		/* Data Format				*/
+	u8	rfc;		/* RFIFO Control Register		*/
+	u8	__pad2;
+	u8	rbcl;		/* Receive Byte Count Low		*/
+	u8	rbch;		/* Receive Byte Count High		*/
+	u8	ccr0;		/* Channel Configuration Register 0	*/
+	u8	ccr1;		/* Channel Configuration Register 1	*/
+	u8	ccr2;		/* Channel Configuration Register 2	*/
+	u8	ccr3;		/* Channel Configuration Register 3	*/
+	u8	__pad3[4];
+	u8	vstr;		/* Version Status Register		*/
+	u8	__pad4[3];
+	u8	gis;		/* Global Interrupt Status		*/
+	u8	ipc;		/* Interrupt Port Configuration		*/
+	u8	isr0;		/* Interrupt Status 0			*/
+	u8	isr1;		/* Interrupt Status 1			*/
+	u8	pvr;		/* Port Value Register			*/
+	u8	pis;		/* Port Interrupt Status		*/
+	u8	pcr;		/* Port Configuration Register		*/
+	u8	ccr4;		/* Channel Configuration Register 4	*/
+};
+
+struct sab82532_async_wr_regs {
+	u8	xfifo[0x20];	/* Transmit FIFO			*/
+	u8	cmdr;		/* Command Register			*/
+	u8	__pad1;
+	u8	mode;
+	u8	timr;
+	u8	xon;
+	u8	xoff;
+	u8	tcr;
+	u8	dafo;
+	u8	rfc;
+	u8	__pad2;
+	u8	xbcl;		/* Transmit Byte Count Low		*/
+	u8	xbch;		/* Transmit Byte Count High		*/
+	u8	ccr0;
+	u8	ccr1;
+	u8	ccr2;
+	u8	ccr3;
+	u8	tsax;		/* Time-Slot Assignment Reg. Transmit	*/
+	u8	tsar;		/* Time-Slot Assignment Reg. Receive	*/
+	u8	xccr;		/* Transmit Channel Capacity Register	*/
+	u8	rccr;		/* Receive Channel Capacity Register	*/
+	u8	bgr;		/* Baud Rate Generator Register		*/
+	u8	tic;		/* Transmit Immediate Character		*/
+	u8	mxn;		/* Mask XON Character			*/
+	u8	mxf;		/* Mask XOFF Character			*/
+	u8	iva;		/* Interrupt Vector Address		*/
+	u8	ipc;
+	u8	imr0;		/* Interrupt Mask Register 0		*/
+	u8	imr1;		/* Interrupt Mask Register 1		*/
+	u8	pvr;
+	u8	pim;		/* Port Interrupt Mask			*/
+	u8	pcr;
+	u8	ccr4;
+};
+
+struct sab82532_async_rw_regs {	/* Read/Write registers			*/
+	u8	__pad1[0x20];
+	u8	__pad2;
+	u8	__pad3;
+	u8	mode;
+	u8	timr;
+	u8	xon;
+	u8	xoff;
+	u8	tcr;
+	u8	dafo;
+	u8	rfc;
+	u8	__pad4;
+	u8	__pad5;
+	u8	__pad6;
+	u8	ccr0;
+	u8	ccr1;
+	u8	ccr2;
+	u8	ccr3;
+	u8	__pad7;
+	u8	__pad8;
+	u8	__pad9;
+	u8	__pad10;
+	u8	__pad11;
+	u8	__pad12;
+	u8	__pad13;
+	u8	__pad14;
+	u8	__pad15;
+	u8	ipc;
+	u8	__pad16;
+	u8	__pad17;
+	u8	pvr;
+	u8	__pad18;
+	u8	pcr;
+	u8	ccr4;
+};
+
+union sab82532_async_regs {
+	__volatile__ struct sab82532_async_rd_regs	r;
+	__volatile__ struct sab82532_async_wr_regs	w;
+	__volatile__ struct sab82532_async_rw_regs	rw;
+};
+
+#define NR_PORTS			 2
+
+union sab82532_irq_status {
+	unsigned long			 stat;
+	struct {
+		unsigned char		 isr0;
+		unsigned char		 isr1;
+		unsigned char		 ddsr;
+	} sreg;
+};
+
+struct sab82532 {
+	int				 magic;
+	int				 baud_base;
+	union sab82532_async_regs	*regs;
+	int				 irq;
+	int				 flags;		/* defined in tty.h */
+	int				 type;		/* SAB82532 version */
+	struct tty_struct		*tty;
+	int				 read_status_mask;
+	int				 ignore_status_mask;
+	int				 timeout;
+	int				 xmit_fifo_size;
+	int				 custom_divisor;
+	int				 quot;
+	int				 x_char;
+	int				 close_delay;
+	unsigned short			 closing_wait;
+	unsigned short			 closing_wait2;
+	int				 all_sent;
+	int				 is_console;
+	unsigned char			 interrupt_mask0;
+	unsigned char			 interrupt_mask1;
+	unsigned char			 pvr_dtr_bit;
+	unsigned char			 pvr_dsr_bit;
+	unsigned long			 event;
+	unsigned long			 last_active;
+	int				 line;
+	int				 count;
+	int				 blocked_open;
+	long				 session;
+	long				 pgrp;
+	unsigned char			*xmit_buf;
+	int				 xmit_head;
+	int				 xmit_tail;
+	int				 xmit_cnt;
+	struct tq_struct		 tqueue;
+	struct tq_struct		 tqueue_hangup;
+	struct async_icount		 icount;
+	struct termios			 normal_termios;
+	struct termios			 callout_termios;
+	struct wait_queue		*open_wait;
+	struct wait_queue		*close_wait;
+	struct wait_queue		*delta_msr_wait;
+	struct sab82532			*next;
+	struct sab82532			*prev;
+};
+
+
+/* RFIFO Status Byte */
+#define SAB82532_RSTAT_PE		0x80
+#define SAB82532_RSTAT_FE		0x40
+#define SAB82532_RSTAT_PARITY		0x01
+
+/* Status Register (STAR) */
+#define SAB82532_STAR_XDOV		0x80
+#define SAB82532_STAR_XFW		0x40
+#define SAB82532_STAR_RFNE		0x20
+#define SAB82532_STAR_FCS		0x10
+#define SAB82532_STAR_TEC		0x08
+#define SAB82532_STAR_CEC		0x04
+#define SAB82532_STAR_CTS		0x02
+
+/* Command Register (CMDR) */
+#define SAB82532_CMDR_RMC		0x80
+#define SAB82532_CMDR_RRES		0x40
+#define SAB82532_CMDR_RFRD		0x20
+#define SAB82532_CMDR_STI		0x10
+#define SAB82532_CMDR_XF		0x08
+#define SAB82532_CMDR_XRES		0x01
+
+/* Mode Register (MODE) */
+#define SAB82532_MODE_FRTS		0x40
+#define SAB82532_MODE_FCTS		0x20
+#define SAB82532_MODE_FLON		0x10
+#define SAB82532_MODE_RAC		0x08
+#define SAB82532_MODE_RTS		0x04
+#define SAB82532_MODE_TRS		0x02
+#define SAB82532_MODE_TLP		0x01
+
+/* Timer Register (TIMR) */
+#define SAB82532_TIMR_CNT_MASK		0xe0
+#define SAB82532_TIMR_VALUE_MASK	0x1f
+
+/* Data Format (DAFO) */
+#define SAB82532_DAFO_XBRK		0x40
+#define SAB82532_DAFO_STOP		0x20
+#define SAB82532_DAFO_PAR_SPACE		0x00
+#define SAB82532_DAFO_PAR_ODD		0x08
+#define SAB82532_DAFO_PAR_EVEN		0x10
+#define SAB82532_DAFO_PAR_MARK		0x18
+#define SAB82532_DAFO_PARE		0x04
+#define SAB82532_DAFO_CHL8		0x00
+#define SAB82532_DAFO_CHL7		0x01
+#define SAB82532_DAFO_CHL6		0x02
+#define SAB82532_DAFO_CHL5		0x03
+
+/* RFIFO Control Register (RFC) */
+#define SAB82532_RFC_DPS		0x40
+#define SAB82532_RFC_DXS		0x20
+#define SAB82532_RFC_RFDF		0x10
+#define SAB82532_RFC_RFTH_1		0x00
+#define SAB82532_RFC_RFTH_4		0x04
+#define SAB82532_RFC_RFTH_16		0x08
+#define SAB82532_RFC_RFTH_32		0x0c
+#define SAB82532_RFC_TCDE		0x01
+
+/* Received Byte Count High (RBCH) */
+#define SAB82532_RBCH_DMA		0x80
+#define SAB82532_RBCH_CAS		0x20
+
+/* Transmit Byte Count High (XBCH) */
+#define SAB82532_XBCH_DMA		0x80
+#define SAB82532_XBCH_CAS		0x20
+#define SAB82532_XBCH_XC		0x10
+
+/* Channel Configuration Register 0 (CCR0) */
+#define SAB82532_CCR0_PU		0x80
+#define SAB82532_CCR0_MCE		0x40
+#define SAB82532_CCR0_SC_NRZ		0x00
+#define SAB82532_CCR0_SC_NRZI		0x08
+#define SAB82532_CCR0_SC_FM0		0x10
+#define SAB82532_CCR0_SC_FM1		0x14
+#define SAB82532_CCR0_SC_MANCH		0x18
+#define SAB82532_CCR0_SM_HDLC		0x00
+#define SAB82532_CCR0_SM_SDLC_LOOP	0x01
+#define SAB82532_CCR0_SM_BISYNC		0x02
+#define SAB82532_CCR0_SM_ASYNC		0x03
+
+/* Channel Configuration Register 1 (CCR1) */
+#define SAB82532_CCR1_ODS		0x10
+#define SAB82532_CCR1_BCR		0x08
+#define SAB82532_CCR1_CM_MASK		0x07
+
+/* Channel Configuration Register 2 (CCR2) */
+#define SAB82532_CCR2_SOC1		0x80
+#define SAB82532_CCR2_SOC0		0x40
+#define SAB82532_CCR2_BR9		0x80
+#define SAB82532_CCR2_BR8		0x40
+#define SAB82532_CCR2_BDF		0x20
+#define SAB82532_CCR2_SSEL		0x10
+#define SAB82532_CCR2_XCS0		0x20
+#define SAB82532_CCR2_RCS0		0x10
+#define SAB82532_CCR2_TOE		0x08
+#define SAB82532_CCR2_RWX		0x04
+#define SAB82532_CCR2_DIV		0x01
+
+/* Channel Configuration Register 3 (CCR3) */
+#define SAB82532_CCR3_PSD		0x01
+
+/* Time Slot Assignment Register Transmit (TSAX) */
+#define SAB82532_TSAX_TSNX_MASK		0xfc
+#define SAB82532_TSAX_XCS2		0x02	/* see also CCR2 */
+#define SAB82532_TSAX_XCS1		0x01
+
+/* Time Slot Assignment Register Receive (TSAR) */
+#define SAB82532_TSAR_TSNR_MASK		0xfc
+#define SAB82532_TSAR_RCS2		0x02	/* see also CCR2 */
+#define SAB82532_TSAR_RCS1		0x01
+
+/* Version Status Register (VSTR) */
+#define SAB82532_VSTR_CD		0x80
+#define SAB82532_VSTR_DPLA		0x40
+#define SAB82532_VSTR_VN_MASK		0x0f
+#define SAB82532_VSTR_VN_1		0x00
+#define SAB82532_VSTR_VN_2		0x01
+#define SAB82532_VSTR_VN_3_2		0x02
+
+/* Global Interrupt Status Register (GIS) */
+#define SAB82532_GIS_PI			0x80
+#define SAB82532_GIS_ISA1		0x08
+#define SAB82532_GIS_ISA0		0x04
+#define SAB82532_GIS_ISB1		0x02
+#define SAB82532_GIS_ISB0		0x01
+
+/* Interrupt Vector Address (IVA) */
+#define SAB82532_IVA_MASK		0xf1
+
+/* Interrupt Port Configuration (IPC) */
+#define SAB82532_IPC_VIS		0x80
+#define SAB82532_IPC_SLA1		0x10
+#define SAB82532_IPC_SLA0		0x08
+#define SAB82532_IPC_CASM		0x04
+#define SAB82532_IPC_IC_OPEN_DRAIN	0x00
+#define SAB82532_IPC_IC_ACT_LOW		0x01
+#define SAB82532_IPC_IC_ACT_HIGH	0x03
+
+/* Interrupt Status Register 0 (ISR0) */
+#define SAB82532_ISR0_TCD		0x80
+#define SAB82532_ISR0_TIME		0x40
+#define SAB82532_ISR0_PERR		0x20
+#define SAB82532_ISR0_FERR		0x10
+#define SAB82532_ISR0_PLLA		0x08
+#define SAB82532_ISR0_CDSC		0x04
+#define SAB82532_ISR0_RFO		0x02
+#define SAB82532_ISR0_RPF		0x01
+
+/* Interrupt Status Register 1 (ISR1) */
+#define SAB82532_ISR1_BRK		0x80
+#define SAB82532_ISR1_BRKT		0x40
+#define SAB82532_ISR1_ALLS		0x20
+#define SAB82532_ISR1_XOFF		0x10
+#define SAB82532_ISR1_TIN		0x08
+#define SAB82532_ISR1_CSC		0x04
+#define SAB82532_ISR1_XON		0x02
+#define SAB82532_ISR1_XPR		0x01
+
+/* Interrupt Mask Register 0 (IMR0) */
+#define SAB82532_IMR0_TCD		0x80
+#define SAB82532_IMR0_PERR		0x20
+#define SAB82532_IMR0_SCD		0x10
+#define SAB82532_IMR0_PLLA		0x08
+#define SAB82532_IMR0_CDSC		0x04
+#define SAB82532_IMR0_RFO		0x02
+#define SAB82532_IMR0_RPF		0x01
+#define SAB82532_IMR0_OR_ME_IN		0x40
+
+/* Interrupt Mask Register 1 (IMR1) */
+#define SAB82532_IMR1_ALLS		0x20
+#define SAB82532_IMR1_XDU		0x10
+#define SAB82532_IMR1_TIN		0x08
+#define SAB82532_IMR1_CSC		0x04
+#define SAB82532_IMR1_XMR		0x02
+#define SAB82532_IMR1_XPR		0x01
+#define SAB82532_IMR1_OR_ME_IN		0xc0
+
+/* Port Interrupt Status Register (PIS) */
+#define SAB82532_PIS_SYNC_B		0x08
+#define SAB82532_PIS_DTR_B		0x04
+#define SAB82532_PIS_DTR_A		0x02
+#define SAB82532_PIS_SYNC_A		0x01
+
+/* Channel Configuration Register 4 (CCR4) */
+#define SAB82532_CCR4_MCK4		0x80
+#define SAB82532_CCR4_EBRG		0x40
+#define SAB82532_CCR4_TST1		0x20
+#define SAB82532_CCR4_ICD		0x10
+
+
+#endif /* !(_SPARC64_SAB82532_H) */
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/sbus.h linux/include/asm-sparc64/sbus.h
--- v2.1.50/linux/include/asm-sparc64/sbus.h	Mon Apr 14 16:28:23 1997
+++ linux/include/asm-sparc64/sbus.h	Sat Aug 16 09:51:10 1997
@@ -1,4 +1,4 @@
-/* $Id: sbus.h,v 1.3 1997/03/21 17:57:24 jj Exp $
+/* $Id: sbus.h,v 1.5 1997/08/12 04:13:16 ecd Exp $
  * sbus.h:  Defines for the Sun SBus.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -87,9 +87,7 @@
         for((device) = (bus)->devices; (device); (device)=(device)->next)
         
 #define for_all_sbusdev(device, bus) \
-	for((bus) = SBus_chain, (device) = (bus)->devices; (bus); (device)=((device)->next ? (device)->next : ((bus) = (bus)->next, (bus) ? (bus)->devices : 0)))
-
-/* XXX This is promlib stuff, what is it doing here? XXX */
+	for((bus) = SBus_chain, ((device) = (bus) ? (bus)->devices : 0); (bus); (device)=((device)->next ? (device)->next : ((bus) = (bus)->next, (bus) ? (bus)->devices : 0)))
 
 /* Apply promlib probed SBUS ranges to registers. */
 extern void prom_apply_sbus_ranges(struct linux_sbus *sbus, 
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/semaphore.h linux/include/asm-sparc64/semaphore.h
--- v2.1.50/linux/include/asm-sparc64/semaphore.h	Mon Aug  4 16:25:40 1997
+++ linux/include/asm-sparc64/semaphore.h	Sat Aug 16 09:51:10 1997
@@ -38,20 +38,28 @@
 
 extern __inline__ void down(struct semaphore * sem)
 {
-	if (atomic_dec_return(&sem->count) < 0)
+	int result;
+
+	result = atomic_dec_return(&sem->count);
+	membar("#StoreLoad | #StoreStore");
+	if (result < 0)
 		__down(sem);
 }
 
 extern __inline__ int down_interruptible(struct semaphore *sem)
 {
-	int ret = 0;
-	if (atomic_dec_return(&sem->count) < 0)
+	int result, ret = 0;
+
+	result = atomic_dec_return(&sem->count);
+	membar("#StoreLoad | #StoreStore");
+	if (result < 0)
 		ret = __down_interruptible(sem);
 	return ret;
 }
 
 extern __inline__ void up(struct semaphore * sem)
 {
+	membar("#StoreStore | #LoadStore");
 	if (atomic_inc_return(&sem->count) <= 0)
 		__up(sem);
 }	
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/shmparam.h linux/include/asm-sparc64/shmparam.h
--- v2.1.50/linux/include/asm-sparc64/shmparam.h	Mon Dec 30 02:00:03 1996
+++ linux/include/asm-sparc64/shmparam.h	Sat Aug 16 09:51:10 1997
@@ -1,4 +1,4 @@
-/* $Id: shmparam.h,v 1.1 1996/12/26 14:22:36 davem Exp $ */
+/* $Id: shmparam.h,v 1.2 1997/08/04 16:16:55 davem Exp $ */
 #ifndef _ASMSPARC64_SHMPARAM_H
 #define _ASMSPARC64_SHMPARAM_H
 
@@ -41,7 +41,7 @@
 #define SHMMNI (1<<_SHM_ID_BITS)	/* max num of segs system wide */
 #define SHMALL				/* max shm system wide (pages) */ \
 	(1<<(_SHM_IDX_BITS+_SHM_ID_BITS))
-#define	SHMLBA PAGE_SIZE		/* attach addr a multiple of this */
+#define	SHMLBA (PAGE_SIZE<<1)		/* attach addr a multiple of this */
 #define SHMSEG SHMMNI			/* max shared segs per process */
 
 #endif /* _ASMSPARC64_SHMPARAM_H */
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/smp.h linux/include/asm-sparc64/smp.h
--- v2.1.50/linux/include/asm-sparc64/smp.h	Mon Aug  4 16:25:40 1997
+++ linux/include/asm-sparc64/smp.h	Sat Aug 16 09:51:10 1997
@@ -6,6 +6,7 @@
 #ifndef _SPARC64_SMP_H
 #define _SPARC64_SMP_H
 
+#include <linux/tasks.h>
 #include <asm/asi.h>
 
 #ifndef __ASSEMBLY__
@@ -29,8 +30,20 @@
 
 /* Per processor Sparc parameters we need. */
 
+/* Keep this a multiple of 64-bytes for cache reasons. */
 struct cpuinfo_sparc {
-	unsigned long udelay_val; /* that's it */
+	/* Dcache line 1 */
+	unsigned long	irq_count;
+	unsigned int	multiplier;
+	unsigned int	counter;
+	unsigned long	last_tlbversion_seen;
+	unsigned long	pgcache_size;
+
+	/* Dcache line 2 */
+	unsigned long	*pgd_cache;
+	unsigned long	*pmd_cache;
+	unsigned long	*pte_cache;
+	unsigned long	udelay_val;
 };
 
 extern struct cpuinfo_sparc cpu_data[NR_CPUS];
@@ -49,21 +62,8 @@
  *	Private routines/data
  */
  
-extern int smp_found_cpus;
 extern unsigned char boot_cpu_id;
 extern unsigned long cpu_present_map;
-extern __volatile__ unsigned long smp_invalidate_needed[NR_CPUS];
-extern __volatile__ unsigned long kernel_counter;
-extern __volatile__ unsigned char active_kernel_processor;
-extern void smp_message_irq(void);
-extern unsigned long ipi_count;
-extern __volatile__ unsigned long kernel_counter;
-extern __volatile__ unsigned long syscall_count;
-
-extern void print_lock_state(void);
-
-typedef void (*smpfunc_t)(unsigned long, unsigned long, unsigned long,
-		       unsigned long, unsigned long);
 
 /*
  *	General functions that each host system must provide.
@@ -88,30 +88,12 @@
 
 #define smp_processor_id() (current->processor)
 
-extern __volatile__ unsigned long smp_proc_in_lock[NR_CPUS]; /* for computing process time */
 #endif /* !(__ASSEMBLY__) */
 
-/* Sparc specific messages. */
-#define MSG_CROSS_CALL         0x0005       /* run func on cpus */
-
-/* Empirical PROM processor mailbox constants.  If the per-cpu mailbox
- * contains something other than one of these then the ipi is from
- * Linux's active_kernel_processor.  This facility exists so that
- * the boot monitor can capture all the other cpus when one catches
- * a watchdog reset or the user enters the monitor using L1-A keys.
- */
-#define MBOX_STOPCPU          0xFB
-#define MBOX_IDLECPU          0xFC
-#define MBOX_IDLECPU2         0xFD
-#define MBOX_STOPCPU2         0xFE
-
-#define PROC_CHANGE_PENALTY     20
-
-#define SMP_FROM_INT		1
-#define SMP_FROM_SYSCALL	2
+#define PROC_CHANGE_PENALTY	20
 
 #endif /* !(__SMP__) */
 
-#define NO_PROC_ID            0xFF
+#define NO_PROC_ID		0xFF
 
 #endif /* !(_SPARC64_SMP_H) */
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/smp_lock.h linux/include/asm-sparc64/smp_lock.h
--- v2.1.50/linux/include/asm-sparc64/smp_lock.h	Mon Aug  4 16:25:40 1997
+++ linux/include/asm-sparc64/smp_lock.h	Sat Aug 16 09:51:10 1997
@@ -28,6 +28,7 @@
 		__cli();				\
 		(task)->lock_depth = 0;			\
 		klock_info.akp = NO_PROC_ID;		\
+		membar("#LoadStore | #StoreStore");	\
 		klock_info.kernel_flag = 0;		\
 	}						\
 	release_irqlock(cpu);				\
@@ -45,7 +46,7 @@
 				     " mov	%1, %%g2"			\
 				     : /* No outputs. */			\
 				     : "r" (klip), "r" (depth)			\
-				     : "g2", "g3", "g5", "g7", "memory", "cc");	\
+				     : "g2", "g3", "g5", "memory", "cc");	\
 	}									\
 } while(0)
 
@@ -63,9 +64,9 @@
 	__asm__ __volatile__("
 	mov	%%o7, %%g5
 	call	___lock_kernel
-	 ld	[%%g6 + %0], %%g2
+	 lduw	[%%g6 + %0], %%g2
 "	: : "i" (AOFF_task_lock_depth), "r" (klip)
-	: "g2", "g3", "g5", "g7", "memory", "cc");
+	: "g2", "g3", "g5", "memory", "cc");
 }
 
 /* Release kernel global lock. */
@@ -76,7 +77,7 @@
 	__asm__ __volatile__("
 	mov	%%o7, %%g5
 	call	___unlock_kernel
-	 ld	[%%g6 + %0], %%g2
+	 lduw	[%%g6 + %0], %%g2
 "	: : "i" (AOFF_task_lock_depth), "r" (klip)
 	: "g2", "g3", "g5", "memory", "cc");
 }
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/spinlock.h linux/include/asm-sparc64/spinlock.h
--- v2.1.50/linux/include/asm-sparc64/spinlock.h	Mon Aug  4 16:25:40 1997
+++ linux/include/asm-sparc64/spinlock.h	Sat Aug 16 09:51:10 1997
@@ -68,33 +68,35 @@
 
 typedef unsigned char spinlock_t;
 #define SPIN_LOCK_UNLOCKED	0
-#define spin_lock_init(lock)	(*(lock) = 0)
-#define spin_unlock_wait(lock)	do { barrier(); } while(*(volatile spinlock_t *)lock)
+
+#define spin_lock_init(lock)	(*((unsigned char *)(lock)) = 0)
+
+#define spin_unlock_wait(lock)	\
+do {	membar("#LoadLoad");	\
+} while(*((volatile unsigned char *)lock))
 
 extern __inline__ void spin_lock(spinlock_t *lock)
 {
 	__asm__ __volatile__("
-1:	ldstub		[%0], %%g2
-	brz,pt		%%g2, 2f
-	 membar		#LoadLoad | #LoadStore
-	b,a		%%xcc, 3f
-2:
-	.text		2
-3:	ldub		[%0], %%g2
-4:	brnz,a,pt	%%g2, 4b
-	 ldub		[%0], %%g2
-	b,a		1b
+1:	ldstub		[%0], %%g7
+	brnz,pn		%%g7, 2f
+	 membar		#StoreLoad | #StoreStore
+	.subsection	2
+2:	ldub		[%0], %%g7
+	brnz,pt		%%g7, 2b
+	 membar		#LoadLoad
+	b,a,pt		%%xcc, 1b
 	.previous
 "	: /* no outputs */
 	: "r" (lock)
-	: "g2", "memory");
+	: "g7", "memory");
 }
 
 extern __inline__ int spin_trylock(spinlock_t *lock)
 {
 	unsigned int result;
 	__asm__ __volatile__("ldstub [%1], %0\n\t"
-			     "membar #LoadLoad | #LoadStore"
+			     "membar #StoreLoad | #StoreStore"
 			     : "=r" (result)
 			     : "r" (lock)
 			     : "memory");
@@ -104,7 +106,7 @@
 extern __inline__ void spin_unlock(spinlock_t *lock)
 {
 	__asm__ __volatile__("membar	#StoreStore | #LoadStore\n\t"
-			     "stb	%%g0, [%0]"
+			     "stb	%%g0, [%0]\n\t"
 			     : /* No outputs */
 			     : "r" (lock)
 			     : "memory");
@@ -114,20 +116,18 @@
 {
 	__asm__ __volatile__("
 	wrpr		%%g0, 15, %%pil
-1:	ldstub		[%0], %%g2
-	brz,pt		%%g2, 2f
-	 membar		#LoadLoad | #LoadStore
-	b,a		3f
-2:
-	.text		2
-3:	ldub		[%0], %%g2
-4:	brnz,a,pt	%%g2, 4b
-	 ldub		[%0], %%g2
-	b,a		1b
+1:	ldstub		[%0], %%g7
+	brnz,pn		%%g7, 2f
+	 membar		#StoreLoad | #StoreStore
+	.subsection	2
+2:	ldub		[%0], %%g7
+	brnz,pt		%%g7, 2b
+	 membar		#LoadLoad
+	b,a,pt		%%xcc, 1b
 	.previous
 "	: /* no outputs */
 	: "r" (lock)
-	: "g2", "memory");
+	: "g7", "memory");
 }
 
 extern __inline__ void spin_unlock_irq(spinlock_t *lock)
@@ -147,20 +147,18 @@
 	__asm__ __volatile__(					\
 	"\n	rdpr		%%pil, %0\n"			\
 	"	wrpr		%%g0, 15, %%pil\n"		\
-	"1:	ldstub		[%1], %%g2\n"			\
-	"	brz,pt		%%g2, 2f\n"			\
-	"	 membar		#LoadLoad | #LoadStore\n"	\
-	"	b,a		3f\n"				\
-	"2:\n"							\
-	"	.text		2\n"				\
-	"3:	ldub		[%1], %%g2\n"			\
-	"4:	brnz,a,pt	%%g2, 4b\n"			\
-	"	 ldub		[%1], %%g2\n"			\
-	"	b,a		1b\n"				\
+	"1:	ldstub		[%1], %%g7\n"			\
+	"	brnz,pn		%%g7, 2f\n"			\
+	"	 membar		#StoreLoad | #StoreStore\n"	\
+	"	.subsection	2\n"				\
+	"2:	ldub		[%1], %%g7\n"			\
+	"	brnz,pt		%%g7, 2b\n"			\
+	"	 membar		#LoadLoad\n"			\
+	"	b,a,pt		%%xcc, 1b\n"			\
 	"	.previous\n"					\
 	: "=&r" (flags)						\
 	: "r" (lp)						\
-	: "g2", "memory");					\
+	: "g7", "memory");					\
 } while(0)
 
 extern __inline__ void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
@@ -182,94 +180,83 @@
 extern __inline__ void read_lock(rwlock_t *rw)
 {
 	__asm__ __volatile__("
-	ldx		[%0], %%g2
-1:	brgez,pt	%%g2, 4f
-	 add		%%g2, 1, %%g3
-	b,a		2f
-4:	casx		[%0], %%g2, %%g3
-	cmp		%%g2, %%g3
-	bne,a,pn	%%xcc, 1b
-	 ldx		[%0], %%g2
-	membar		#LoadLoad | #LoadStore
-	.text		2
-2:	ldx		[%0], %%g2
-3:	brlz,a,pt	%%g2, 3b
-	 ldx		[%0], %%g2
-	b		4b
-	 add		%%g2, 1, %%g3
+1:	ldx		[%0], %%g5
+	brlz,pn		%%g5, 2f
+4:	 add		%%g5, 1, %%g7
+	casx		[%0], %%g5, %%g7
+	cmp		%%g5, %%g7
+	bne,pn		%%xcc, 1b
+	 membar		#StoreLoad | #StoreStore
+	.subsection	2
+2:	ldx		[%0], %%g5
+	brlz,pt		%%g5, 2b
+	 membar		#LoadLoad
+	b,a,pt		%%xcc, 4b
 	.previous
 "	: /* no outputs */
 	: "r" (rw)
-	: "g2", "g3", "cc", "memory");
+	: "g5", "g7", "cc", "memory");
 }
 
 extern __inline__ void read_unlock(rwlock_t *rw)
 {
 	__asm__ __volatile__("
-	membar		#StoreStore | #LoadStore
-	ldx		[%0], %%g2
-1:	sub		%%g2, 1, %%g3
-	casx		[%0], %%g2, %%g3
-	cmp		%%g2, %%g3
-	bne,a,pn	%%xcc, 1b
-	 ldx		[%0], %%g2
+1:	ldx		[%0], %%g5
+	sub		%%g5, 1, %%g7
+	casx		[%0], %%g5, %%g7
+	cmp		%%g5, %%g7
+	bne,pn		%%xcc, 1b
+	 membar		#StoreLoad | #StoreStore
 "	: /* no outputs */
 	: "r" (rw)
-	: "g2", "g3", "cc", "memory");
+	: "g5", "g7", "cc", "memory");
 }
 
 extern __inline__ void write_lock(rwlock_t *rw)
 {
 	__asm__ __volatile__("
-	sethi		%%uhi(0x8000000000000000), %%g5
-	ldx		[%0], %%g2
-	sllx		%%g5, 32, %%g5
-1:	brgez,pt	%%g2, 4f
-	 or		%%g2, %%g5, %%g3
-	b,a		5f
-4:	casx		[%0], %%g2, %%g3
-	cmp		%%g2, %%g3
-	bne,a,pn	%%xcc, 1b
-	 ldx		[%0], %%g2
-	andncc		%%g3, %%g5, %%g0
-	be,pt		%%xcc, 2f
-	 membar		#LoadLoad | #LoadStore
-	b,a		7f
-2:
-	.text		2
-7:	ldx		[%0], %%g2
-3:	andn		%%g2, %%g5, %%g3
-	casx		[%0], %%g2, %%g3
-	cmp		%%g2, %%g3
-	bne,a,pn	%%xcc, 3b
-	 ldx		[%0], %%g2
-	membar		#LoadLoad | #LoadStore
-5:	ldx		[%0], %%g2
-6:	brlz,a,pt	%%g2, 6b
-	 ldx		[%0], %%g2
-	b		4b
-	 or		%%g2, %%g5, %%g3
+	sethi		%%uhi(0x8000000000000000), %%g3
+	sllx		%%g3, 32, %%g3
+1:	ldx		[%0], %%g5
+	brlz,pn		%%g5, 5f
+4:	 or		%%g5, %%g3, %%g7
+	casx		[%0], %%g5, %%g7
+	cmp		%%g5, %%g7
+	bne,pn		%%xcc, 1b
+	 andncc		%%g7, %%g3, %%g0
+	bne,pn		%%xcc, 7f
+	 membar		#StoreLoad | #StoreStore
+	.subsection	2
+7:	ldx		[%0], %%g5
+	andn		%%g5, %%g3, %%g7
+	casx		[%0], %%g5, %%g7
+	cmp		%%g5, %%g7
+	bne,pn		%%xcc, 7b
+	 membar		#StoreLoad | #StoreStore
+5:	ldx		[%0], %%g5
+	brnz,pt		%%g5, 5b
+	 membar		#LoadLoad
+	b,a,pt		%%xcc, 4b
 	.previous
 "	: /* no outputs */
 	: "r" (rw)
-	: "g2", "g3", "g5", "memory", "cc");
+	: "g3", "g5", "g7", "memory", "cc");
 }
 
 extern __inline__ void write_unlock(rwlock_t *rw)
 {
 	__asm__ __volatile__("
-	membar		#StoreStore | #LoadStore
-	sethi		%%uhi(0x8000000000000000), %%g5
-	ldx		[%0], %%g2
-	sllx		%%g5, 32, %%g5
-1:	andn		%%g2, %%g5, %%g3
-	casx		[%0], %%g2, %%g3
-	cmp		%%g2, %%g3
-	bne,a,pn	%%xcc, 1b
-	 ldx		[%0], %%g2
+	sethi		%%uhi(0x8000000000000000), %%g3
+	sllx		%%g3, 32, %%g3
+1:	ldx		[%0], %%g5
+	andn		%%g5, %%g3, %%g7
+	casx		[%0], %%g5, %%g7
+	cmp		%%g5, %%g7
+	bne,pn		%%xcc, 1b
+	 membar		#StoreLoad | #StoreStore
 "	: /* no outputs */
 	: "r" (rw)
-	: "g2", "g3", "g5", "memory", "cc");
+	: "g3", "g5", "g7", "memory", "cc");
 }
 
 #define read_lock_irq(lock)	do { __cli(); read_lock(lock); } while (0)
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/sysio.h linux/include/asm-sparc64/sysio.h
--- v2.1.50/linux/include/asm-sparc64/sysio.h	Mon Apr 14 16:28:24 1997
+++ linux/include/asm-sparc64/sysio.h	Sat Aug 16 09:51:10 1997
@@ -1,4 +1,4 @@
-/* $Id: sysio.h,v 1.2 1997/04/03 12:26:45 davem Exp $
+/* $Id: sysio.h,v 1.6 1997/08/15 06:44:53 davem Exp $
  * sysio.h: UltraSparc sun5 specific SBUS definitions.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -49,7 +49,7 @@
 		 *	slot 5) MACIO
 		 *	slot 6) SLAVIO
 		 *
-		 * On Sunfire/Wildfire enterprise boxen these upper slots
+		 * On Sunfire/Starfire/Wildfire enterprise boxen these upper slots
 		 * are unused.
 		 */
 /*0x2020*/	u64	sbus_s0cfg;	/* SBUS Slot 0 Config			*/
@@ -72,83 +72,83 @@
 		/* SBUS/IOMMU Streaming Buffer Registers */
 /*0x2800*/	u64	sbuf_control;	/* StrBuffer Control			*/
 /*0x2808*/	u64	sbuf_pflush;	/* StrBuffer Page Flush			*/
-/*0x2810*/	u64	sbus_fsync;	/* StrBuffer Flush Synchronization Reg	*/
+/*0x2810*/	u64	sbuf_fsync;	/* StrBuffer Flush Synchronization Reg	*/
 
 		u64	__pad4[0x7d];
 
 		/* Interrupt mapping/control registers */
-/*0x2c00*/	u32	imap_slot0, _uim0;	/* SBUS Slot 0 Int Mapping	*/
-/*0x2c08*/	u32	imap_slot1, _uim1;	/* SBUS Slot 1 Int Mapping	*/
-/*0x2c10*/	u32	imap_slot2, _uim2;	/* SBUS Slot 2 Int Mapping	*/
-/*0x2c18*/	u32	imap_slot3, _uim3;	/* SBUS Slot 3 Int Mapping	*/
+/*0x2c00*/	u32	_uim0, imap_slot0;	/* SBUS Slot 0 Int Mapping	*/
+/*0x2c08*/	u32	_uim1, imap_slot1;	/* SBUS Slot 1 Int Mapping	*/
+/*0x2c10*/	u32	_uim2, imap_slot2;	/* SBUS Slot 2 Int Mapping	*/
+/*0x2c18*/	u32	_uim3, imap_slot3;	/* SBUS Slot 3 Int Mapping	*/
 
 		/* Interrupt Retry Timer. */
-/*0x2c20*/	u32	irq_retry,  _irpad;
+/*0x2c20*/	u32	_irpad, irq_retry;
 
 		u64	__pad5[0x7b];
 
 		/* The following are only used on Fusion/Electron/Pulsar
-		 * desktop systems, they mean nothing on Sunfire/Wildfire
+		 * desktop systems, they mean nothing on Sunfire/Starfire/Wildfire
 		 */
-/*0x3000*/	u32	imap_scsi,  _uis;	/* SCSI Int Mapping		*/
-/*0x3008*/	u32	imap_eth,   _uie;	/* Ethernet Int Mapping		*/
-/*0x3010*/	u32	imap_bpp,   _uip;	/* Parallel Port Int Mapping	*/
-/*0x3018*/	u32	imap_audio, _uia;	/* Audio Int Mapping		*/
-/*0x3020*/	u32	imap_pfail, _uipf;	/* Power Fail Int Mapping	*/
-/*0x3028*/	u32	imap_kms,   _uik;	/* Kbd/Mouse/Serial Int Mapping	*/
-/*0x3030*/	u32	imap_flpy,  _uif;	/* Floppy Int Mapping		*/
-/*0x3038*/	u32	imap_shw,   _uishw;	/* Spare HW Int Mapping		*/
-/*0x3040*/	u32	imap_kbd,   _uikbd;	/* Kbd Only Int Mapping		*/
-/*0x3048*/	u32	imap_ms,    _uims;	/* Mouse Only Int Mapping	*/
-/*0x3050*/	u32	imap_ser,   _uiser;	/* Serial Only Int Mapping	*/
+/*0x3000*/	u32	_uis, imap_scsi;	/* SCSI Int Mapping		*/
+/*0x3008*/	u32	_uie, imap_eth;		/* Ethernet Int Mapping		*/
+/*0x3010*/	u32	_uip, imap_bpp;		/* Parallel Port Int Mapping	*/
+/*0x3018*/	u32	_uia, imap_audio;	/* Audio Int Mapping		*/
+/*0x3020*/	u32	_uipf, imap_pfail;	/* Power Fail Int Mapping	*/
+/*0x3028*/	u32	_uik, imap_kms;		/* Kbd/Mouse/Serial Int Mapping	*/
+/*0x3030*/	u32	_uif, imap_flpy;	/* Floppy Int Mapping		*/
+/*0x3038*/	u32	_uishw, imap_shw;	/* Spare HW Int Mapping		*/
+/*0x3040*/	u32	_uikbd, imap_kbd;	/* Kbd Only Int Mapping		*/
+/*0x3048*/	u32	_uims, imap_ms;		/* Mouse Only Int Mapping	*/
+/*0x3050*/	u32	_uiser, imap_ser;	/* Serial Only Int Mapping	*/
 /*0x3058*/	u64	_imap_unused;
-/*0x3060*/	u32	imap_tim0,  _uit0;	/* Timer 0 Int Mapping		*/
-/*0x3068*/	u32	imap_tim1,  _uit1;	/* Timer 1 Int Mapping		*/
-/*0x3070*/	u32	imap_ue,    _uiue;	/* UE Int Mapping		*/
-/*0x3078*/	u32	imap_ce,    _uice;	/* CE Int Mapping		*/
-/*0x3080*/	u32	imap_sberr, _uisbe;	/* SBUS Err Int Mapping		*/
-/*0x3088*/	u32	imap_pmgmt, _uipm;	/* Power Mgmt Int Mapping	*/
-/*0x3090*/	u32	imap_gfx,   _uigfx;	/* OB Graphics Int Mapping	*/
-/*0x3098*/	u32	imap_eupa,  _uieupa;	/* UPA Expansion Int Mapping	*/
+/*0x3060*/	u32	_uit0, imap_tim0;	/* Timer 0 Int Mapping		*/
+/*0x3068*/	u32	_uit1, imap_tim1;	/* Timer 1 Int Mapping		*/
+/*0x3070*/	u32	_uiue, imap_ue;		/* UE Int Mapping		*/
+/*0x3078*/	u32	_uice, imap_ce;		/* CE Int Mapping		*/
+/*0x3080*/	u32	_uisbe, imap_sberr;	/* SBUS Err Int Mapping		*/
+/*0x3088*/	u32	_uipm, imap_pmgmt;	/* Power Mgmt Int Mapping	*/
+/*0x3090*/	u32	_uigfx, imap_gfx;	/* OB Graphics Int Mapping	*/
+/*0x3098*/	u32	_uieupa, imap_eupa;	/* UPA Expansion Int Mapping	*/
 
 		u64	__pad6[0x6c];
 
 		/* Interrupt Clear Registers */
-/*0x3400*/	u64	iclr_unused0;
-/*0x3408*/	u32	iclr_slot0, _ucs0;
+/*0x3400*/	u32	__ucu0, iclr_unused0;
+/*0x3408*/	u32	_ucs0, iclr_slot0;
 		u64	__pad7[0x7];
-/*0x3448*/	u32	iclr_slot1, _ucs1;
+/*0x3448*/	u32	_ucs1, iclr_slot1;
 		u64	__pad8[0x7];
-/*0x3488*/	u32	iclr_slot2, _ucs2;
+/*0x3488*/	u32	_ucs2, iclr_slot2;
 		u64	__pad9[0x7];
-/*0x34c8*/	u32	iclr_slot3, _ucs3;
+/*0x34c8*/	u32	_ucs3, iclr_slot3;
 		u64	__pad10[0x66];
-/*0x3800*/	u32	iclr_scsi,  _ucscsi;
-/*0x3808*/	u32	iclr_eth,   _uceth;
-/*0x3810*/	u32	iclr_bpp,   _ucbpp;
-/*0x3818*/	u32	iclr_audio, _ucaudio;
-/*0x3820*/	u32	iclr_pfail, _ucpfail;
-/*0x3828*/	u32	iclr_kms,   _uckms;
-/*0x3830*/	u32	iclr_flpt,  _ucflpy;
-/*0x3838*/	u32	iclr_shw,   _ucshw;
-/*0x3840*/	u32	iclr_kbd,   _uckbd;
-/*0x3848*/	u32	iclr_ms,    _ucms;
-/*0x3850*/	u32	iclr_ser,   _ucser;
+/*0x3800*/	u32	_ucscsi, iclr_scsi;
+/*0x3808*/	u32	_uceth, iclr_eth;
+/*0x3810*/	u32	_ucbpp, iclr_bpp;
+/*0x3818*/	u32	_ucaudio, iclr_audio;
+/*0x3820*/	u32	_ucpfail, iclr_pfail;
+/*0x3828*/	u32	_uckms, iclr_kms;
+/*0x3830*/	u32	_ucflpy, iclr_flpt;
+/*0x3838*/	u32	_ucshw, iclr_shw;
+/*0x3840*/	u32	_uckbd, iclr_kbd;
+/*0x3848*/	u32	_ucms, iclr_ms;
+/*0x3850*/	u32	_ucser, iclr_ser;
 /*0x3858*/	u64	iclr_unused1;
-/*0x3860*/	u32	iclr_tim0,  _uctim0;
-/*0x3868*/	u32	iclr_tim1,  _uctim1;
-/*0x3870*/	u32	iclr_ue,    _ucue;
-/*0x3878*/	u32	iclr_ce,    _ucce;
-/*0x3880*/	u32	iclr_serr,  _ucserr;
-/*0x3888*/	u32	iclr_pmgmt, _ucpmgmt;
+/*0x3860*/	u32	_uctim0, iclr_tim0;
+/*0x3868*/	u32	_uctim1, iclr_tim1;
+/*0x3870*/	u32	_ucue, iclr_ue;
+/*0x3878*/	u32	_ucce, iclr_ce;
+/*0x3880*/	u32	_ucserr, iclr_serr;
+/*0x3888*/	u32	_ucpmgmt, iclr_pmgmt;
 
 		u64	__pad11[0x6e];
 
 		/* Counters/Timers */
-/*0x3c00*/	u32	tim0_cnt, _tim0_u0;
-/*0x3c08*/	u32	tim0_lim, _tim0_u1;
-/*0x3c10*/	u32	tim1_cnt, _tim1_u0;
-/*0x3c18*/	u32	tim1_lim, _tim1_u1;
+/*0x3c00*/	u64	tim0_cnt;
+/*0x3c08*/	u64	tim0_lim;
+/*0x3c10*/	u64	tim1_cnt;
+/*0x3c18*/	u64	tim1_lim;
 
 		u64	__pad12[0x7c];
 
@@ -169,11 +169,13 @@
 /*0x4580*/	u64	iommu_tag[16];	/* IOMMU TLB Tag Diagnostic Access	*/
 /*0x4600*/	u64	iommu_data[32];	/* IOMMU TLB Data RAM Diagnostic Access	*/
 
+		u64	__pad15[0x20];
+
 		/* Interrupt State Diagnostics */
 /*0x4800*/	u64	sbus_istate;
 /*0x4808*/	u64	obio_istate;
 
-		u64	__pad15[0xfe];
+		u64	__pad16[0xfe];
 
 		/* Streaming Buffer Diagnostic Area */
 /*0x5000*/	u64	sbuf_data[128];	/* StrBuffer Data Ram Diagnostic	*/
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h
--- v2.1.50/linux/include/asm-sparc64/system.h	Mon Aug  4 16:25:40 1997
+++ linux/include/asm-sparc64/system.h	Sat Aug 16 09:51:10 1997
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.29 1997/07/24 16:48:32 davem Exp $ */
+/* $Id: system.h,v 1.35 1997/08/07 03:53:00 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -6,8 +6,6 @@
 #include <asm/processor.h>
 #include <asm/asm_offsets.h>
 
-#define NCPUS	4	/* No SMP yet */
-
 #ifndef __ASSEMBLY__
 /*
  * Sparc (general) CPU types
@@ -103,7 +101,7 @@
 
 #define membar(type)	__asm__ __volatile__ ("membar " type : : : "memory");
 
-#define flushi(addr)	__asm__ __volatile__ ("flush %0" : : "r" (addr))
+#define flushi(addr)	__asm__ __volatile__ ("flush %0" : : "r" (addr) : "memory")
 
 #define flushw_all()	__asm__ __volatile__("flushw")
 
@@ -131,6 +129,16 @@
 	 * I do not clobber it, when in fact I do.  Please,
 	 * when modifying this code inspect output of sched.s very
 	 * carefully to make sure things still work.  -DaveM
+	 *
+	 * SMP NOTE: At first glance it looks like there is a tiny
+	 *           race window here at the end.  The possible problem
+	 *           would be if a tlbcachesync MONDO vector got delivered
+	 *           to us right before we set the final %g6 thread reg
+	 *           value.  But that is impossible since only the holder
+	 *           of scheduler_lock can send a tlbcachesync MONDO and
+	 *           by definition we hold it right now.  Normal tlb
+	 *           flush xcalls can come in, but those are safe and do
+	 *           not reference %g6.
 	 */
 #define switch_to(prev, next)							\
 do {	__label__ switch_continue;						\
@@ -142,7 +150,6 @@
 	"rdpr	%%pstate, %%g2\n\t"						\
 	"wrpr	%%g2, 0x3, %%pstate\n\t"					\
 	"flushw\n\t"								\
-/*XXX*/	"wr	%%g0, 0, %%fprs\n\t"						\
 	"stx	%%i6, [%%sp + 2047 + 0x70]\n\t"					\
 	"stx	%%i7, [%%sp + 2047 + 0x78]\n\t"					\
 	"rdpr	%%wstate, %%o5\n\t"						\
@@ -151,6 +158,7 @@
 	"rdpr	%%cwp, %%o5\n\t"						\
 	"stx	%%o7, [%%g6 + %4]\n\t"						\
 	"st	%%o5, [%%g6 + %5]\n\t"						\
+	"membar #Sync\n\t"							\
 	"mov	%0, %%g6\n\t"							\
 	"ld	[%0 + %5], %%g1\n\t"						\
 	"wrpr	%%g1, %%cwp\n\t"						\
@@ -176,30 +184,35 @@
 	  "o0", "o1", "o2", "o3", "o4", "o5");					\
 switch_continue: } while(0)
 
-/* 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)
+extern __inline__ unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val)
 {
-	__asm__ __volatile__("swap	[%2], %0"
-			     : "=&r" (val)
-			     : "0" (val), "r" (m));
+	__asm__ __volatile__("
+	mov		%0, %%g5
+1:	lduw		[%2], %%g7
+	cas		[%2], %%g7, %0
+	cmp		%%g7, %0
+	bne,a,pn	%%icc, 1b
+	 mov		%%g5, %0
+	membar		#StoreLoad | #StoreStore
+"	: "=&r" (val)
+	: "0" (val), "r" (m)
+	: "g5", "g7", "cc", "memory");
 	return val;
 }
 
-/* Bolix, must use casx for 64-bit values. */
-extern __inline__ unsigned long xchg_u64(__volatile__ unsigned long *m,
-					 unsigned long val)
+extern __inline__ unsigned long xchg64(__volatile__ unsigned long *m, unsigned long val)
 {
-	unsigned long temp;
 	__asm__ __volatile__("
-	mov		%0, %%g1
-1:	ldx		[%3], %1
-	casx		[%3], %1, %0
-	cmp		%1, %0
+	mov		%0, %%g5
+1:	ldx		[%2], %%g7
+	casx		[%2], %%g7, %0
+	cmp		%%g7, %0
 	bne,a,pn	%%xcc, 1b
-	 mov		%%g1, %0
-"	: "=&r" (val), "=&r" (temp)
+	 mov		%%g5, %0
+	membar		#StoreLoad | #StoreStore
+"	: "=&r" (val)
 	: "0" (val), "r" (m)
-	: "g1", "cc");
+	: "g5", "g7", "cc", "memory");
 	return val;
 }
 
@@ -213,9 +226,9 @@
 {
 	switch (size) {
 	case 4:
-		return xchg_u32(ptr, x);
+		return xchg32(ptr, x);
 	case 8:
-		return xchg_u64(ptr, x);
+		return xchg64(ptr, x);
 	};
 	__xchg_called_with_bad_pointer();
 	return x;
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/termbits.h linux/include/asm-sparc64/termbits.h
--- v2.1.50/linux/include/asm-sparc64/termbits.h	Tue May 13 22:41:18 1997
+++ linux/include/asm-sparc64/termbits.h	Sat Aug 16 09:51:10 1997
@@ -148,13 +148,18 @@
 #define HUPCL	  0x00000400
 #define CLOCAL	  0x00000800
 #define CBAUDEX   0x00001000
-/* We'll never see these speeds with the Zilogs, but for completeness... */
 #define  B57600   0x00001001
 #define  B115200  0x00001002
 #define  B230400  0x00001003
 #define  B460800  0x00001004
 /* This is what we can do with the Zilogs. */
 #define  B76800   0x00001005
+/* This is what we can do with the SAB82532. */
+#define  B153600  0x00001006
+#define  B307200  0x00001007
+#define  B614400  0x00001008
+#define  B921600  0x00001009
+#define  B1843200 0x0000100a
 #define CIBAUD	  0x100f0000  /* input baud rate (not used) */
 #define CMSPAR    0x40000000  /* mark or space (stick) parity */
 #define CRTSCTS	  0x80000000  /* flow control */
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/ttable.h linux/include/asm-sparc64/ttable.h
--- v2.1.50/linux/include/asm-sparc64/ttable.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-sparc64/ttable.h	Sat Aug 16 09:51:10 1997
@@ -0,0 +1,320 @@
+/* $Id: ttable.h,v 1.2 1997/08/09 09:03:36 davem Exp $ */
+#ifndef _SPARC64_TTABLE_H
+#define _SPARC64_TTABLE_H
+
+#define BOOT_KERNEL b sparc64_boot; nop; nop; nop; nop; nop; nop; nop;
+
+/* We need a "cleaned" instruction... */
+#define CLEAN_WINDOW							\
+	rdpr	%cleanwin, %l0;		add	%l0, 1, %l0;		\
+	wrpr	%l0, 0x0, %cleanwin;					\
+	clr	%o0;	clr	%o1;	clr	%o2;	clr	%o3;	\
+	clr	%o4;	clr	%o5;	clr	%o6;	clr	%o7;	\
+	clr	%l0;	clr	%l1;	clr	%l2;	clr	%l3;	\
+	clr	%l4;	clr	%l5;	clr	%l6;	clr	%l7;	\
+	retry;								\
+	nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
+
+#define TRAP(routine)					\
+	sethi	%hi(109f), %g7;				\
+	ba,pt	%xcc, etrap;				\
+109:	 or	%g7, %lo(109b), %g7;			\
+	call	routine;				\
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	ba,pt	%xcc, rtrap;				\
+	 clr	%l6;					\
+	nop;
+
+#define TRAP_NOSAVE(routine)				\
+	ba,pt	%xcc, routine;				\
+	 nop;						\
+	nop; nop; nop; nop; nop; nop;
+
+#define TRAPTL1(routine)				\
+	sethi	%hi(109f), %g7;				\
+	ba,pt	%xcc, etraptl1;				\
+109:	 or	%g7, %lo(109b), %g7;			\
+	call	routine;				\
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	ba,pt	%xcc, rtrap;				\
+	 clr	%l6;					\
+	nop;
+	
+#define TRAP_ARG(routine, arg)				\
+	sethi	%hi(109f), %g7;				\
+	ba,pt	%xcc, etrap;				\
+109:	 or	%g7, %lo(109b), %g7;			\
+	add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	call	routine;				\
+	 mov	arg, %o1;				\
+	ba,pt	%xcc, rtrap;				\
+	 clr	%l6;
+	
+#define TRAPTL1_ARG(routine, arg)			\
+	sethi	%hi(109f), %g7;				\
+	ba,pt	%xcc, etraptl1;				\
+109:	 or	%g7, %lo(109b), %g7;			\
+	add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	call	routine;				\
+	 mov	arg, %o1;				\
+	ba,pt	%xcc, rtrap;				\
+	 clr	%l6;
+	
+#define SYSCALL_TRAP(routine, systbl)			\
+	sethi	%hi(109f), %g7;				\
+	ba,pt	%xcc, etrap;				\
+109:	 or	%g7, %lo(109b), %g7;			\
+	call	routine;				\
+	 sethi	%hi(systbl), %l7;			\
+	nop; nop; nop;
+	
+#define ACCESS_EXCEPTION_TRAP(routine)			\
+	rdpr	%pstate, %g1;				\
+	wrpr	%g1, PSTATE_MG|PSTATE_AG, %pstate;	\
+	ba,pt	%xcc, etrap;				\
+	 rd	%pc, %g7;				\
+	call	routine;				\
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	ba,pt	%xcc, rtrap;				\
+	 clr	%l6;
+
+#define ACCESS_EXCEPTION_TRAPTL1(routine)		\
+	rdpr	%pstate, %g1;				\
+	wrpr	%g1, PSTATE_MG|PSTATE_AG, %pstate;	\
+	ba,pt	%xcc, etraptl1;				\
+	 rd	%pc, %g7;				\
+	call	routine;				\
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	ba,pt	%xcc, rtrap;				\
+	 clr	%l6;
+
+#define SUNOS_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sunos_sys_table)
+#define	LINUX_32BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table32)
+#define LINUX_64BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table64)
+#define GETCC_TRAP TRAP(getcc)
+#define SETCC_TRAP TRAP(setcc)
+/* FIXME: Write these actually */	
+#define NETBSD_SYSCALL_TRAP TRAP(netbsd_syscall)
+#define SOLARIS_SYSCALL_TRAP TRAP(solaris_syscall)
+#define BREAKPOINT_TRAP TRAP(breakpoint_trap)
+#define INDIRECT_SOLARIS_SYSCALL(tlvl) TRAP_ARG(indirect_syscall, tlvl)
+
+#define TRAP_IRQ(routine, level)			\
+	rdpr	%pil, %g2;				\
+	wrpr	%g0, 15, %pil;				\
+	b,pt	%xcc, etrap_irq;			\
+	 rd	%pc, %g7;				\
+	mov	level, %o0;				\
+	call	routine;				\
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o1;	\
+	ba,a,pt	%xcc, rtrap_clr_l6;
+
+#ifdef __SMP__
+#define TRAP_TICK					\
+	rdpr	%pil, %g2;				\
+	wrpr	%g0, 15, %pil;				\
+	b,pt	%xcc, etrap_irq;			\
+	 rd	%pc, %g7;				\
+	call	smp_percpu_timer_interrupt;		\
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
+	b,pt	%xcc, rtrap;				\
+	 clr	%l6;
+#else
+#define TRAP_TICK	TRAP_IRQ(handler_irq, 14)
+#endif
+
+#define TRAP_IVEC TRAP_NOSAVE(do_ivec)
+
+#define BTRAP(lvl) TRAP_ARG(bad_trap, lvl)
+
+#define BTRAPTL1(lvl) TRAPTL1_ARG(bad_trap_tl1, lvl)
+
+#define FLUSH_WINDOW_TRAP						\
+	ba,pt	%xcc, etrap;						\
+	 rd	%pc, %g7;						\
+	flushw;								\
+	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1;	\
+	add	%l1, 4, %l2;						\
+	stx	%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC];	\
+	ba,pt	%xcc, rtrap_clr_l6;					\
+	 stx	%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC];
+	        
+/* Before touching these macros, you owe it to yourself to go and
+ * see how arch/sparc64/kernel/winfixup.S works... -DaveM
+ */
+
+/* Normal kernel spill */
+#define SPILL_0_NORMAL					\
+	stx	%l0, [%sp + STACK_BIAS + 0x00];		\
+	stx	%l1, [%sp + STACK_BIAS + 0x08];		\
+	stx	%l2, [%sp + STACK_BIAS + 0x10];		\
+	stx	%l3, [%sp + STACK_BIAS + 0x18];		\
+	stx	%l4, [%sp + STACK_BIAS + 0x20];		\
+	stx	%l5, [%sp + STACK_BIAS + 0x28];		\
+	stx	%l6, [%sp + STACK_BIAS + 0x30];		\
+	stx	%l7, [%sp + STACK_BIAS + 0x38];		\
+	stx	%i0, [%sp + STACK_BIAS + 0x40];		\
+	stx	%i1, [%sp + STACK_BIAS + 0x48];		\
+	stx	%i2, [%sp + STACK_BIAS + 0x50];		\
+	stx	%i3, [%sp + STACK_BIAS + 0x58];		\
+	stx	%i4, [%sp + STACK_BIAS + 0x60];		\
+	stx	%i5, [%sp + STACK_BIAS + 0x68];		\
+	stx	%i6, [%sp + STACK_BIAS + 0x70];		\
+	stx	%i7, [%sp + STACK_BIAS + 0x78];		\
+	saved; retry; nop; nop; nop; nop; nop; nop;	\
+	nop; nop; nop; nop; nop; nop; nop; nop;
+
+/* Normal 64bit spill */
+#define SPILL_1_GENERIC(xxx)				\
+	wr	%g0, xxx, %asi;				\
+	stxa	%l0, [%sp + STACK_BIAS + 0x00] %asi;	\
+	stxa	%l1, [%sp + STACK_BIAS + 0x08] %asi;	\
+	stxa	%l2, [%sp + STACK_BIAS + 0x10] %asi;	\
+	stxa	%l3, [%sp + STACK_BIAS + 0x18] %asi;	\
+	stxa	%l4, [%sp + STACK_BIAS + 0x20] %asi;	\
+	stxa	%l5, [%sp + STACK_BIAS + 0x28] %asi;	\
+	stxa	%l6, [%sp + STACK_BIAS + 0x30] %asi;	\
+	stxa	%l7, [%sp + STACK_BIAS + 0x38] %asi;	\
+	stxa	%i0, [%sp + STACK_BIAS + 0x40] %asi;	\
+	stxa	%i1, [%sp + STACK_BIAS + 0x48] %asi;	\
+	stxa	%i2, [%sp + STACK_BIAS + 0x50] %asi;	\
+	stxa	%i3, [%sp + STACK_BIAS + 0x58] %asi;	\
+	stxa	%i4, [%sp + STACK_BIAS + 0x60] %asi;	\
+	stxa	%i5, [%sp + STACK_BIAS + 0x68] %asi;	\
+	stxa	%i6, [%sp + STACK_BIAS + 0x70] %asi;	\
+	stxa	%i7, [%sp + STACK_BIAS + 0x78] %asi;	\
+	saved; retry; nop; nop; nop; nop; nop; nop;	\
+	nop; nop; nop; nop; nop;			\
+	b,a,pt	%xcc, spill_fixup_mna;			\
+	b,a,pt	%xcc, spill_fixup;
+
+/* Normal 32bit spill */
+#define SPILL_2_GENERIC(xxx)				\
+	wr	%g0, xxx, %asi;				\
+	srl	%sp, 0, %sp;				\
+	stwa	%l0, [%sp + 0x00] %asi;			\
+	stwa	%l1, [%sp + 0x04] %asi;			\
+	stwa	%l2, [%sp + 0x08] %asi;			\
+	stwa	%l3, [%sp + 0x0c] %asi;			\
+	stwa	%l4, [%sp + 0x10] %asi;			\
+	stwa	%l5, [%sp + 0x14] %asi;			\
+	stwa	%l6, [%sp + 0x18] %asi;			\
+	stwa	%l7, [%sp + 0x1c] %asi;			\
+	stwa	%i0, [%sp + 0x20] %asi;			\
+	stwa	%i1, [%sp + 0x24] %asi;			\
+	stwa	%i2, [%sp + 0x28] %asi;			\
+	stwa	%i3, [%sp + 0x2c] %asi;			\
+	stwa	%i4, [%sp + 0x30] %asi;			\
+	stwa	%i5, [%sp + 0x34] %asi;			\
+	stwa	%i6, [%sp + 0x38] %asi;			\
+	stwa	%i7, [%sp + 0x3c] %asi;			\
+	saved; retry; nop; nop; nop; nop;		\
+	nop; nop; nop; nop; nop; nop;			\
+	b,a,pt	%xcc, spill_fixup_mna;			\
+	b,a,pt	%xcc, spill_fixup;
+
+#define SPILL_1_NORMAL SPILL_1_GENERIC(ASI_AIUP)
+#define SPILL_2_NORMAL SPILL_2_GENERIC(ASI_AIUP)
+#define SPILL_3_NORMAL SPILL_0_NORMAL
+#define SPILL_4_NORMAL SPILL_0_NORMAL
+#define SPILL_5_NORMAL SPILL_0_NORMAL
+#define SPILL_6_NORMAL SPILL_0_NORMAL
+#define SPILL_7_NORMAL SPILL_0_NORMAL
+
+#define SPILL_0_OTHER SPILL_0_NORMAL
+#define SPILL_1_OTHER SPILL_1_GENERIC(ASI_AIUS)
+#define SPILL_2_OTHER SPILL_2_GENERIC(ASI_AIUS)
+#define SPILL_3_OTHER SPILL_3_NORMAL
+#define SPILL_4_OTHER SPILL_4_NORMAL
+#define SPILL_5_OTHER SPILL_5_NORMAL
+#define SPILL_6_OTHER SPILL_6_NORMAL
+#define SPILL_7_OTHER SPILL_7_NORMAL
+
+/* Normal kernel fill */
+#define FILL_0_NORMAL					\
+	ldx	[%sp + STACK_BIAS + 0x00], %l0;		\
+	ldx	[%sp + STACK_BIAS + 0x08], %l1;		\
+	ldx	[%sp + STACK_BIAS + 0x10], %l2;		\
+	ldx	[%sp + STACK_BIAS + 0x18], %l3;		\
+	ldx	[%sp + STACK_BIAS + 0x20], %l4;		\
+	ldx	[%sp + STACK_BIAS + 0x28], %l5;		\
+	ldx	[%sp + STACK_BIAS + 0x30], %l6;		\
+	ldx	[%sp + STACK_BIAS + 0x38], %l7;		\
+	ldx	[%sp + STACK_BIAS + 0x40], %i0;		\
+	ldx	[%sp + STACK_BIAS + 0x48], %i1;		\
+	ldx	[%sp + STACK_BIAS + 0x50], %i2;		\
+	ldx	[%sp + STACK_BIAS + 0x58], %i3;		\
+	ldx	[%sp + STACK_BIAS + 0x60], %i4;		\
+	ldx	[%sp + STACK_BIAS + 0x68], %i5;		\
+	ldx	[%sp + STACK_BIAS + 0x70], %i6;		\
+	ldx	[%sp + STACK_BIAS + 0x78], %i7;		\
+	restored; retry; nop; nop; nop; nop; nop; nop;	\
+	nop; nop; nop; nop; nop; nop; nop; nop;
+
+/* Normal 64bit fill */
+#define FILL_1_GENERIC(xxx)				\
+	wr	%g0, xxx, %asi;				\
+	ldxa	[%sp + STACK_BIAS + 0x00] %asi, %l0;	\
+	ldxa	[%sp + STACK_BIAS + 0x08] %asi, %l1;	\
+	ldxa	[%sp + STACK_BIAS + 0x10] %asi, %l2;	\
+	ldxa	[%sp + STACK_BIAS + 0x18] %asi, %l3;	\
+	ldxa	[%sp + STACK_BIAS + 0x20] %asi, %l4;	\
+	ldxa	[%sp + STACK_BIAS + 0x28] %asi, %l5;	\
+	ldxa	[%sp + STACK_BIAS + 0x30] %asi, %l6;	\
+	ldxa	[%sp + STACK_BIAS + 0x38] %asi, %l7;	\
+	ldxa	[%sp + STACK_BIAS + 0x40] %asi, %i0;	\
+	ldxa	[%sp + STACK_BIAS + 0x48] %asi, %i1;	\
+	ldxa	[%sp + STACK_BIAS + 0x50] %asi, %i2;	\
+	ldxa	[%sp + STACK_BIAS + 0x58] %asi, %i3;	\
+	ldxa	[%sp + STACK_BIAS + 0x60] %asi, %i4;	\
+	ldxa	[%sp + STACK_BIAS + 0x68] %asi, %i5;	\
+	ldxa	[%sp + STACK_BIAS + 0x70] %asi, %i6;	\
+	ldxa	[%sp + STACK_BIAS + 0x78] %asi, %i7;	\
+	restored; retry; nop; nop; nop; nop; nop; nop;	\
+	nop; nop; nop; nop; nop;			\
+	b,a,pt	%xcc, fill_fixup_mna;			\
+	b,a,pt	%xcc, fill_fixup;
+
+/* Normal 32bit fill */
+#define FILL_2_GENERIC(xxx)				\
+	wr	%g0, xxx, %asi;				\
+	srl	%sp, 0, %sp;				\
+	lduwa	[%sp + 0x00] %asi, %l0;			\
+	lduwa	[%sp + 0x04] %asi, %l1;			\
+	lduwa	[%sp + 0x08] %asi, %l2;			\
+	lduwa	[%sp + 0x0c] %asi, %l3;			\
+	lduwa	[%sp + 0x10] %asi, %l4;			\
+	lduwa	[%sp + 0x14] %asi, %l5;			\
+	lduwa	[%sp + 0x18] %asi, %l6;			\
+	lduwa	[%sp + 0x1c] %asi, %l7;			\
+	lduwa	[%sp + 0x20] %asi, %i0;			\
+	lduwa	[%sp + 0x24] %asi, %i1;			\
+	lduwa	[%sp + 0x28] %asi, %i2;			\
+	lduwa	[%sp + 0x2c] %asi, %i3;			\
+	lduwa	[%sp + 0x30] %asi, %i4;			\
+	lduwa	[%sp + 0x34] %asi, %i5;			\
+	lduwa	[%sp + 0x38] %asi, %i6;			\
+	lduwa	[%sp + 0x3c] %asi, %i7;			\
+	restored; retry; nop; nop; nop; nop;		\
+	nop; nop; nop; nop; nop; nop;			\
+	b,a,pt	%xcc, fill_fixup_mna;			\
+	b,a,pt	%xcc, fill_fixup;
+
+#define FILL_1_NORMAL FILL_1_GENERIC(ASI_AIUP)
+#define FILL_2_NORMAL FILL_2_GENERIC(ASI_AIUP)
+#define FILL_3_NORMAL FILL_0_NORMAL
+#define FILL_4_NORMAL FILL_0_NORMAL
+#define FILL_5_NORMAL FILL_0_NORMAL
+#define FILL_6_NORMAL FILL_0_NORMAL
+#define FILL_7_NORMAL FILL_0_NORMAL
+
+#define FILL_0_OTHER FILL_0_NORMAL
+#define FILL_1_OTHER FILL_1_GENERIC(ASI_AIUS)
+#define FILL_2_OTHER FILL_2_GENERIC(ASI_AIUS)
+#define FILL_3_OTHER FILL_3_NORMAL
+#define FILL_4_OTHER FILL_4_NORMAL
+#define FILL_5_OTHER FILL_5_NORMAL
+#define FILL_6_OTHER FILL_6_NORMAL
+#define FILL_7_OTHER FILL_7_NORMAL
+
+#endif /* !(_SPARC64_TTABLE_H) */
diff -u --recursive --new-file v2.1.50/linux/include/asm-sparc64/uaccess.h linux/include/asm-sparc64/uaccess.h
--- v2.1.50/linux/include/asm-sparc64/uaccess.h	Thu Jul 17 10:06:08 1997
+++ linux/include/asm-sparc64/uaccess.h	Sat Aug 16 09:51:10 1997
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.20 1997/07/13 18:23:45 davem Exp $ */
+/* $Id: uaccess.h,v 1.21 1997/07/31 07:37:25 davem Exp $ */
 #ifndef _ASM_UACCESS_H
 #define _ASM_UACCESS_H
 
@@ -30,8 +30,11 @@
 
 #define get_fs() (current->tss.current_ds)
 #define get_ds() (KERNEL_DS)
+
+extern spinlock_t scheduler_lock;
+
 #define set_fs(val)				\
-do {						\
+do {	spin_lock(&scheduler_lock);		\
 	current->tss.current_ds = (val);	\
 	if ((val) == KERNEL_DS) {		\
 		flushw_user ();			\
@@ -41,6 +44,7 @@
 	}					\
 	spitfire_set_secondary_context(current->tss.ctx); \
 	__asm__ __volatile__("flush %g6");	\
+	spin_unlock(&scheduler_lock);		\
 } while(0)
 
 #define __user_ok(addr,size) 1
diff -u --recursive --new-file v2.1.50/linux/include/linux/blk.h linux/include/linux/blk.h
--- v2.1.50/linux/include/linux/blk.h	Mon Jul  7 16:02:14 1997
+++ linux/include/linux/blk.h	Mon Aug 18 17:09:22 1997
@@ -97,6 +97,9 @@
 #ifdef CONFIG_AMIGA_Z2RAM
 extern int z2_init(void);
 #endif
+#ifdef CONFIG_MAC_FLOPPY
+extern int swim3_init(void);
+#endif
 
 extern void set_device_ro(kdev_t dev,int flag);
 void add_blkdev_randomness(int major);
diff -u --recursive --new-file v2.1.50/linux/include/linux/dcache.h linux/include/linux/dcache.h
--- v2.1.50/linux/include/linux/dcache.h	Thu Aug 14 20:49:17 1997
+++ linux/include/linux/dcache.h	Thu Aug 14 21:40:57 1997
@@ -97,7 +97,6 @@
 extern void d_delete(struct dentry *);
 
 /* allocate/de-allocate */
-extern void d_free(struct dentry *);
 extern struct dentry * d_alloc(struct dentry * parent, const struct qstr *name);
 extern void shrink_dcache(void);
 extern int d_invalidate(struct dentry *);
diff -u --recursive --new-file v2.1.50/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.1.50/linux/include/linux/fs.h	Thu Aug 14 20:49:17 1997
+++ linux/include/linux/fs.h	Mon Aug 18 17:09:10 1997
@@ -93,7 +93,7 @@
 /*
  * Flags that can be altered by MS_REMOUNT
  */
-#define MS_RMT_MASK (MS_RDONLY|MS_MANDLOCK)
+#define MS_RMT_MASK (MS_RDONLY|MS_MANDLOCK|MS_NOATIME)
 
 /*
  * Magic mount flag number. Has to be or-ed to the flag values.
diff -u --recursive --new-file v2.1.50/linux/include/linux/nfsd/nfsfh.h linux/include/linux/nfsd/nfsfh.h
--- v2.1.50/linux/include/linux/nfsd/nfsfh.h	Sun Jul 27 12:11:01 1997
+++ linux/include/linux/nfsd/nfsfh.h	Mon Aug 18 17:10:46 1997
@@ -137,6 +137,7 @@
 	if (fhp->fh_dverified) {
 		fh_unlock(fhp);
 		dput(fhp->fh_handle.fh_dentry);
+		fhp->fh_dverified = 0;
 	}
 }
 #else
@@ -159,6 +160,7 @@
 	} else {
 		fh_unlock(fhp);
 		dput(dentry);
+		fhp->fh_dverified = 0;
 	}
 }
 #endif
diff -u --recursive --new-file v2.1.50/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.1.50/linux/include/linux/proc_fs.h	Mon Aug  4 16:25:40 1997
+++ linux/include/linux/proc_fs.h	Mon Aug 18 17:09:11 1997
@@ -51,7 +51,8 @@
 	PROC_HARDWARE,
 	PROC_SLABINFO,
 	PROC_PARPORT,
-	PROC_OMIRR /* whether enabled or not */
+	PROC_OMIRR, /* whether enabled or not */
+	PROC_PPC_HTAB
 };
 
 enum pid_directory_inos {
@@ -181,6 +182,8 @@
 	PROC_SCSI_GVP11,
 	PROC_SCSI_ATARI,
 	PROC_SCSI_IDESCSI,
+	PROC_SCSI_MESH,
+	PROC_SCSI_53C94,
 	PROC_SCSI_SCSI_DEBUG,	
 	PROC_SCSI_NOT_PRESENT,
 	PROC_SCSI_FILE,                        /* I'm assuming here that we */
@@ -362,6 +365,7 @@
 extern struct inode_operations proc_ringbuf_inode_operations;
 #endif
 extern struct inode_operations proc_omirr_inode_operations;
+extern struct inode_operations proc_ppc_htab_inode_operations;
 
 #endif
 
@@ -378,3 +382,8 @@
 extern void proc_tty_init(void);
 extern void proc_tty_register_driver(struct tty_driver *driver);
 extern void proc_tty_unregister_driver(struct tty_driver *driver);
+
+/*
+ * proc_devtree.c
+ */
+extern void proc_device_tree_init(void);
diff -u --recursive --new-file v2.1.50/linux/include/linux/tty.h linux/include/linux/tty.h
--- v2.1.50/linux/include/linux/tty.h	Mon Jul  7 16:02:03 1997
+++ linux/include/linux/tty.h	Mon Aug 18 17:09:10 1997
@@ -74,6 +74,8 @@
 
 #define VIDEO_TYPE_SUN          0x50    /* Sun frame buffer. */
 
+#define VIDEO_TYPE_PMAC		0x60	/* PowerMacintosh frame buffer. */
+
 /*
  * This character is the same as _POSIX_VDISABLE: it cannot be used as
  * a c_cc[] character, but indicates that a particular special character
diff -u --recursive --new-file v2.1.50/linux/kernel/fork.c linux/kernel/fork.c
--- v2.1.50/linux/kernel/fork.c	Thu Aug 14 20:49:17 1997
+++ linux/kernel/fork.c	Mon Aug 18 16:13:34 1997
@@ -206,6 +206,7 @@
 static inline int dup_mmap(struct mm_struct * mm)
 {
 	struct vm_area_struct * mpnt, *tmp, **pprev;
+	int retval;
 
 	mm->mmap = mm->mmap_cache = NULL;
 	flush_cache_mm(current->mm);
@@ -213,19 +214,17 @@
 	for (mpnt = current->mm->mmap ; mpnt ; mpnt = mpnt->vm_next) {
 		struct dentry *dentry;
 
+		retval = -ENOMEM;
 		tmp = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
-		if (!tmp) {
-			exit_mmap(mm);
-			flush_tlb_mm(current->mm);
-			return -ENOMEM;
-		}
+		if (!tmp)
+			goto fail_nomem;
 		*tmp = *mpnt;
 		tmp->vm_flags &= ~VM_LOCKED;
 		tmp->vm_mm = mm;
 		tmp->vm_next = NULL;
 		dentry = tmp->vm_dentry;
 		if (dentry) {
-			dentry->d_count++;
+			dget(dentry);
 			if (tmp->vm_flags & VM_DENYWRITE)
 				dentry->d_inode->i_writecount--;
       
@@ -236,60 +235,79 @@
 			mpnt->vm_next_share = tmp;
 			tmp->vm_pprev_share = &mpnt->vm_next_share;
 		}
-		if (copy_page_range(mm, current->mm, tmp)) {
-			exit_mmap(mm);
-			flush_tlb_mm(current->mm);
-			return -ENOMEM;
-		}
-		if (tmp->vm_ops && tmp->vm_ops->open)
+
+		/* Copy the pages, but defer checking for errors */
+		retval = copy_page_range(mm, current->mm, tmp);
+		if (!retval && tmp->vm_ops && tmp->vm_ops->open)
 			tmp->vm_ops->open(tmp);
 
-		/* Ok, finally safe to link it in. */
+		/*
+		 * Link in the new vma even if an error occurred,
+		 * so that exit_mmap() can clean up the mess.
+		 */
 		if((tmp->vm_next = *pprev) != NULL)
 			(*pprev)->vm_pprev = &tmp->vm_next;
 		*pprev = tmp;
 		tmp->vm_pprev = pprev;
 
 		pprev = &tmp->vm_next;
+		if (retval)
+			goto fail_nomem;
 	}
 	flush_tlb_mm(current->mm);
 	return 0;
+
+fail_nomem:
+	exit_mmap(mm);
+	flush_tlb_mm(current->mm);
+	return retval;
 }
 
 static inline int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
 {
-	if (!(clone_flags & CLONE_VM)) {
-		struct mm_struct * mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL);
-		if (!mm)
-			return -1;
-		*mm = *current->mm;
-		init_new_context(mm);
-		mm->count = 1;
-		mm->def_flags = 0;
-		mm->mmap_sem = MUTEX;
-
-		/* It has not run yet, so cannot be present in anyone's
-		 * cache or tlb.
-		 */
-		mm->cpu_vm_mask = 0;
+	struct mm_struct * mm;
+	int retval;
 
-		tsk->mm = mm;
-		tsk->min_flt = tsk->maj_flt = 0;
-		tsk->cmin_flt = tsk->cmaj_flt = 0;
-		tsk->nswap = tsk->cnswap = 0;
-		if (new_page_tables(tsk))
-			goto free_mm;
-		if (dup_mmap(mm)) {
-			free_page_tables(mm);
-free_mm:
-			kmem_cache_free(mm_cachep, mm);
-			return -1;
-		}
+	if (clone_flags & CLONE_VM) {
+		current->mm->count++;
+		SET_PAGE_DIR(tsk, current->mm->pgd);
 		return 0;
 	}
-	current->mm->count++;
-	SET_PAGE_DIR(tsk, current->mm->pgd);
+
+	retval = -ENOMEM;
+	mm = kmem_cache_alloc(mm_cachep, SLAB_KERNEL);
+	if (!mm)
+		goto fail_nomem;
+	*mm = *current->mm;
+	init_new_context(mm);
+	mm->count = 1;
+	mm->def_flags = 0;
+	mm->mmap_sem = MUTEX;
+
+	/* It has not run yet, so cannot be present in anyone's
+	 * cache or tlb.
+	 */
+	mm->cpu_vm_mask = 0;
+
+	tsk->mm = mm;
+	tsk->min_flt = tsk->maj_flt = 0;
+	tsk->cmin_flt = tsk->cmaj_flt = 0;
+	tsk->nswap = tsk->cnswap = 0;
+	retval = new_page_tables(tsk);
+	if (retval)
+		goto free_mm;
+	retval = dup_mmap(mm);
+	if (retval)
+		goto free_pt;
 	return 0;
+
+free_pt:
+	free_page_tables(mm);
+free_mm:
+	tsk->mm = NULL;
+	kmem_cache_free(mm_cachep, mm);
+fail_nomem:
+	return retval;
 }
 
 static inline int copy_fs(unsigned long clone_flags, struct task_struct * tsk)
@@ -478,9 +496,9 @@
 bad_fork_cleanup_sighand:
 	exit_sighand(p);
 bad_fork_cleanup_fs:
-	exit_fs(p);
+	exit_fs(p); /* blocking */
 bad_fork_cleanup_files:
-	exit_files(p);
+	exit_files(p); /* blocking */
 bad_fork_cleanup:
 	charge_uid(current, -1);
 	if (p->exec_domain && p->exec_domain->module)
diff -u --recursive --new-file v2.1.50/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.1.50/linux/kernel/ksyms.c	Thu Aug 14 20:49:17 1997
+++ linux/kernel/ksyms.c	Fri Aug 15 15:34:49 1997
@@ -67,7 +67,6 @@
 #include <asm/irq.h>
 #ifdef __SMP__
 #include <linux/smp.h>
-#include <linux/smp_lock.h>
 #endif
 
 extern char *get_options(char *str, int *ints);
@@ -282,7 +281,6 @@
 /* Various random spinlocks we want to export */
 EXPORT_SYMBOL(tqueue_lock);
 EXPORT_SYMBOL(waitqueue_lock);
-EXPORT_SYMBOL(lk_lockmsg);
 #endif
 
 /* autoirq from  drivers/net/auto_irq.c */
diff -u --recursive --new-file v2.1.50/linux/mm/memory.c linux/mm/memory.c
--- v2.1.50/linux/mm/memory.c	Sun Jun 29 10:48:37 1997
+++ linux/mm/memory.c	Mon Aug 18 13:06:50 1997
@@ -291,19 +291,20 @@
 	return error;
 }
 
-static inline void free_pte(pte_t page)
+/*
+ * Return indicates whether a page was freed so caller can adjust rss
+ */
+static inline int free_pte(pte_t page)
 {
 	if (pte_present(page)) {
 		unsigned long addr = pte_page(page);
 		if (MAP_NR(addr) >= max_mapnr || PageReserved(mem_map+MAP_NR(addr)))
-			return;
+			return 0;
 		free_page(addr);
-		if (current->mm->rss <= 0)
-			return;
-		current->mm->rss--;
-		return;
+		return 1;
 	}
 	swap_free(pte_val(page));
+	return 0;
 }
 
 static inline void forget_pte(pte_t page)
@@ -314,22 +315,24 @@
 	}
 }
 
-static inline void zap_pte_range(pmd_t * pmd, unsigned long address, unsigned long size)
+static inline int zap_pte_range(pmd_t * pmd, unsigned long address, unsigned long size)
 {
 	pte_t * pte;
+	int freed;
 
 	if (pmd_none(*pmd))
-		return;
+		return 0;
 	if (pmd_bad(*pmd)) {
 		printk("zap_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
 		pmd_clear(pmd);
-		return;
+		return 0;
 	}
 	pte = pte_offset(pmd, address);
 	address &= ~PMD_MASK;
 	if (address + size > PMD_SIZE)
 		size = PMD_SIZE - address;
 	size >>= PAGE_SHIFT;
+	freed = 0;
 	for (;;) {
 		pte_t page;
 		if (!size)
@@ -340,32 +343,36 @@
 		if (pte_none(page))
 			continue;
 		pte_clear(pte-1);
-		free_pte(page);
+		freed += free_pte(page);
 	}
+	return freed;
 }
 
-static inline void zap_pmd_range(pgd_t * dir, unsigned long address, unsigned long size)
+static inline int zap_pmd_range(pgd_t * dir, unsigned long address, unsigned long size)
 {
 	pmd_t * pmd;
 	unsigned long end;
+	int freed;
 
 	if (pgd_none(*dir))
-		return;
+		return 0;
 	if (pgd_bad(*dir)) {
 		printk("zap_pmd_range: bad pgd (%08lx)\n", pgd_val(*dir));
 		pgd_clear(dir);
-		return;
+		return 0;
 	}
 	pmd = pmd_offset(dir, address);
 	address &= ~PGDIR_MASK;
 	end = address + size;
 	if (end > PGDIR_SIZE)
 		end = PGDIR_SIZE;
+	freed = 0;
 	do {
-		zap_pte_range(pmd, address, end - address);
+		freed += zap_pte_range(pmd, address, end - address);
 		address = (address + PMD_SIZE) & PMD_MASK; 
 		pmd++;
 	} while (address < end);
+	return freed;
 }
 
 /*
@@ -375,12 +382,21 @@
 {
 	pgd_t * dir;
 	unsigned long end = address + size;
+	int freed = 0;
 
 	dir = pgd_offset(mm, address);
 	while (address < end) {
-		zap_pmd_range(dir, address, end - address);
+		freed += zap_pmd_range(dir, address, end - address);
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
+	}
+	/*
+	 * Update rss for the mm_struct (not necessarily current->mm)
+	 */
+	if (mm->rss > 0) {
+		mm->rss -= freed;
+		if (mm->rss < 0)
+			mm->rss = 0;
 	}
 }
 
diff -u --recursive --new-file v2.1.50/linux/mm/mmap.c linux/mm/mmap.c
--- v2.1.50/linux/mm/mmap.c	Thu Jul 17 10:06:09 1997
+++ linux/mm/mmap.c	Mon Aug 18 13:16:18 1997
@@ -373,10 +373,12 @@
  *    Unmapping between to intermediate points, making a hole.
  *
  * Case 4 involves the creation of 2 new areas, for each side of
- * the hole.
+ * the hole.  If possible, we reuse the existing area rather than
+ * allocate a new one, and the return indicates whether the old
+ * area was reused.
  */
-static void unmap_fixup(struct vm_area_struct *area,
-		 unsigned long addr, size_t len)
+static int unmap_fixup(struct vm_area_struct *area, unsigned long addr,
+			 size_t len, struct vm_area_struct **extra)
 {
 	struct vm_area_struct *mpnt;
 	unsigned long end = addr + len;
@@ -391,7 +393,7 @@
 			area->vm_ops->close(area);
 		if (area->vm_dentry)
 			dput(area->vm_dentry);
-		return;
+		return 0;
 	}
 
 	/* Work out to one of the ends. */
@@ -403,17 +405,16 @@
 	} else {
 	/* Unmapping a hole: area->vm_start < addr <= end < area->vm_end */
 		/* Add end mapping -- leave beginning for below */
-		mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+		mpnt = *extra;
+		*extra = NULL;
 
-		if (!mpnt)
-			return;
 		mpnt->vm_mm = area->vm_mm;
 		mpnt->vm_start = end;
 		mpnt->vm_end = area->vm_end;
 		mpnt->vm_page_prot = area->vm_page_prot;
 		mpnt->vm_flags = area->vm_flags;
 		mpnt->vm_ops = area->vm_ops;
-		mpnt->vm_offset += (end - area->vm_start);
+		mpnt->vm_offset = area->vm_offset + (end - area->vm_start);
 		mpnt->vm_dentry = dget(area->vm_dentry);
 		if (mpnt->vm_ops && mpnt->vm_ops->open)
 			mpnt->vm_ops->open(mpnt);
@@ -421,18 +422,18 @@
 		insert_vm_struct(current->mm, mpnt);
 	}
 
-	/* Construct whatever mapping is needed. */
-	mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
-	if (!mpnt)
-		return;
-	*mpnt = *area;
-	if (mpnt->vm_ops && mpnt->vm_ops->open)
-		mpnt->vm_ops->open(mpnt);
+	/* Close the current area ... */
 	if (area->vm_ops && area->vm_ops->close) {
+		end = area->vm_end; /* save new end */
 		area->vm_end = area->vm_start;
 		area->vm_ops->close(area);
+		area->vm_end = end;
 	}
-	insert_vm_struct(current->mm, mpnt);
+	/* ... then reopen and reinsert. */
+	if (area->vm_ops && area->vm_ops->open)
+		area->vm_ops->open(area);
+	insert_vm_struct(current->mm, area);
+	return 1;
 }
 
 asmlinkage int sys_munmap(unsigned long addr, size_t len)
@@ -452,7 +453,8 @@
  */
 int do_munmap(unsigned long addr, size_t len)
 {
-	struct vm_area_struct *mpnt, *next, *free;
+	struct vm_area_struct *mpnt, *next, *free, *extra;
+	int freed;
 
 	if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr)
 		return -EINVAL;
@@ -471,6 +473,14 @@
 	if (!mpnt)
 		return 0;
 
+	/*
+	 * We may need one additional vma to fix up the mappings ... 
+	 * and this is the last chance for an easy error exit.
+	 */
+	extra = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+	if (!extra)
+		return -ENOMEM;
+
 	next = mpnt->vm_next;
 
 	/* we have mpnt->vm_next = next and addr < mpnt->vm_end */
@@ -486,19 +496,18 @@
 		free = mpnt;
 		mpnt = next;
 	}
-	if (free == NULL)
-		return 0;
 
 	/* Ok - we have the memory areas we should free on the 'free' list,
 	 * so release them, and unmap the page range..
 	 * If the one of the segments is only being partially unmapped,
 	 * it will put new vm_area_struct(s) into the address space.
 	 */
-	do {
+	freed = 0;
+	while ((mpnt = free) != NULL) {
 		unsigned long st, end, size;
 
-		mpnt = free;
 		free = free->vm_next;
+		freed = 1;
 
 		remove_shared_vm_struct(mpnt);
 
@@ -514,12 +523,19 @@
 		zap_page_range(current->mm, st, size);
 		flush_tlb_range(current->mm, st, end);
 
-		unmap_fixup(mpnt, st, size);
+		/*
+		 * Fix the mapping, and free the old area if it wasn't reused.
+		 */
+		if (!unmap_fixup(mpnt, st, size, &extra))
+			kmem_cache_free(vm_area_cachep, mpnt);
+	}
 
-		kmem_cache_free(vm_area_cachep, mpnt);
-	} while (free);
+	/* Release the extra vma struct if it wasn't used */
+	if (extra)
+		kmem_cache_free(vm_area_cachep, extra);
 
-	current->mm->mmap_cache = NULL;		/* Kill the cache. */
+	if (freed)
+		current->mm->mmap_cache = NULL;	/* Kill the cache. */
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.50/linux/net/ipv4/fib.c linux/net/ipv4/fib.c
--- v2.1.50/linux/net/ipv4/fib.c	Mon Jun 16 16:36:01 1997
+++ linux/net/ipv4/fib.c	Fri Aug 15 12:52:03 1997
@@ -2039,7 +2039,7 @@
 		fib_class_get_info
 	});
 	proc_net_register(&(struct proc_dir_entry) {
-		PROC_NET_RTRULES, 8, "rt_local",
+		PROC_NET_RTLOCAL, 8, "rt_local",
 		S_IFREG | S_IRUGO, 1, 0, 0,
 		0, &proc_net_inode_operations,
 		fib_local_get_info
diff -u --recursive --new-file v2.1.50/linux/net/socket.c linux/net/socket.c
--- v2.1.50/linux/net/socket.c	Sun Jul 20 20:41:59 1997
+++ linux/net/socket.c	Fri Aug 15 14:59:49 1997
@@ -648,28 +648,25 @@
 
 asmlinkage int sys_socket(int family, int type, int protocol)
 {
-	int fd, err;
+	int retval;
 	struct socket *sock;
 
 	lock_kernel();
 
-	if ((err = sock_create(family, type, protocol, &sock)) < 0)
+	retval = sock_create(family, type, protocol, &sock);
+	if (retval < 0)
 		goto out;
 
-	if ((fd = get_fd(sock->inode)) < 0) 
-	{
+	retval = get_fd(sock->inode);
+	if (retval < 0) {
 		sock_release(sock);
-		err = -EINVAL;
-	}
-	else
-	{
-		sock->file = current->files->fd[fd];
-		err = fd;
+		goto out;
 	}
 
+	sock->file = current->files->fd[retval];
 out:
 	unlock_kernel();
-	return err;
+	return retval;
 }
 
 /*
