diff -u --recursive --new-file v2.2.7/linux/CREDITS linux/CREDITS
--- v2.2.7/linux/CREDITS	Wed Apr 28 11:37:29 1999
+++ linux/CREDITS	Mon May 10 10:32:45 1999
@@ -256,6 +256,10 @@
 D: Configuration help text support
 D: Linux CD and Support Giveaway List
 
+N: Zoltan Boszormenyi
+E: zboszor@mol.hu
+D: MTRR emulation with Cyrix style ARR registers
+
 N: John Boyd
 E: boyd@cis.ohio-state.edu
 D: Co-author of wd7000 SCSI driver
diff -u --recursive --new-file v2.2.7/linux/Documentation/00-INDEX linux/Documentation/00-INDEX
--- v2.2.7/linux/Documentation/00-INDEX	Tue Feb 23 15:21:31 1999
+++ linux/Documentation/00-INDEX	Thu Apr 29 11:53:41 1999
@@ -38,7 +38,7 @@
 digiepca.txt
 	- info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
 exception.txt
-	- how linux v2.1 handles exceptions without verify_area etc.
+	- how Linux v2.2 handles exceptions without verify_area etc.
 filesystems/
 	- directory with info on the various filesystems that Linux supports.
 ftape.txt
@@ -52,11 +52,11 @@
 ioctl-number.txt
 	- how to implement and register device/driver ioctl calls.
 isdn/
-	- directory with info on the linux ISDN support, and supported cards.
+	- directory with info on the Linux ISDN support, and supported cards.
 java.txt
 	- info on the in-kernel binary support for Java(tm)
 joystick.txt
-	- info on using joystick devices (and driver) with linux.
+	- info on using joystick devices (and driver) with Linux.
 kbuild/
 	- directory with info about the kernel build process
 kmod.txt
@@ -72,7 +72,7 @@
 magic-number.txt
 	- list of magic numbers used to mark/protect kernel data structures.
 mandatory.txt
-	- info on the linux implementation of Sys V mandatory file locking.
+	- info on the Linux implementation of Sys V mandatory file locking.
 mca.txt
 	- info on supporting Micro Channel Architecture (e.g. PS/2) systems.
 md.txt
@@ -100,7 +100,7 @@
 pcwd-watchdog.txt
 	- info and sample code for using with the PC Watchdog reset card.
 powerpc/
-	- directory with info on using linux with the PowerPC.
+	- directory with info on using Linux with the PowerPC.
 ramdisk.txt
 	- short guide on how to set up and use the RAM disk.
 riscom8.txt
@@ -110,7 +110,7 @@
 scsi.txt
 	- short blurb on using SCSI support as a module.
 serial-console.txt
-	- how to set up linux with a serial line console as the default.
+	- how to set up Linux with a serial line console as the default.
 smart-config.txt
 	- description of the Smart Config makefile feature.
 smp.tex
diff -u --recursive --new-file v2.2.7/linux/Documentation/ARM-README linux/Documentation/ARM-README
--- v2.2.7/linux/Documentation/ARM-README	Sun Jun  7 11:16:25 1998
+++ linux/Documentation/ARM-README	Thu Apr 29 11:53:41 1999
@@ -70,8 +70,8 @@
   a 'make zImage' instead of 'make all'.
 
 
-Bug reports etc
----------------
+Bug reports etc.
+----------------
 
   Please send patches, bug reports and code for the ARM Linux project
   to linux@arm.uk.linux.org.  Patches will not be included into future
@@ -116,7 +116,7 @@
   at the top of the screen.  The colours have the following significance
   when run in a 16 colour mode with the default palette:
 
-    Stripes of White,Red,Yellow,Green:
+    Stripes of white, red, yellow, and green:
        Kernel does not support the processor architecture detected.
 
 
@@ -142,11 +142,11 @@
   HDC base to the source.
 
   As of 31/3/96 it works with two drives (you should get the ADFS
-  *configure harddrive set to 2). I've got an internal 20MB and a great
-  big external 5.25" FH 64MB drive (who could ever want more :-) ).
+  *configure hard drive set to 2). I've got an internal 20 MB and a great
+  big external 5.25" FH 64 MB drive (who could ever want more :-) ).
 
-  I've just got 240K/s off it (a dd with bs=128k); thats about half of what
-  RiscOS gets; but it's a heck of a lot better than the 50K/s I was getting
+  I've just got 240 K/s off it (a dd with bs=128k); that's about half of what
+  RiscOS gets, but it's a heck of a lot better than the 50 K/s I was getting
   last week :-)
 
   Known bug: Drive data errors can cause a hang; including cases where
diff -u --recursive --new-file v2.2.7/linux/Documentation/Changes linux/Documentation/Changes
--- v2.2.7/linux/Documentation/Changes	Fri Apr 16 14:47:30 1999
+++ linux/Documentation/Changes	Fri May  7 09:31:25 1999
@@ -105,7 +105,7 @@
 
   none            /dev/pts        devpts	gid=5,mode=620    0 0
 
-   (Note:  gid=5 is applicable for RedHat systems for which group "tty" has
+   (Note:  gid=5 is applicable for Red Hat systems for which group "tty" has
    gid 5.  Adjust according to your distribution.  Use mode=600 if you want
    "mesg n" to be default.)
 - Mount /dev/pts
@@ -433,7 +433,7 @@
 Xosview
 =======
 
-   /proc interface changes require a recent xosview.
+   Changes to the /proc interface require a recent xosview.
 
 RealPlayer
 ==========
@@ -444,8 +444,8 @@
 software available shortly.  In the mean time, you can always try
 backing up your copy of rvplayer, and then editing it by:
 
-   dd if=/dev/zero of=rvplayer bs=1 count=1 seek=657586 conv=notrunc dd
-if=/dev/zero of=rvplayer bs=1 count=1 seek=665986 conv=notrunc
+   dd if=/dev/zero of=rvplayer bs=1 count=1 seek=657586 conv=notrunc
+   dd if=/dev/zero of=rvplayer bs=1 count=1 seek=665986 conv=notrunc
 
    If you're lucky, you'll then have sound....
 
diff -u --recursive --new-file v2.2.7/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.2.7/linux/Documentation/Configure.help	Wed Apr 28 11:37:29 1999
+++ linux/Documentation/Configure.help	Mon May 10 10:32:45 1999
@@ -17,6 +17,8 @@
 #     ftp://ftp-pavia1.linux.it/pub/linux/Configure.help
 #   - Polish, by Cezar Cichocki (cezar@cs.net.pl), at
 #     http://www.cs.net.pl/~cezar/Kernel
+#   - German, by Jörg Strebel (jstrebel@suse.de) and Karl Eichwalder
+#     (ke@suse.de), at http://www.suse.de/~ke/kernel/Configure.de.help.gz
 #
 # 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
@@ -69,7 +71,7 @@
   in some special cases. Detailed bug reports from people familiar
   with the kernel internals are usually welcomed by the developers
   (before submitting bug reports, please read the documents README,
-  MAINTAINERS, Documentation/BUG-HUNTING, and
+  MAINTAINERS, REPORTING_BUGS, Documentation/BUG-HUNTING, and
   Documentation/oops-tracing.txt in the kernel source). 
 
   Unless you intend to help test and develop a feature or driver that
@@ -127,12 +129,38 @@
   available via FTP (user: anonymous) in
   ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.) This means that it is a
   good idea to say Y here if you intend to use this kernel on
-  different machines. More information about the internals of Linux
-  math coprocessor emulation can be found in
-  arch/i386/math-emu/README.
+  different machines. 
+
+  More information about the internals of the Linux math coprocessor
+  emulation can be found in arch/i386/math-emu/README.
 
   If you are not sure, say Y; apart from resulting in a 45 KB bigger
   kernel, it won't hurt.
+  
+Timer and CPU usage LEDs
+CONFIG_LEDS
+  If you define this option, the LEDs on your machine will be used
+  to provide useful information about your current system status.
+
+  If you are compiling a kernel for a NetWinder or EBSA-285, you
+  will be able to select which LEDs are active using the options
+  below. If you are compiling a kernel for the EBSA-110 however,
+  the red LED will simply flash regularly to indicate that the
+  system is still functional. It is still safe to say yes here if
+  you have a CATS system, but the driver will do nothing.
+
+Timer LED
+CONFIG_LEDS_TIMER
+  If you say yes here, one of the system LEDs (the green one on the
+  NetWinder or the amber one on the EBSA285) will flash regularly to
+  indicate that the system is still operational. This is mainly
+  useful to kernel hackers who are debugging unstable kernels.
+
+CPU usage LED
+CONFIG_LEDS_CPU
+  If you say yes here, the red LED will be used to give a good real
+  time indication of CPU usage, by lighting whenever the idle task
+  is not currently executing.
 
 Kernel FP software completion
 CONFIG_MATHEMU
@@ -218,8 +246,8 @@
 
   To use the loop device, you need the losetup utility and a recent
   version of the mount program, both contained in the util-linux
-  package (available via FTP (user: anonymous) from
-  ftp://ftp.win.tue.nl/pub/linux/util/).
+  package. The location and current version number of util-linux is
+  contained in the file Documentation/Changes.
 
   Note that this loop device has nothing to do with the loopback
   device used for network connections from the machine to itself.
@@ -276,7 +304,7 @@
 
   To fine-tune IDE drive/interface parameters for improved
   performance, look for the hdparm package at
-  ftp://metalab.unc.edu:/pub/Linux/kernel/patches/diskdrives/
+  ftp://metalab.unc.edu/pub/Linux/kernel/patches/diskdrives/
 
   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),
@@ -475,7 +503,7 @@
 
 Generic PCI IDE chipset support
 CONFIG_BLK_DEV_IDEPCI
-  Enable this for PCI systems which use IDE drive(s).
+  Say Y here for PCI systems which use IDE drive(s).
   This option helps the IDE driver to automatically detect and
   configure all PCI-based IDE interfaces in your system.
   
@@ -560,15 +588,16 @@
   This driver is enabled at runtime using the "ide0=dtc2278" kernel
   boot parameter. It enables support for the secondary IDE interface
   of the DTC-2278 card, and permits faster I/O speeds to be set as
-  well. See the Documentation/ide.txt and dtc2278.c files for more
-  info.
+  well. See the Documentation/ide.txt and drivers/block/dtc2278.c
+  files for more info.
 
 Holtek HT6560B support
 CONFIG_BLK_DEV_HT6560B
   This driver is enabled at runtime using the "ide0=ht6560b" kernel
   boot parameter. It enables support for the secondary IDE interface
   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.
+  See the Documentation/ide.txt and drivers/block/ht6560b.c files for
+  more info.
 
 PROMISE DC4030 support (EXPERIMENTAL)
 CONFIG_BLK_DEV_PDC4030
@@ -618,36 +647,26 @@
   If you say Y here, you also need to say Y to "Use DMA by default
   when available", above.
 
-  Please read the comments at the top of drivers/block/via82C586.c
-
   If unsure, say N.
 
 CMD646 chipset support (EXPERIMENTAL)
 CONFIG_BLK_DEV_CMD646
   Say Y here if you have an IDE controller like this.
 
-HPT343 chipset support (EXPERIMENTAL)
-CONFIG_BLK_DEV_HPT343
-  This driver adds up to 4 more EIDE devices sharing a single
-  interrupt. The HPT343 chipset in its current form is a non-bootable
-  PCI UDMA controller. This driver requires dynamic tuning of the
-  chipset during the ide-probe at boot. It is reported to support DVD
-  II drives, by the manufacturer.
-
-  Please read the comments at the top of drivers/block/hpt343.c
-
 QDI QD6580 support
 CONFIG_BLK_DEV_QD6580
   This driver is enabled at runtime using the "ide0=qd6580" kernel
   boot parameter. It permits faster I/O speeds to be set. See the
-  files Documentation/ide.txt and qd6580.c for more info.
+  files Documentation/ide.txt and drivers/block/qd6580.c for more
+  info.
 
 UMC 8672 support
 CONFIG_BLK_DEV_UMC8672
   This driver is enabled at runtime using the "ide0=umc8672" kernel
   boot parameter. It enables support for the secondary IDE interface
   of the UMC-8672, and permits faster I/O speeds to be set as well.
-  See the files Documentation/ide.txt and umc8672.c for more info.
+  See the files Documentation/ide.txt and drivers/block/umc8672.c for
+  more info.
 
 ALI M14xx support
 CONFIG_BLK_DEV_ALI14XX
@@ -655,7 +674,7 @@
   boot parameter. It enables support for the secondary IDE interface
   of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
   I/O speeds to be set as well. See the files Documentation/ide.txt
-  and ali14xx.c for more info.
+  and drivers/block/ali14xx.c for more info.
 
 XT hard disk support
 CONFIG_BLK_DEV_XD
@@ -1034,6 +1053,24 @@
   board uses the R4300 and a R5230 CPUs. For more information about
   this board see http://www.algor.co.uk.
 
+IDE card support
+CONFIG_BLK_DEV_IDE_CARDS
+  On Acorn systems, enable this if you wish to use an IDE interface
+  expansion card. If you do not or are unsure, say N to this.
+
+ICS IDE interface
+CONFIG_BLK_DEV_IDE_ICS
+  On Acorn systems, enable this if you wish to use the ICS IDE
+  interface card.  This is not required for ICS partition support.
+  If you are unsure, say N to this.
+
+ADFS partition support
+CONFIG_BLK_DEV_PART
+  This allows Linux on Acorn systems to determine its partitions in
+  the 'non-ADFS' partition area of the hard disk - usually located
+  after the ADFS partition.  You are probably using this system, so
+  you should enable it.
+
 Support for Mips Magnum 4000
 CONFIG_MIPS_MAGNUM_4000
   This is a machine with a R4000 100 MHz CPU. To compile a Linux
@@ -1870,7 +1907,7 @@
   card. You do this by inserting several instances of the module 
   matroxfb.o into the kernel with insmod, supplying the parameter
   "dev=N" where N is 0, 1, etc. for the different Matrox devices.
-  
+
 MDA text console (dual-headed)
 CONFIG_MDA_CONSOLE
   Say Y here if you have an old MDA or monochrome Hercules graphics
@@ -2030,7 +2067,7 @@
 Parallel-port support
 CONFIG_PARPORT
   If you want to use devices connected to your machine's parallel port
-  (the connector at the computer with 25 holes), e.g. printer, Zip
+  (the connector at the computer with 25 holes), e.g. printer, ZIP
   drive, PLIP link (Parallel Line Internet Protocol is mainly used to
   create a mini network by connecting the parallel ports of two local
   machines) etc., then you need to say Y here; please read
@@ -2057,10 +2094,13 @@
 CONFIG_PARPORT_PC
   You should say Y here if you have a PC-style parallel port. All IBM
   PC compatible computers and some Alphas have PC-style parallel
-  ports. This code is also available as a module. If you want to it as
-  a module ( = code which can be inserted in and removed from the
+  ports. 
+
+  This code is also available as a module. If you want to compile it
+  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_pc.o.
+  
   If unsure, say Y.
 
 Support foreign hardware
@@ -2231,8 +2271,18 @@
   the Linux router will also be able to take the packet's source
   address into account. Furthermore, if you also say Y to "IP: use TOS
   value as routing key" below, the TOS (Type-Of-Service) field of the
-  packet can be used for routing decisions as well.
-
+  packet can be used for routing decisions as well. In addition, if
+  you say Y here and to "IP: fast network address translation" below,
+  the router will also be able to modify source and destination
+  addresses of forwarded packets.
+
+  If you are interested in this, please see the preliminary
+  documentation at http://www.compendium.com.ar/policy-routing.txt and
+  ftp://post.tepkom.ru/pub/vol2/Linux/docs/advanced-routing.tex. You
+  will need supporting software from ftp://ftp.inr.ac.ru/ip-routing/
+  
+  If unsure, say N.
+  
 IP: equal cost multipath
 CONFIG_IP_ROUTE_MULTIPATH
   Normally, the routing tables specify a single action to be taken in
@@ -2275,9 +2325,9 @@
 CONFIG_IP_ROUTE_NAT
   If you say Y here, your router will be able to modify source and
   destination addresses of packets that pass through it, in a manner
-  you specify. Please see
-  http://www.csn.tu-chemnitz.de/HyperNews/get/linux-ip-nat.html for
-  details. 
+  you specify. General information about Network Address Translation
+  can be gotten from the document
+  http://www.csn.tu-chemnitz.de/~mha/linux-ip-nat/diplom/nat.html
 
 IP: optimize as router not host
 CONFIG_IP_ROUTER
@@ -2601,12 +2651,12 @@
   Sometimes it is useful to give several IP addresses to a single
   physical network interface (serial port or Ethernet card). The most
   common case is that you want to serve different WWW or ftp documents
-  to the outside according to which of your host names was used to
+  to the outside depending on which of your host names was used to
   connect to you. This is called "multihosting" or "virtual domains"
   or "virtual hosting services" 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 a program
-  like lynx or netscape) and also in the Virtual-Hosting-HOWTO,
+  like lynx or netscape) and also in the Virtual-Services-HOWTO,
   available via FTP (user: anonymous) from
   ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
@@ -2920,36 +2970,45 @@
 CONFIG_IPDDP
   This allows IP networking for users who only have AppleTalk
   networking available. This feature is experimental. With this
-  driver, you can either encapsulate IP inside AppleTalk (e.g. if your
-  Linux box is stuck on an AppleTalk only network) or decapsulate
-  (e.g. if you want your Linux box to act as an Internet gateway for a
-  zoo of AppleTalk connected Macs). You decide which one of the two
-  you want in the following two questions; you can say Y to only one
-  of them. Please see Documentation/networking/ipddp.txt for more
-  information.
+  driver, you can encapsulate IP inside AppleTalk (e.g. if your Linux
+  box is stuck on an AppleTalk only network) or decapsulate (e.g. if
+  you want your Linux box to act as an Internet gateway for a zoo of
+  AppleTalk connected Macs). Please see the file
+  Documentation/networking/ipddp.txt for more information.
+
+  If you say Y here, the AppleTalk-IP support will be compiled into
+  the kernel. In this case, you can either use encapsulation or
+  decapsulation, but not both. With the following two questions, you
+  decide which one you want.
 
-  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 is called ipddp.o. If you want to compile it as a module,
-  say M here and read Documentation/modules.txt.
+  If you say M here, the AppleTalk-IP support will be compiled as a
+  module ( = code which can be inserted in and removed from the
+  running kernel whenever you want, read Documentation/modules.txt).
+  The module is called ipddp.o. In this case, you will be able to use
+  both encapsulation and decapsulation simultaneously, by loading two
+  copies of the module and specifying different values for the module
+  option ipddp_mode. 
 
 IP to AppleTalk-IP Encapsulation support
 CONFIG_IPDDP_ENCAP
-  If you say Y here, the kernel will be able to encapsulate IP packets
-  inside AppleTalk frames; this is useful if your Linux box is stuck
-  on an AppleTalk network (which hopefully contains a decapsulator
-  somewhere). Please see Documentation/networking/ipddp.txt for more
-  information. If you say Y here, you cannot say Y to "AppleTalk-IP to
-  IP Decapsulation support", below.
+  If you say Y here, the AppleTalk-IP code will be able to encapsulate
+  IP packets inside AppleTalk frames; this is useful if your Linux box
+  is stuck on an AppleTalk network (which hopefully contains a
+  decapsulator somewhere). Please see
+  Documentation/networking/ipddp.txt for more information. If you said
+  Y to "AppleTalk-IP driver support" above and you say Y here, then
+  you cannot say Y to "AppleTalk-IP to IP Decapsulation support",
+  below.
 
 AppleTalk-IP to IP Decapsulation support
 CONFIG_IPDDP_DECAP
-  If you say Y here, the kernel will be able to decapsulate
+  If you say Y here, the AppleTalk-IP code will be able to decapsulate
   AppleTalk-IP frames to IP packets; this is useful if you want your
-  Linux box to act as an Internet gateway for an AppleTalk
-  network. Please see Documentation/networking/ipddp.txt for more
-  information. If you say Y here, you cannot say Y to "IP to
-  AppleTalk-IP Encapsulation support", above.
+  Linux box to act as an Internet gateway for an AppleTalk network.
+  Please see Documentation/networking/ipddp.txt for more information.
+  If you said Y to "AppleTalk-IP driver support" above and you say Y
+  here, then you cannot say Y to "IP to AppleTalk-IP Encapsulation
+  support", above.
 
 Apple/Farallon LocalTalk PC card support
 CONFIG_LTPC
@@ -3526,7 +3585,7 @@
 CONFIG_BLK_DEV_SR
   If you want to use a SCSI CDROM under Linux, say Y and read the
   SCSI-HOWTO and the CDROM-HOWTO from
-  ftp://metalab.unc.edu:/pub/Linux/docs/HOWTO. Also make sure to say Y
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Also make sure to say Y
   or M to "ISO 9660 CDROM filesystem support" later.
 
   This driver is also available as a module ( = code which can be
@@ -3554,7 +3613,8 @@
   other devices, it's possible that you'll have to write the driver
   software yourself, so have a look at the SCSI-HOWTO and at the
   SCSI-Programming-HOWTO, both available via FTP (user: anonymous) in
-  ftp://metalab.unc.edu:/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Please read the file
+  Documentation/scsi-generic.txt for more information.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -3956,33 +4016,33 @@
   tagged command queuing and fast synchronous data transfers up to 80
   MB/s with wide FAST-40 LVD devices and controllers.
 
-  An additionnal driver named SYM53C8XX (a.k.a 896 driver) can also be 
-  configured. See the help on the SYM53C8XX driver for more information.
+  Recent versions of the 53C8XX chips are better supported by the
+  option "SYM53C8XX SCSI support", below.
 
-  Note: there is another driver for the 53c8xx family of controllers
+  Note: there is yet another driver for the 53c8xx family of controllers
   ("NCR53c7,8xx SCSI support" above). If you want to use them both,
   you need to say M to both and build them as modules, but only one
-  may be active at a time. If you have a 53c8xx board, it's best to
-  use this driver.
+  may be active at a time. If you have a 53c8xx board, you probably do
+  not want to use the "NCR53c7,8xx SCSI support".
 
   Please read drivers/scsi/README.ncr53c8xx for more information.
 
 SYM53C8XX SCSI support
 CONFIG_SCSI_SYM53C8XX
-  The 896 driver for Linux (a.k.a. sym53c8xx) is derivated from the 
-  ncr53c8xx driver and has been heavily reworked and enhanced to 
-  fully support all the features of recent 53C8XX chips, notably the 
-  hardware phase mismatch feature of the SYM53C896.
-
-  For that to be achieved without additionnal complexity, support of 
-  old 8XX chips has been dropped. If your system uses either a 
-  810 rev. < 16, a 815, or a 825 rev. < 16 PCI SCSI processor, you must 
-  use the generic NCR53C8XX driver or configure both the NCR53C8XX and 
-  the SYM53C8XX drivers either as module or linked to the kernel image.
+  This driver supports all the features of recent 53C8XX chips (used
+  in PCI SCSI controllers), notably the hardware phase mismatch
+  feature of the SYM53C896.
+
+  Older versions of the 53C8XX chips are not supported by this
+  driver. If your system uses either a 810 rev. < 16, a 815, or a 825
+  rev. < 16 PCI SCSI processor, you must use the generic NCR53C8XX
+  driver ("NCR53C8XX SCSI support" above) or configure both the
+  NCR53C8XX and this SYM53C8XX drivers either as module or linked to
+  the kernel image.
 
   When both drivers are linked to the kernel, the SYM53C8XX driver is 
   called first at initialization and you can use the 'excl=ioaddr' 
-  driver boot option to exclude attachement of adapters by the SYM53C8XX 
+  driver boot option to exclude attachment of adapters by the SYM53C8XX 
   driver. For instance, entering 'sym53c8xx=excl:0xb400,excl=0xc000' at 
   lilo prompt prevents adapters at io address 0xb400 and 0xc000 from 
   being attached by the SYM53C8XX driver, thus allowing the NCR53C8XX 
@@ -4105,12 +4165,11 @@
 
 include support for the NCR PQS/PDS SCSI card
 CONFIG_SCSI_NCR53C8XX_PQS_PDS
-  This allows the driver to detect a special adapter produced by NCR
+  Say Y here if you have a special SCSI adapter produced by NCR
   corporation called a PCI Quad SCSI or PCI Dual SCSI. You do not need
-  this if you do not have one of these adapters. However, since this 
-  device is detected as a specific PCI device, this option is quite 
-  safe. This option is only supported by the SYM53C8XX driver (not 
-  by the NCR53C8XX driver).
+  this if you do not have one of these adapters. However, since this
+  device is detected as a specific PCI device, this option is quite
+  safe.
 
   The common answer here is N, but answering Y is safe.
 
@@ -4215,17 +4274,6 @@
   say M here and read Documentation/modules.txt. The module will be
   called initio.o
 
-Initio 91XXU(W) SCSI support
-CONFIG_SCSI_INITIO
-  This is support for the Initio 91XXU(W) SCSI host adapter.
-  Please read the SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://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. The module will be
-  called initio.o
-
 PAS16 SCSI support
 CONFIG_SCSI_PAS16
   This is support for a SCSI host adapter. It is explained in section
@@ -4243,7 +4291,7 @@
 CONFIG_SCSI_INIA100
   This is support for the Initio INI-A100U2W SCSI host adapter.
   Please read the SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.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),
@@ -4309,8 +4357,8 @@
   IQ-PCI-10, IQ_PCI-D) except for the PCI-basic card. (This latter
   card is supported by the "AM53/79C974 PCI SCSI" driver). 
 
-  If you say Y here, make sure to say Y to choose "BIOS" at the
-  question "PCI access mode".
+  If you say Y here, make sure to choose "BIOS" at the question "PCI
+  access mode".
 
   Please read the file drivers/scsi/README.qlogicisp. You should also
   read the SCSI-HOWTO, available via FTP (user: anonymous) at
@@ -4321,6 +4369,15 @@
   The module will be called qlogicisp.o. If you want to compile it as
   a module, say M here and read Documentation/modules.txt.
 
+Qlogic ISP FC SCSI support
+CONFIG_SCSI_QLOGIC_FC
+  This is a driver for the QLogic ISP2100 SCSI-FCP host adapter.
+
+  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 qlogicfc.o. If you want to compile it as
+  a module, say M here and read Documentation/modules.txt.
+
 Seagate ST-02 and Future Domain TMC-8xx SCSI support
 CONFIG_SCSI_SEAGATE
   These are 8-bit SCSI controllers; the ST-01 is also supported by
@@ -4444,20 +4501,22 @@
 
 Symbios Logic sym53c416 support
 CONFIG_SCSI_SYM53C416
-  This is support for the sym53c416 SCSI host adapter. This is the
-  SCSI adapter that comes with some hp scanners. This driver requires that
-  the sym53c416 is configured first using some sort of pnp configuration
-  program (e.g. isapnp) or by a PnP aware BIOS. If you are using isapnp then
-  you need to compile it as a module and then load it using insmod after
-  isapnp has run. The parameters of the configured card(s) should be passed
-  to the driver. The format is:
+  This is support for the sym53c416 SCSI host adapter, the SCSI
+  adapter that comes with some HP scanners. This driver requires that
+  the sym53c416 is configured first using some sort of pnp
+  configuration program (e.g. isapnp) or by a PnP aware BIOS. If you
+  are using isapnp then you need to compile this driver as a module
+  and then load it using insmod after isapnp has run. The parameters
+  of the configured card(s) should be passed to the driver. The format
+  is:
 
     insmod sym53c416 sym53c416=<base>,<irq> [sym53c416_1=<base>,<irq>]
 
-  There is support for up to four adapters. 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.
+  There is support for up to four adapters. 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
+  sym53c416.o. 
 
 Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support
 CONFIG_SCSI_DC390T
@@ -4518,6 +4577,12 @@
   say M here and read Documentation/modules.txt. The module will be
   called megaraid.o.
 
+###
+### What is this?
+###
+#Concurrent IO commands on MegaRAID
+#CONFIG_MEGARAID_MULTI_IO
+
 GDT SCSI Disk Array Controller support
 CONFIG_SCSI_GDTH
   This is a driver for all SCSI Disk Array Controllers (EISA/ISA/PCI) 
@@ -4710,7 +4775,7 @@
   you want to use under Linux (make sure you know its name because you
   will be asked for it and read the Ethernet-HOWTO (especially if you
   plan to use more than one network card under Linux), available from
-  ftp://metalab.unc.edu:/pub/Linux/docs/HOWTO/mini) or if you want to
+  ftp://metalab.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 null modem cables) or CSLIP
   (compressed SLIP) or PPP (Point to Point Protocol, a better and
@@ -4721,7 +4786,7 @@
 
   Make sure to read the NET-3-HOWTO. Eventually, you will have to read
   Olaf Kirch's excellent and free book "Network Administrator's
-  Guide", to be found in ftp://metalab.unc.edu:/pub/Linux/docs/LDP. If
+  Guide", to be found in ftp://metalab.unc.edu/pub/Linux/docs/LDP. If
   unsure, say Y.
 
 Dummy net driver support
@@ -4827,7 +4892,7 @@
 
   To use PPP, you need an additional program called pppd as described
   in Documentation/networking/ppp.txt and in the PPP-HOWTO, available
-  from ftp://metalab.unc.edu:/pub/Linux/docs/HOWTO. If you upgrade
+  from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If you upgrade
   from an older kernel, you might need to upgrade pppd as well. The
   PPP option enlarges your kernel by about 16 KB.
 
@@ -5142,11 +5207,13 @@
 
     *** This option is NOT COMPATIBLE with several important ***
     *** networking options: especially CONFIG*FIREWALL.      ***
+    *** Say N here if you intend to use Linux as a firewall. ***
 
   However, it will work with all options in CONFIG_IP_ADVANCED_ROUTER
-  section (except for CONFIG_IP_ROUTE_TOS&FWMARK). At the moment, few devices
-  support fast switching (tulip is one of them, modified 8390 can be
-  found at ftp://ftp.inr.ac.ru/ip-routing/fastroute-8390.tar.gz). 
+  section (except for CONFIG_IP_ROUTE_TOS and CONFIG_IP_ROUTE_FWMARK).
+  At the moment, few devices support fast switching (tulip is one of
+  them, modified 8390 can be found at
+  ftp://ftp.inr.ac.ru/ip-routing/fastroute-8390.tar.gz).
 
   If unsure, say N.
 
@@ -5752,6 +5819,18 @@
   module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
 
+3c527 support
+CONFIG_ELMC_II
+  If you have a network (Ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available via FTP (user: anonymous) in
+  ftp://metalab.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 3c527.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.
+
 3c509/3c579 support
 CONFIG_EL3
   If you have a network (Ethernet) card belonging to the 3Com
@@ -6560,6 +6639,20 @@
   The module will be called mcd.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
+IRQ channel for Mitsumi CD-ROM
+CONFIG_MCD_IRQ
+  This allows you to specify the default value of the IRQ used by the
+  driver. This setting can be overridden by passing the "mcd="
+  parameter to the kernel at boot time (or at module load time if you
+  said M to "Standard Mitsumi CDROM support").
+
+I/O base address for Mitsumi CD-ROM
+CONFIG_MCD_BASE
+  This allows you to specify the default value of the I/O base address
+  used by the driver. This setting can be overridden by passing the
+  "mcd=" parameter to the kernel at boot time (or at module load time
+  if you said M to "Standard Mitsumi CDROM support").
+
 Mitsumi [XA/MultiSession] support
 CONFIG_MCDX
   Use this driver if you want to be able to read XA or MultiSession
@@ -6750,6 +6843,13 @@
   ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini. Probably the quota
   support is only useful for multi user systems. If unsure, say N.
 
+Acorn's ADFS filesystem support (read only) (EXPERIMENTAL)
+CONFIG_ADFS_FS
+  The Advanced Disk File System is the filesystem used on floppy and
+  hard disks by Acorn Systems.  Currently in development, as a read-
+  only driver for hard disks.  These should be the first partition
+  (eg. /dev/[sh]d?1) on each of your drives.  If unsure, say N.
+
 Minix fs support
 CONFIG_MINIX_FS
   Minix is a simple operating system used in many classes about OS's.
@@ -7032,10 +7132,13 @@
   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/.
+
+  In either case, you will need support software; the respective
+  locations are given in the file Documentation/Changes in the NFS
+  section.
+
   Please read the NFS-HOWTO, available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu:/pub/Linux/docs/HOWTO. 
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   The NFS server is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -7213,7 +7316,8 @@
   Unixes can create and mount hard disk partitions and diskettes using
   this filesystem as well. Saying Y here will allow you to read from
   these partitions; if you also want to write to them, say Y to the
-  experimental "UFS filesystem write support", below.
+  experimental "UFS filesystem write support", below. Please read the
+  file Documentation/filesystems/ufs.txt for more information.
 
   If you only intend to mount files from some other Unix over the
   network using NFS, you don't need the UFS filesystem support (but
@@ -7333,7 +7437,7 @@
 SMB filesystem support (to mount Windows shares etc...)
 CONFIG_SMB_FS
   SMB (Server Message Block) is the protocol Windows for Workgroups
-  (WfW), Windows 95, Windows NT and OS/2 Lan Manager use to share
+  (WfW), Windows 95/98, Windows NT and OS/2 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. Currently, this
@@ -7397,7 +7501,7 @@
   mount NetWare file server volumes and to access them just like any
   other Unix directory. For details, please read the file
   Documentation/filesystems/ncpfs.txt in the kernel source and the
-  IPX-HOWTO on ftp://metalab.unc.edu:/pub/Linux/docs/howto.
+  IPX-HOWTO on ftp://metalab.unc.edu/pub/Linux/docs/howto.
 
   You do not have to say Y here if you want your Linux box to act as a
   file *server* for Novell NetWare clients.
@@ -7445,23 +7549,22 @@
 
 Lowercase DOS filenames on LONG namespace volume
 CONFIG_NCPFS_SMALLDOS
-  Saying Y here will convert every filename with creator/owner DOS
-  namespace on NetWare servers to lowercase characters as silently
-  kernel does when you mount  NetWare file server volumes with DOS
-  namespace without OS2/LONG namespace support. Saying N here will
-  give you these filenames with uppercase characters.
-  
-  This is  only cosmetic option  because of OS2/LONG  namespace is
-  case  insensitive.  The  only major  reason for  this option  is
-  backward  compatibility when  you want  to do  step from  DOS to
-  OS2/LONG  namespace support.  Long filenames  (created by Win95)
-  will not be affected.
-
-  This  option  does not  solve a  problem that  filenames  appear
-  differently  in Linux box  and in MS  environment because  of MS
-  does an additional  conversions on client side.  You can achieve
-  simillar effects  enabling ncpfs  option "Allow  using of Native
-  Language Support" below.
+  If you say Y here, every filename on a NetWare server volume using
+  the OS2/LONG namespace will be converted to lowercase characters.
+  (For regular NetWare file server volumes with DOS namespace, this is
+  done automatically, even if you say N here.) Saying N here will give
+  you these filenames in uppercase.
+  
+  This is only a cosmetic option since the OS2/LONG namespace is case
+  insensitive. The only major reason for this option is backward
+  compatibility when moving from DOS to OS2/LONG namespace support.
+  Long filenames (created by Win95) will not be affected.
+
+  This option does not solve the problem that filenames appear
+  differently under Linux and under Windows, since Windows does an
+  additional conversions on the client side. You can achieve similar
+  effects by saying Y to "Allow using of Native Language Support"
+  below.
 
 Allow mounting of volume subdirectories
 CONFIG_NCPFS_MOUNT_SUBDIR
@@ -7483,10 +7586,10 @@
 
 Allow using of Native Language Support
 CONFIG_NCPFS_NLS
-  Allows you to use codepages and I/O charsets for file name translation
-  between file system on server and input/output. This may be useful,
-  if you want to access to the server with other operating systems,
-  e.g. Windows 95. See also NLS for more Information.
+  Allows you to use codepages and I/O charsets for file name
+  translation between the server file system and input/output. This
+  may be useful, if you want to access the server with other operating
+  systems, e.g. Windows 95. See also NLS for more Information.
 
   To select codepages and I/O charsets use ncpfs-2.2.0.13 or newer.
 
@@ -7494,12 +7597,11 @@
 CONFIG_NCPFS_EXTRAS
   This enables the use of symbolic links and an execute permission
   bit on NCPFS. The file server need not have long name space or NFS
-  name space loaded for these to work, they are stored using rarely
-  found combinations of Hidden, System and Shared flags.
+  name space loaded for these to work.
+
+  To use the new attributes, it is recommended to use the flags
+  '-f 600 -d 755' on the ncpmount command line.
 
-  To use the new attributes, you are recommended to use the flags
-  '-f 600 -d 755' on the ncpmount commandline.
-  
 nls codepage 437
 CONFIG_NLS_CODEPAGE_437
   The Microsoft fat filesystem family can deal with filenames in
@@ -8035,14 +8137,24 @@
   Provides support for the SyncLink ISA and PCI
   multiprotocol serial adapters. These adapters
   support asynchronous and HDLC bit synchronous
-  communication up to 10Mbps (PCI adapter)
+  communication up to 10Mbps (PCI adapter).
+
+  This driver can only be built as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called synclink.o. If you want to do that, say M
+  here.
 
 Synchronous HDLC line discipline support
 CONFIG_N_HDLC
   Allows synchronous HDLC communications with
   tty device drivers that support synchronous
   HDLC such as the Microgate SyncLink adapter.
-  
+
+  This driver can only be built as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called n_hdlc.o. If you want to do that, say M
+  here.
+
 Hayes ESP serial port support
 CONFIG_ESPSERIAL
   This is a driver which supports Hayes ESP serial ports. Both single
@@ -8087,7 +8199,7 @@
   If you want to say Y here, you need to have the C library glibc 2.1
   or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
   Read the instructions in Documentation/Changes pertaining to pseudo
-  terminals. It's save to say N.
+  terminals. It's safe to say N.
 
 Maximum number of Unix98 PTYs in use (0-2048)
 CONFIG_UNIX98_PTY_COUNT
@@ -8183,7 +8295,7 @@
   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. Using the "-R" option
   of the Linux mouse managing program gpm (available from
-  ftp://metalab.unc.edu:/pub/Linux/system/Daemons) solves this
+  ftp://metalab.unc.edu/pub/Linux/system/Daemons) solves this
   problem, or you can get the "mconv" utility also from metalab.
 
 C&T 82C710 mouse port support (as on TI Travelmate)
@@ -8554,17 +8666,24 @@
 
 MTRR control and configuration
 CONFIG_MTRR
-  On Intel Pentium Pro and Pentium II systems the Memory Type Range
-  Registers (MTRRs) may be used to control processor access to memory
-  ranges. This is most useful when you have a video (VGA) card on a
-  PCI or AGP bus. Enabling write-combining allows bus write transfers
-  to be combined into a larger transfer before bursting over the
-  PCI/AGP bus. This can increase performance of image write operations
-  2.5 times or more. This option creates a /proc/mtrr file which may
-  be used to manipulate your MTRRs. Typically the X server should use
-  this. This should have a reasonably generic interface so that
-  similar control registers on other processors can be easily
-  supported.
+  On Intel P6 family processors (Pentium Pro, Pentium II and later)
+  the Memory Type Range Registers (MTRRs) may be used to control
+  processor access to memory ranges. This is most useful when you have
+  a video (VGA) card on a PCI or AGP bus. Enabling write-combining
+  allows bus write transfers to be combined into a larger transfer
+  before bursting over the PCI/AGP bus. This can increase performance
+  of image write operations 2.5 times or more. This option creates a
+  /proc/mtrr file which may be used to manipulate your
+  MTRRs. Typically the X server should use this. This should have a
+  reasonably generic interface so that similar control registers on
+  other processors can be easily supported.
+
+  The Cyrix 6x86, 6x86MX and M II processors have Address Range
+  Registers (ARRs) which provide a similar functionality to MTRRs. For
+  these, the ARRs are used to emulate the MTRRs.
+
+  The AMD K6-2 (stepping 8 and above) and K6-3 processors have two
+  MTRRs. These are supported.
 
   Saying Y here also fixes a problem with buggy SMP BIOSes which only
   set the MTRRs for the boot CPU and not the secondary CPUs. This can
@@ -8893,6 +9012,17 @@
   The module will be called nvram.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
+Atomwide Serial Support
+CONFIG_ATOMWIDE_SERIAL
+  If you have an Atomwide Serial card for an Acorn system, say Y to
+  this option.  The driver can handle 1, 2, or 3 port cards.
+  If unsure, say N
+
+The Serial Port Dual Serial Port
+CONFIG_DUALSP_SERIAL
+  If you have the Serial Port's dual serial card for an Acorn system,
+  say Y to this option.  If unsure, say N
+
 Joystick support
 CONFIG_JOYSTICK
   If you have a joystick, you can say Y here to enable generic
@@ -8996,6 +9126,35 @@
   If you have the Serial Port's dual serial card for an Acorn system,
   say Y to this option. If unsure, say N
 
+NetWinder Button
+CONFIG_NWBUTTON
+  If you enable this driver and create a character device node
+  /dev/nwbutton with major and minor numbers 10 and 158 ("man mknod"),
+  then every time the orange button is pressed a number of times, the
+  number of times the button was pressed will be written to that device.
+  This is most useful for applications, as yet unwritten, which perform
+  actions based on how many times the button is pressed in a row.
+  Do not hold the button down for too long, as the driver does not alter
+  the behaviour of the hardware reset circuitry attached to the button;
+  it will still execute a hard reset if the button is held down for
+  longer than approximately five seconds.
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt. The module will be called nwbutton.o.
+  Most people will answer Y to this question and "Reboot Using Button"
+  below to be able to initiate a system shutdown from the button.
+
+Reboot Using Button
+CONFIG_NWBUTTON_REBOOT
+  If you enable this option, then you will be able to initiate a system
+  shutdown and reboot by pressing the orange button a number of times.
+  The number of presses to initiate the shutdown is two by default, but
+  this can be altered by modifying the value of NUM_PRESSES_REBOOT in
+  nwbutton.h and recompiling the driver or, if you compile the driver as
+  a module, you can specify the number of presses at load time with
+  "insmod button reboot_count=<something>".
+
 Sound card support
 CONFIG_SOUND
   If you have a sound card in your computer, i.e. if it can say more
@@ -9037,18 +9196,19 @@
 
 Persistent DMA buffers
 CONFIG_SOUND_DMAP
-  Linux can often have problems allocating DMA buffers for ISA cards on
-  machines with more than 16MB of RAM. This is because ISA DMA buffers
-  must exist below the 16MB boundry and it is quite possible that we
-  can't find a large enough free block in this region after the machine
-  has been running for any amount of time. If you say Y here the DMA
-  buffers (64Kb) will be allocated at boot time and kept until the
-  shutdown. This option is only usefull if you say Y to OSS sound
-  modules. If you say M to OSS sound modules then you can just pass to
-  the sound.o module a "dmabuf=1" command-line argument.
+  Linux can often have problems allocating DMA buffers for ISA sound
+  cards on machines with more than 16MB of RAM. This is because ISA
+  DMA buffers must exist below the 16MB boundary and it is quite
+  possible that a large enough free block in this region cannot be
+  found after the machine has been running for a while. If you say Y
+  here the DMA buffers (64Kb) will be allocated at boot time and kept
+  until the shutdown. This option is only useful if you said Y to
+  "OSS sound modules", above. If you said M to "OSS sound modules"
+  then you can get the persistent DMA buffer functionality by passing
+  the command-line argument "dmabuf=1" to the sound.o module.
 
   Say Y unless you have 16MB or less RAM or a PCI sound card.
- 
+
 Support for Aztech Sound Galaxy (non-PnP) cards
 CONFIG_SOUND_SGALAXY
   This module initializes the older non Plug and Play sound galaxy
@@ -9556,6 +9716,11 @@
   differs slightly from OSS/Free, so PLEASE READ
   Documentation/sound/sonicvibes.
 
+Rockwell WaveArtist
+CONFIG_SOUND_WAVEARTIST
+  Say Y here to include support for the Rockwell WaveArtist sound
+  system.  This driver is mainly for the NetWinder.
+
 Are you using a crosscompiler
 CONFIG_CROSSCOMPILE
   Say Y here if you are compiling the kernel on a different
@@ -10513,11 +10678,21 @@
   motherboard will usually use a MACE (Medium Access Control for
   Ethernet) interface. Say Y to include support for the MACE chip.
 
+  This driver is also available as a module called mace.o ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
+
 BMAC (G3 ethernet) support
 CONFIG_BMAC
   Say Y for support of BMAC Ethernet interfaces. These are used on G3
   computers. 
 
+  This driver is also available as a module called bmac.o ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
+
 Video For Linux
 CONFIG_VIDEO_DEV
   Support for audio/video capture and overlay devices and FM radio
@@ -10686,11 +10861,27 @@
 CONFIG_RADIO_ZOLTRIX_PORT
   Enter the I/O port of your Zoltrix radio card.
 
+ADS Cadet AM/FM Tuner
+CONFIG_RADIO_CADET
+  Say Y here if this is your AM/FM radio card.
+
+  In order to control your radio card, you will need to use programs
+  that are compatible with the Video for Linux API. Information on 
+  this API and pointers to "v4l" programs may be found on the WWW at
+  http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW,
+  you need to have access to a machine on the Internet that has a 
+  program like lynx or netscape.
+
+  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 radio-cadet.o
+
 Miro PCM20 Radio
 CONFIG_RADIO_MIROPCM20
-  Choose Y here if you have this FM radio card. You also need the
-  PCM12/PCM20 ACI mixer in additional low level sound drivers for this
-  to work.
+  Choose Y here if you have this FM radio card. You also need to say Y
+  to "ACI mixer (miroPCM12/PCM20)" (in "additional low level sound
+  drivers") for this to work.
 
   In order to control your radio card, you will need to use programs
   that are compatible with the Video for Linux API. Information on 
@@ -10772,6 +10963,9 @@
   from the running kernel whenever you want). If you want to compile
   it as a module, say M here and read Documentation/modules.txt.
 
+#
+# ARM options
+#
 CPU Optimization
 CONFIG_CPU_ARM2
   This selects the processor type of your CPU. This is only used to
@@ -10788,40 +10982,154 @@
   to set this option to, please consult any information supplied with
   your system.
 
-Include support for CATS boards
+Include support for Chalice CATS boards
 CONFIG_CATS
-  Say Y here if you wish to include support for the extra hardware
-  found in Chalice CATS machines. The resulting kernel will still run
-  on an EBSA-285 but will be slightly larger. If in doubt say N.
+  Say Y here if you intend to run this kernel on a CATS system.
+
+Include support for Intel EBSA285
+CONFIG_ARCH_EBSA285
+  Say Y here if you intend to run this kernel on an EBSA-285 evaluation
+  board.
+
+Include support for the NetWinder
+CONFIG_ARCH_NETWINDER
+  Say Y here if you intend to run this kernel on the NetWinder.
+
+Math emulation
+CONFIG_NWFPE
+  Say Y to include the NWFPE floating point emulator in the kernel. This
+  is necessary to run most binaries. Linux does not currently support
+  floating point hardware so you need to say Y here even if your machine
+  has an FPA or floating point co-processor podule.
+
+  It is also possible to say M to build the emulator as a module
+  (nwfpe.o) or indeed to leave it out altogether. However, unless you
+  know what you are doing this can easily render your machine unbootable.
+  Saying Y is the safe option.
+
+  You may say N here if you are going to load the Acorn FPEmulator
+  early in the bootup.
+
+DS1620 Thermometer support
+CONFIG_DS1620
+  Say Y here to include support for the thermal management hardware
+  found in the NetWinder. This driver allows the user to control the
+  temperature set points and to read the current temperature.
+
+  It is also possible to say M here to build it as a module (ds1620.o)
+  It is recommended to be used on a NetWinder, but it is not a
+  necessity.
 
-Debug kernel errors
+Verbose kernel error messages
 CONFIG_DEBUG_ERRORS
   This option controls verbose debugging information which can be
-  printed when the kernel detects an internal error. Verbose debugging
-  information is useful when tracking down kernel problems, but it
-  will be meaning less for non-kernel hackers. It's safe for everyone
-  to say Y.
-
-Build Tools Selection
-CONFIG_BINUTILS_NEW
-  Say Y here if and only if you're using GCC 2.8.1/EGCS with a
-  binutils version >= 2.8.1 to compile the kernel (check with "gcc
-  --version" and "ld -v").
+  printed when the kernel detects an internal error. This debugging
+  information is useful to kernel hackers when tracking down problems,
+  but mostly meaningless to other people. It's safe to say Y unless
+  you are concerned with the code size or don't want to see these
+  messages.
 
 Compile kernel with frame pointer
 CONFIG_FRAME_POINTER
-  If you say Y here, the resulting kernel will be slightly larger, but
-  it will give useful debugging/error results. If you don't debug the
-  kernel, you can say N.
+  If you say Y here, the resulting kernel will be slightly larger and
+  slower, but it will give useful debugging information. If you don't
+  debug the kernel, you can say N.
+
+User fault debugging
+CONFIG_DEBUG_USER
+  When a user program crashes due to an exception, the kernel can print
+  a brief message explaining what the problem was. This is sometimes
+  helpful for debugging but serves no purpose on a production system.
+  Most people should say N here.
+
+Include gdb debugging information in kernel binary
+CONFIG_DEBUG_INFO
+  Say Y here to include source-level debugging information in the
+  `vmlinux' binary image. This is handy if you want to use gdb or
+  addr2line to debug the kernel. It has no impact on the in-memory
+  footprint of the running kernel but it can increase the amount of
+  time and disk space needed for compilation. If in doubt say N.
+
+Split initialisation functions into discardable section
+CONFIG_TEXT_SECTIONS
+  Normally code that is only used during initialisation is collected
+  into a special area of the kernel so that it can be discarded and
+  the memory reclaimed when initialisation is complete. In addition,
+  if the kernel you wish to build is able to run on multiple
+  architectures, it allows the unused code to be discarded. Some
+  versions of binutils, however, have a bug that causes the kernel
+  to crash during startup when this option is enabled. Say Y unless
+  you experience problems that you suspect may be caused by this.
+
+Disable pgtable cache
+CONFIG_NO_PGT_CACHE
+  Normally the kernel maintains a `quicklist' of preallocated pagetable
+  structures in order to increase performance. On machines with very
+  few pages this may however be a loss. Say Y here to disable the pgtable
+  cache.
+
+RISC OS personality
+CONFIG_ARTHUR
+  Say Y here to include the kernel code necessary if you want to run
+  Acorn RISC OS/Arthur binaries under Linux. This code is still very 
+  experimental; if this sounds frightening, say N and sleep in peace.
+  You can also say M here to compile this support as a module (which
+  will be called arthur.o).
 
 Initial kernel command line
 CONFIG_CMDLINE
-  On some architectures (EBSA285, EBSA110 and Corel NetWinder), there
-  is currently no way for the boot loader to pass arguments to the
-  kernel. For these architectures, you should supply some command-line
-  options at build time by entering them here. As a minimum, you
-  should specify the memory size and the root device (e.g., mem=64M
-  root=/dev/nfs)
+  On some architectures (EBSA110 and CATS), there is currently no way
+  for the boot loader to pass arguments to the kernel. For these
+  architectures, you should supply some command-line options at build
+  time by entering them here. As a minimum, you should specify the
+  memory size and the root device (eg, mem=64M root=/dev/nfs)
+
+Hardware alignment trap
+CONFIG_ALIGNMENT_TRAP
+  ARM processors can not fetch/store information which is not naturally
+  aligned on the bus, ie, a 4 byte fetch must start at an address divisable
+  by 4.  On 32-bit ARM processors, these instructions can be emulated in
+  software with a severe performance impact. This is necessary for correct
+  operation of some network protocols.  With an IP-only configuration
+  it is safe to say N, otherwise say Y.
+
+21285 serial port support
+CONFIG_SERIAL_21285
+  If you have a machine based on a 21285 (Footbridge) StrongARM/PCI
+  bridge you can enable its onboard serial port by enabling this
+  option. The device has major ID 4, minor 64.
+
+Console on 21285 serial port
+CONFIG_SERIAL_21285_CONSOLE
+  If you have enabled the serial port on the 21285 footbridge you can
+  make it the console by answering 'Y' to this option.
+
+Footbridge Mode
+CONFIG_HOST_FOOTBRIDGE
+  The 21285 Footbridge chip can operate in either `host mode' or
+  `add-in' mode.  Say Y if your 21285 is in host mode, and therefore
+  is the configuration master, otherwise say N.
+
+MFM harddisk support
+CONFIG_BLK_DEV_MFM
+  Support the MFM hard drives on the Acorn Archimedes both
+  on-board the A4x0 motherboards and via the Acorn MFM podules.
+  Drives upto 64MB are supported. If you haven't got one of these
+  machines or drives just say 'N'.
+
+Old Archimedes floppy (1772) support
+CONFIG_BLK_DEV_FD1772
+  Support the floppy drive on the Acorn Archimedes (A300, A4x0, A540,
+  R140 and R260) series of computers; it supports only 720K floppies
+  at the moment. If you don't have one of these machines just answer
+  'N'.
+
+Autodetect hard drive geometry
+CONFIG_BLK_DEV_MFM_AUTODETECT
+  If you answer 'Y' the MFM code will attempt to automatically detect
+  the cylinders/heads/sectors count on your hard drive. WARNING: This
+  sometimes doesn't work and it also does some dodgy stuff which
+  potentially might damage your drive.
 
 IrDA Protocols
 CONFIG_IRDA
@@ -10834,7 +11142,7 @@
   as well. For more information, see the file
   Documentation/networking/irda.txt. You also want to read the
   IR-HOWTO, available from
-  ftp://metalab.unc.edu:/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This support is also available as a module. If you want to compile
   it as a module, say M here and read Documentation/modules.txt. The
@@ -10864,17 +11172,6 @@
 
   If unsure, say N.
 
-IrDA Recycle RR's
-CONFIG_IRDA_RECYCLE_RR
-  In the normal life of the IrLAP protocol, it sends a lot of small RR
-  (Receive Ready) frames over the link (at least when it has nothing
-  else to do). Saying Y to this option will make IrLAP recycle these
-  frames thus avoiding many alloc_skb's and kfree_skb's. To do this it
-  will only buffer one of these frame which is enough for the normal
-  case.
-
-  If unsure, say Y.
-
 IrDA Debug
 CONFIG_IRDA_DEBUG
   Say Y here if you want the IrDA subsystem to write debug information
@@ -10912,21 +11209,9 @@
 
   The IrLAN protocol can be used to talk with infrared access points 
   like the HP NetbeamIR, or the ESI JetEye NET. You can also connect 
-  to another Linux machine running the IrLAN protocol for ac-hoc 
+  to another Linux machine running the IrLAN protocol for ad-hoc 
   networking!
 
-IrOBEX Protocol
-CONFIG_IROBEX
-  Say Y here if you want to build support for the IrOBEX protocol. If
-  you want to compile it as a module, say M here and read
-  Documentation/modules.txt. The module does not actually implement
-  the IrOBEX protocol since that protocol lives in user space, but it 
-  contains the necessary functions to interface the user-space stuff
-  with the kernel. So you will need to have the user-space library and
-  programs that can use this library installed as well to be able to
-  use the IrOBEX protocol. This module will hopefully be replaced by
-  IrDA sockets in the future.
-
 IrCOMM Protocol
 CONFIG_IRCOMM
   Say Y here if you want to build support for the IrCOMM protocol. If
@@ -11331,7 +11616,7 @@
 # LocalWords:  COSA SRP muni cz kas cosa Alteon AceNIC acenic VTOC OSes GMT SAx
 # LocalWords:  Inspiron localtime INTS Thinkpads Ralf Brown's Flightstick NNN
 # LocalWords:  Xterminator Blackhawk NN mpu ioports DCA HPDCA HPLANCE DIO Corel
-# LocalWords:  GemTek gemtek CMDLINE IrDA PDA's irmanager irattach RR AVA DN
+# LocalWords:  GemTek gemtek CMDLINE IrDA PDA's irmanager irattach RR AVA DN rg
 # LocalWords:  uit dagb irda LSAP IrLMP RR's IrLAP IR alloc skb's kfree skb's
 # LocalWords:  GZIP IrLAN NetbeamIR ESI JetEye IrOBEX IrCOMM TTY's minicom dti
 # LocalWords:  ircomm ircomm pluto thiguchi IrTTY Linux's bps NetWinder MIR NSC
@@ -11340,3 +11625,4 @@
 # LocalWords:  alphalinux GOBIOS csn chemnitz nat ACARD AMI MegaRAID megaraid
 # LocalWords:  QNXFS ISI isicom xterms Apollos VPN RCPCI rcpci sgi visws pcmcia
 # LocalWords:  IrLPT UIRCC Tecra
+
diff -u --recursive --new-file v2.2.7/linux/Documentation/arm/Netwinder linux/Documentation/arm/Netwinder
--- v2.2.7/linux/Documentation/arm/Netwinder	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/Netwinder	Sun May  2 09:51:16 1999
@@ -0,0 +1,78 @@
+NetWinder specific documentation
+================================
+
+The NetWinder is a small low-power computer, primarily designed
+to run Linux.  It is based around the StrongARM RISC processor,
+DC21285 PCI bridge, with PC-type hardware glued around it.
+
+Port usage
+==========
+
+Min    - Max	Description
+---------------------------
+0x0000 - 0x000f	DMA1
+0x0020 - 0x0021	PIC1
+0x0060 - 0x006f	Keyboard
+0x0070 - 0x007f	RTC
+0x0080 - 0x0087	DMA1
+0x0088 - 0x008f	DMA2
+0x00a0 - 0x00a3	PIC2
+0x00c0 - 0x00df	DMA2
+0x0180 - 0x0187	IRDA
+0x01f0 - 0x01f6	ide0
+0x0201		Game port
+0x0203		RWA010 configuration read
+0x0220 - ?	SoundBlaster
+0x0250 - ?	WaveArtist
+0x0279		RWA010 configuration index
+0x02f8 - 0x02ff	Serial ttyS1
+0x0300 - 0x031f	Ether10
+0x0338		GPIO1
+0x033a		GPIO2
+0x0370 - 0x0371	W83977F configuration registers
+0x0388 - ?	AdLib
+0x03c0 - 0x03df	VGA
+0x03f6		ide0
+0x03f8 - 0x03ff	Serial ttyS0
+0x0400 - 0x0408	DC21143
+0x0480 - 0x0487	DMA1
+0x0488 - 0x048f	DMA2
+0x0a79		RWA010 configuration write
+0xe800 - 0xe80f	ide0/ide1 BM DMA
+
+
+Interrupt usage
+===============
+
+IRQ	type	Description
+---------------------------
+ 0	ISA	100Hz timer
+ 1	ISA	Keyboard
+ 2	ISA	cascade
+ 3	ISA	Serial ttyS1
+ 4	ISA	Serial ttyS0
+ 5	ISA	PS/2 mouse
+ 6	ISA	IRDA
+ 7	ISA	Printer
+ 8	ISA	RTC alarm
+ 9	ISA
+10	ISA	GP10 (Orange reset button)
+11	ISA
+12	ISA	WaveArtist
+13	ISA
+14	ISA	hda1
+15	ISA
+
+DMA usage
+=========
+
+DMA	type	Description
+---------------------------
+ 0	ISA	IRDA
+ 1	ISA
+ 2	ISA	cascade
+ 3	ISA	WaveArtist
+ 4	ISA
+ 5	ISA
+ 6	ISA
+ 7	ISA	WaveArtist
diff -u --recursive --new-file v2.2.7/linux/Documentation/arm/README linux/Documentation/arm/README
--- v2.2.7/linux/Documentation/arm/README	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/README	Sun May  2 09:51:16 1999
@@ -0,0 +1,139 @@
+			   ARM Linux 2.2.3
+			   ===============
+
+      * NOTE * The ARM support in the mainstream Linux kernel sources
+    is not up to date.  Please check ftp.arm.uk.linux.org:/pub/armlinux
+                             for latest updates.
+
+Compilation of kernel
+---------------------
+
+  In order to compile ARM Linux, you will need a compiler capable of
+  generating ARM ELF code with GNU extensions.  GCC-2.7.2.2 ELF, GCC 2.8.1
+  and EGCS are good compilers.  Note that GCC-2.7.2.2 ELF is rare, and
+  you probably don't have it.
+
+  To build ARM Linux natively, you shouldn't have to alter the ARCH = line in
+  the top level Makefile.  However, if you don't have the ARM Linux ELF tools
+  installed as default, then you should change the CROSS_COMPILE line as
+  detailed below.
+
+  If you wish to cross-compile, then alter the following lines in the top
+  level make file:
+
+    ARCH = <whatever>
+	with
+    ARCH = arm
+
+	and
+
+    CROSS_COMPILE=
+	to
+    CROSS_COMPILE=<your-path-to-your-compiler-without-gcc>
+	eg.
+    CROSS_COMPILE=arm-linux-
+
+  Do a 'make config', followed by 'make dep', and finally 'make Image' to
+  build the kernel (arch/arm/boot/Image).  A compressed image can be built
+  by doing a 'make zImage' instead of 'make Image'.
+
+
+Bug reports etc
+---------------
+
+  Please send patches, bug reports and code for the ARM Linux project
+  to linux@arm.linux.org.uk  Patches will not be included into future
+  kernels unless they come to me (or the relevant person concerned).
+
+  When sending bug reports, please ensure that they contain all relevant
+  information, eg. the kernel messages that were printed before/during
+  the problem, what you were doing, etc.
+
+  For patches, please include some explanation as to what the patch does
+  and why (if relevant).
+
+
+Modules
+-------
+
+  Although modularisation is supported (and required for the FP emulator),
+  each module on an arm2/arm250/arm3 machine when is loaded will take
+  memory up to the next 32k boundary due to the size of the pages.  Hence is
+  modularisation on these machines really worth it?
+
+  However, arm6 and up machines allow modules to take multiples of 4k, and
+  as such Acorn RiscPCs and other architectures using these processors can
+  make good use of modularisation.
+
+
+ADFS Image files
+----------------
+
+  You can access image files on your ADFS partitions by mounting the ADFS
+  partition, and then using the loopback device driver.  You must have
+  losetup installed.
+
+  Please note that the PCEmulator DOS partitions have a partition table at
+  the start, and as such, you will have to give '-o offset' to losetup.
+
+
+Request to developers
+---------------------
+
+  When writing device drivers which include a separate assembler file, please
+  include it in with the C file, and not the arch/arm/lib directory.  This
+  allows the driver to be compiled as a loadable module without requiring
+  half the code to be compiled into the kernel image.
+
+  In general, try to avoid using assembler unless it is really necessary.  It
+  makes drivers far less easy to port to other hardware.
+
+
+ST506 hard drives
+-----------------
+
+  The ST506 hard drive controllers seem to be working fine (if a little
+  slowly).  At the moment they will only work off the controllers on an
+  A4x0's motherboard, but for it to work off a Podule just requires
+  someone with a podule to add the addresses for the IRQ mask and the
+  HDC base to the source.
+
+  As of 31/3/96 it works with two drives (you should get the ADFS
+  *configure harddrive set to 2). I've got an internal 20MB and a great
+  big external 5.25" FH 64MB drive (who could ever want more :-) ).
+
+  I've just got 240K/s off it (a dd with bs=128k); thats about half of what
+  RiscOS gets; but it's a heck of a lot better than the 50K/s I was getting
+  last week :-)
+
+  Known bug: Drive data errors can cause a hang; including cases where
+  the controller has fixed the error using ECC. (Possibly ONLY
+  in that case...hmm).
+
+
+1772 Floppy
+-----------
+  This also seems to work OK, but hasn't been stressed much lately.  It
+  hasn't got any code for disc change detection in there at the moment which
+  could be a bit of a problem!  Suggestions on the correct way to do this
+  are welcome.
+
+
+Kernel entry (head-armv.S)
+--------------------------
+  The initial entry into the kernel made via head-armv.S uses architecture
+  independent code.  The architecture is selected by the value of 'r1' on
+  entry, which must be kept unique.  You can register a new architecture
+  by mailing the following details to rmk@arm.uk.linux.org.  Please give
+  the mail a subject of 'Register new architecture':
+
+    Name: <name of your architecture>
+    ARCHDIR: <name of include/asm-arm/arch-* directory>
+    Description:
+    <description of your architecture>
+
+  Please follow this format - it is an automated system.  You should
+  receive a reply the next day.
+
+---
+Russell King (27/03/1999)
diff -u --recursive --new-file v2.2.7/linux/Documentation/arm/nwfpe/NOTES linux/Documentation/arm/nwfpe/NOTES
--- v2.2.7/linux/Documentation/arm/nwfpe/NOTES	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/nwfpe/NOTES	Sun May  2 09:51:16 1999
@@ -0,0 +1,29 @@
+There seems to be a problem with exp(double) and our emulator.  I haven't
+been able to track it down yet.  This does not occur with the emulator
+supplied by Russell King.
+
+I also found one oddity in the emulator.  I don't think it is serious but
+will point it out.  The ARM calling conventions require floating point
+registers f4-f7 to be preserved over a function call.  The compiler quite
+often uses an stfe instruction to save f4 on the stack upon entry to a
+function, and an ldfe instruction to restore it before returning.
+
+I was looking at some code, that calculated a double result, stored it in f4
+then made a function call. Upon return from the function call the number in
+f4 had been converted to an extended value in the emulator.
+
+This is a side effect of the stfe instruction.  The double in f4 had to be
+converted to extended, then stored.  If an lfm/sfm combination had been used,
+then no conversion would occur.  This has performance considerations.  The
+result from the function call and f4 were used in a multiplication.  If the
+emulator sees a multiply of a double and extended, it promotes the double to
+extended, then does the multiply in extended precision.
+
+This code will cause this problem:
+
+double x, y, z;
+z = log(x)/log(y);
+
+The result of log(x) (a double) will be calculated, returned in f0, then
+moved to f4 to preserve it over the log(y) call.  The division will be done
+in extended precision, due to the stfe instruction used to save f4 in log(y).
diff -u --recursive --new-file v2.2.7/linux/Documentation/arm/nwfpe/README linux/Documentation/arm/nwfpe/README
--- v2.2.7/linux/Documentation/arm/nwfpe/README	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/nwfpe/README	Sun May  2 09:51:16 1999
@@ -0,0 +1,70 @@
+This directory contains the version 0.92 test release of the NetWinder 
+Floating Point Emulator.
+
+The majority of the code was written by me, Scott Bambrough It is
+written in C, with a small number of routines in inline assembler
+where required.  It was written quickly, with a goal of implementing a
+working version of all the floating point instructions the compiler
+emits as the first target.  I have attempted to be as optimal as
+possible, but there remains much room for improvement.
+
+I have attempted to make the emulator as portable as possible.  One of
+the problems is with leading underscores on kernel symbols.  Elf
+kernels have no leading underscores, a.out compiled kernels do.  I
+have attempted to use the C_SYMBOL_NAME macro wherever this may be
+important.
+
+Another choice I made was in the file structure.  I have attempted to
+contain all operating system specfic code in one module (fpmodule.*).
+All the other files contain emulator specific code.  This should allow
+others to port the emulator to NetBSD for instance relatively easily.
+
+The floating point operations are based on SoftFloat Release 2, by
+John Hauser.  SoftFloat is a software implementation of floating-point
+that conforms to the IEC/IEEE Standard for Binary Floating-point
+Arithmetic.  As many as four formats are supported: single precision,
+double precision, extended double precision, and quadruple precision.
+All operations required by the standard are implemented, except for
+conversions to and from decimal.  We use only the single precision,
+double precision and extended double precision formats.  The port of
+SoftFloat to the ARM was done by Phil Blundell, based on an earlier
+port of SoftFloat version 1 by Neil Carson for NetBSD/arm32.
+
+The file README.FPE contains a description of what has been implemented
+so far in the emulator.  The file TODO contains a information on what 
+remains to be done, and other ideas for the emulator.
+
+Bug reports, comments, suggestions should be directed to me at
+<scottb@corelcomputer.com>.  General reports of "this program doesn't
+work correctly when your emulator is installed" are useful for
+determining that bugs still exist; but are virtually useless when
+attempting to isolate the problem.  Please report them, but don't
+expect quick action.  Bugs still exist.  The problem remains in isolating
+which instruction contains the bug.  Small programs illustrating a specific
+problem are a godsend.
+
+Legal Notices
+-------------
+
+The NetWinder Floating Point Emulator is free software.  Everything Corel
+has written is provided under the GNU GPL.  See the file COPYING for copying
+conditions.  Excluded from the above is the SoftFloat code.  John Hauser's 
+legal notice for SoftFloat is included below.
+
+-------------------------------------------------------------------------------
+SoftFloat Legal Notice
+
+SoftFloat was written by John R. Hauser.  This work was made possible in
+part by the International Computer Science Institute, located at Suite 600,
+1947 Center Street, Berkeley, California 94704.  Funding was partially
+provided by the National Science Foundation under grant MIP-9311980.  The
+original version of this code was written as part of a project to build
+a fixed-point vector processor in collaboration with the University of
+California at Berkeley, overseen by Profs. Nelson Morgan and John Wawrzynek.
+
+THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE.  Although reasonable effort
+has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
+TIMES RESULT IN INCORRECT BEHAVIOR.  USE OF THIS SOFTWARE IS RESTRICTED TO
+PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
+AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
+-------------------------------------------------------------------------------
diff -u --recursive --new-file v2.2.7/linux/Documentation/arm/nwfpe/README.FPE linux/Documentation/arm/nwfpe/README.FPE
--- v2.2.7/linux/Documentation/arm/nwfpe/README.FPE	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/nwfpe/README.FPE	Sun May  2 09:51:16 1999
@@ -0,0 +1,156 @@
+The following describes the current state of the NetWinder's floating point
+emulator.
+
+In the following nomenclature is used to describe the floating point
+instructions.  It follows the conventions in the ARM manual.
+
+<S|D|E> = <single|double|extended>, no default
+{P|M|Z} = {round to +infinity,round to -infinity,round to zero},
+          default = round to nearest
+
+Note: items enclosed in {} are optional.
+
+Floating Point Coprocessor Data Transfer Instructions (CPDT)
+------------------------------------------------------------
+
+LDF/STF - load and store floating
+
+<LDF|STF>{cond}<S|D|E> Fd, Rn
+<LDF|STF>{cond}<S|D|E> Fd, [Rn, #<expression>]{!}
+<LDF|STF>{cond}<S|D|E> Fd, [Rn], #<expression>
+
+These instructions are fully implemented.
+
+LFM/SFM - load and store multiple floating
+
+Form 1 syntax:
+<LFM|SFM>{cond}<S|D|E> Fd, <count>, [Rn]
+<LFM|SFM>{cond}<S|D|E> Fd, <count>, [Rn, #<expression>]{!}
+<LFM|SFM>{cond}<S|D|E> Fd, <count>, [Rn], #<expression>
+
+Form 2 syntax:
+<LFM|SFM>{cond}<FD,EA> Fd, <count>, [Rn]{!}
+
+These instructions are fully implemented.  They store/load three words
+for each floating point register into the memory location given in the 
+instruction.  The format in memory is unlikely to be compatible with
+other implementations, in particular the actual hardware.  Specific
+mention of this is made in the ARM manuals.  
+
+Floating Point Coprocessor Register Transfer Instructions (CPRT)
+----------------------------------------------------------------
+
+Conversions, read/write status/control register instructions
+
+FLT{cond}<S,D,E>{P,M,Z} Fn, Rd          Convert integer to floating point
+FIX{cond}{P,M,Z} Rd, Fn                 Convert floating point to integer
+WFS{cond} Rd                            Write floating point status register
+RFS{cond} Rd                            Read floating point status register
+WFC{cond} Rd                            Write floating point control register
+RFC{cond} Rd                            Read floating point control register
+
+FLT/FIX are fully implemented.
+
+RFS/WFS are fully implemented.
+
+RFC/WFC are fully implemented.  RFC/WFC are supervisor only instructions, and
+presently check the CPU mode, and do an invalid instruction trap if not called
+from supervisor mode.
+
+Compare instructions
+
+CMF{cond} Fn, Fm        Compare floating
+CMFE{cond} Fn, Fm       Compare floating with exception
+CNF{cond} Fn, Fm        Compare negated floating
+CNFE{cond} Fn, Fm       Compare negated floating with exception
+
+These are fully implemented.
+
+Floating Point Coprocessor Data Instructions (CPDT)
+---------------------------------------------------
+
+Dyadic operations:
+
+ADF{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - add
+SUF{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - subtract
+RSF{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - reverse subtract
+MUF{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - multiply
+DVF{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - divide
+RDV{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - reverse divide
+
+These are fully implemented.
+
+FML{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - fast multiply
+FDV{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - fast divide
+FRD{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - fast reverse divide
+
+These are fully implemented as well.  They use the same algorithm as the
+non-fast versions.  Hence, in this implementation their performance is
+equivalent to the MUF/DVF/RDV instructions.  This is acceptable according
+to the ARM manual.  The manual notes these are defined only for single
+operands, on the actual FPA11 hardware they do not work for double or
+extended precision operands.  The emulator currently does not check
+the requested permissions conditions, and performs the requested operation.
+
+RMF{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - IEEE remainder
+
+This is fully implemented.
+
+Monadic operations:
+
+MVF{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - move
+MNF{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - move negated
+
+These are fully implemented.
+
+ABS{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - absolute value
+SQT{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - square root
+RND{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - round
+
+These are fully implemented.
+
+URD{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - unnormalized round
+NRM{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - normalize
+
+These are implemented.  URD is implemented using the same code as the RND
+instruction.  Since URD cannot return a unnormalized number, NRM becomes
+a NOP.
+
+Library calls:
+
+POW{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - power
+RPW{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - reverse power
+POL{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - polar angle (arctan2)
+
+LOG{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - logarithm to base 10
+LGN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - logarithm to base e 
+EXP{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - exponent
+SIN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - sine
+COS{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - cosine
+TAN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - tangent
+ASN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - arcsine
+ACS{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - arccosine
+ATN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - arctangent
+
+These are not implemented.  They are not currently issued by the compiler,
+and are handled by routines in libc.  These are not implemented by the FPA11
+hardware, but are handled by the floating point support code.  They should 
+be implemented in future versions.
+
+Signalling:
+
+Signals are implemented.  However current ELF kernels produced by Corel
+Computer have a bug in them that prevents the module from generating a 
+SIGFPE.  This is caused by a failure to alias fp_current to the kernel
+variable current_set[0] correctly.
+
+The kernel provided with this distribution (vmlinux-nwfpe-0.93) contains
+a fix for this problem and also incorporates the current version of the
+emulator directly.  It is possible to run with no floating point module
+loaded with this kernel.  It is provided as a demonstration of the 
+technology and for those who want to do floating point work that depends
+on signals.  It is not strictly necessary to use the module.
+
+A module (either the one provided by Russell King, or the one in this 
+distribution) can be loaded to replace the functionality of the emulator
+built into the kernel.
diff -u --recursive --new-file v2.2.7/linux/Documentation/arm/nwfpe/TODO linux/Documentation/arm/nwfpe/TODO
--- v2.2.7/linux/Documentation/arm/nwfpe/TODO	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/arm/nwfpe/TODO	Sun May  2 09:51:16 1999
@@ -0,0 +1,67 @@
+TODO LIST
+---------
+
+POW{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - power
+RPW{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - reverse power
+POL{cond}<S|D|E>{P,M,Z} Fd, Fn, <Fm,#value> - polar angle (arctan2)
+
+LOG{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - logarithm to base 10
+LGN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - logarithm to base e 
+EXP{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - exponent
+SIN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - sine
+COS{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - cosine
+TAN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - tangent
+ASN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - arcsine
+ACS{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - arccosine
+ATN{cond}<S|D|E>{P,M,Z} Fd, <Fm,#value> - arctangent
+
+These are not implemented.  They are not currently issued by the compiler,
+and are handled by routines in libc.  These are not implemented by the FPA11
+hardware, but are handled by the floating point support code.  They should 
+be implemented in future versions.
+
+There are a couple of ways to approach the implementation of these.  One
+method would be to use accurate table methods for these routines.  I have 
+a couple of papers by S. Gal from IBM's research labs in Haifa, Israel that
+seem to promise extreme accuracy (in the order of 99.8%) and reasonable speed.
+These methods are used in GLIBC for some of the transcendental functions.
+
+Another approach, which I know little about is CORDIC.  This stands for
+Coordinate Rotation Digital Computer, and is a method of computing 
+transcendental functions using mostly shifts and adds and a few
+multiplications and divisions.  The ARM excels at shifts and adds,
+so such a method could be promising, but requires more research to 
+determine if it is feasible.
+
+Rounding Methods
+
+The IEEE standard defines 4 rounding modes.  Round to nearest is the
+default, but rounding to + or - infinity or round to zero are also allowed.
+Many architectures allow the rounding mode to be specified by modifying bits
+in a control register.  Not so with the ARM FPA11 architecture.  To change
+the rounding mode one must specify it with each instruction.
+
+This has made porting some benchmarks difficult.  It is possible to
+introduce such a capability into the emulator.  The FPCR contains 
+bits describing the rounding mode.  The emulator could be altered to 
+examine a flag, which if set forced it to ignore the rounding mode in
+the instruction, and use the mode specified in the bits in the FPCR.
+
+This would require a method of getting/setting the flag, and the bits
+in the FPCR.  This requires a kernel call in ArmLinux, as WFC/RFC are
+supervisor only instructions.  If anyone has any ideas or comments I
+would like to hear them.
+
+[NOTE: pulled out from some docs on ARM floating point, specifically
+ for the Acorn FPE, but not limited to it:
+
+ The floating point control register (FPCR) may only be present in some
+ implementations: it is there to control the hardware in an implementation-
+ specific manner, for example to disable the floating point system.  The user
+ mode of the ARM is not permitted to use this register (since the right is
+ reserved to alter it between implementations) and the WFC and RFC
+ instructions will trap if tried in user mode.
+
+ Hence, the answer is yes, you could do this, but then you will run a high
+ risk of becoming isolated if and when hardware FP emulation comes out
+		-- Russell].
diff -u --recursive --new-file v2.2.7/linux/Documentation/digiboard.txt linux/Documentation/digiboard.txt
--- v2.2.7/linux/Documentation/digiboard.txt	Fri Jan  8 22:35:58 1999
+++ linux/Documentation/digiboard.txt	Thu Apr 29 11:53:41 1999
@@ -111,7 +111,7 @@
 Boot-time configuration when linked into the kernel
 ---------------------------------------------------
 
-Per Board to be configured, pass a digi= commandline parameter to the
+Per board to be configured, pass a digi= command-line parameter to the
 kernel using lilo or loadlin. It consists of a string of comma separated
 identifiers or integers.  The 6 values in order are:
 
@@ -142,7 +142,7 @@
 
    append="digi=1,0,0,16,512,851968"
 
-If you don't give a digi= commandline, the compiled-in defaults of
+If you don't give a digi= command line, the compiled-in defaults of
 board 1: io=0x200, membase=0xd0000, altpin=off and numports=16 are used.
 
 If you have the resources (io&mem) free for use, configure your board to
@@ -153,9 +153,9 @@
 Sources of Information
 ----------------------
 
-Webpage: http://private.fuller.edu/clameter/digi.html
+Web page: http://private.fuller.edu/clameter/digi.html
 
-Mailing List: digiboard@list.fuller.edu
+Mailing list: digiboard@list.fuller.edu
 
 (Write e-mail to that address to subscribe. Common ListServ commands work.
 Archive of messages available)
diff -u --recursive --new-file v2.2.7/linux/Documentation/digiepca.txt linux/Documentation/digiepca.txt
--- v2.2.7/linux/Documentation/digiepca.txt	Fri Jan  8 22:35:58 1999
+++ linux/Documentation/digiepca.txt	Thu Apr 29 11:53:41 1999
@@ -11,7 +11,7 @@
 
 The Linux MAKEDEV command does not support generating the Digiboard
 Devices.  Users executing digiConfig to setup EISA and PC series cards
-will have their device nodes automaticly constructed (cud?? for ~CLOCAL,
+will have their device nodes automatically constructed (cud?? for ~CLOCAL,
 and ttyD?? for CLOCAL).  Users wishing to boot their board from the LILO
 prompt, or those users booting PCI cards may use buildDIGI to construct 
 the necessary nodes. 
@@ -19,7 +19,7 @@
 Notes:
 ------
 This driver may be configured via LILO.  For users who have already configured
-their driver using digiConfig, configuring from lilo will override previous 
+their driver using digiConfig, configuring from LILO will override previous 
 settings.  Multiple boards may be configured by issuing multiple LILO command 
 lines.  For examples see the bottom of this document.
 
diff -u --recursive --new-file v2.2.7/linux/Documentation/fb/matroxfb.txt linux/Documentation/fb/matroxfb.txt
--- v2.2.7/linux/Documentation/fb/matroxfb.txt	Wed Apr 28 11:37:29 1999
+++ linux/Documentation/fb/matroxfb.txt	Thu Apr 29 11:53:41 1999
@@ -95,11 +95,11 @@
 =======
 
 Driver contains SVGALib compatibility code. It is turned on by choosing textual
-mode for console. You can do it at boottime by using videomode
+mode for console. You can do it at boot time by using videomode
 2,3,7,0x108-0x10C or 0x1C0. At runtime, `fbset -depth 0' does this work.
 Unfortunately, after SVGALib application exits, screen contents is corrupted.
-Switching to another console and back fixes it. I hope that it is SVGALib and
-not mine problem, but I'm not sure.
+Switching to another console and back fixes it. I hope that it is SVGALib's
+problem and not mine, but I'm not sure.
 
 
 Configuration
@@ -113,7 +113,7 @@
 mem:X    - size of memory (X can be in megabytes, kilobytes or bytes)
            You can only decrease value determined by driver because of
 	   it always probe for memory. Default is to use whole detected
-	   memory usable for on-screen display (i.e. max. 8MB).
+	   memory usable for on-screen display (i.e. max. 8 MB).
 disabled - do not load driver; you can use also `off', but `disabled'
            is here too.
 enabled  - load driver, if you have `video=matrox:disabled' in LILO
@@ -159,7 +159,7 @@
 inv24    - change timings parameters for 24bpp modes on Millenium and
            Millenium II. Specify this if you see strange color shadows around
 	   characters.
-noinv24  - use standard timmings. It is default.
+noinv24  - use standard timings. It is the default.
 inverse  - invert colors on screen (for LCD displays)
 noinverse - show true colors on screen. It is default.
 dev:X    - bind driver to device X. Driver numbers device from 0 up to N,
@@ -252,25 +252,25 @@
    access to /dev/fb* - everyone with access to this device can destroy
    your monitor, believe me...).
  + 24bpp does not support correctly XF-FBDev on big-endian architectures.
- + interlaced text mode is not supported; it looks like hardware limitiation,
+ + interlaced text mode is not supported; it looks like hardware limitation,
    but I'm not sure.
  + G200 SGRAM/SDRAM is not autodetected.
  + maybe more...
 And following misfeatures:
  + SVGALib does not restore screen on exit.
  + pixclock for text modes is limited by hardware to
-    83MHz on G200
-    66MHz on Millenium I
-    60MHz on Millenium II
-   Because of I have not access to other devices, I do not know specific
+    83 MHz on G200
+    66 MHz on Millennium I
+    60 MHz on Millennium II
+   Because I have no access to other devices, I do not know specific
    frequencies for them. So driver does not check this and allows you to
-   set frequency higher that this. It cause sparks, black holes and other
-   pretty effects on screen. Device was not destroyed during tests :-)
- + my Millenium G200 oscillator has frequency range from 35MHz to 380MHz
-   (and it works with 8bpp on about 320MHz dotclocks (and changed mclk)).
-   But Matrox says on product sheet that VCO limit is 50-250MHz, so I believe
-   them (maybe that chip overheates, but it has very big cooler (G100 has
-   not one), so it should work).
+   set frequency higher that this. It causes sparks, black holes and other
+   pretty effects on screen. Device was not destroyed during tests. :-)
+ + my Millennium G200 oscillator has frequency range from 35 MHz to 380 MHz
+   (and it works with 8bpp on about 320 MHz dotclocks (and changed mclk)).
+   But Matrox says on product sheet that VCO limit is 50-250 MHz, so I believe
+   them (maybe that chip overheats, but it has a very big cooler (G100 has
+   none), so it should work).
  + special mixed video/graphics videomodes of Mystique and Gx00 - 2G8V16 and
    G16V16 are not supported
  + color keying is not supported
@@ -281,14 +281,14 @@
    specify vslen=4000 and so on).
  + maybe more...
 And following features:
- + 4bpp is available only on Millenium I and Millenium II. It is hardware
-   limitiation.
+ + 4bpp is available only on Millennium I and Millennium II. It is hardware
+   limitation.
  + current fbset is not able to set 15bpp videomode: you must specify
    depth==16 and green.length==5. fbset does not allow you to set 
    green.length.
  + text mode uses 6 bit VGA palette instead of 8 bit (one of 262144 colors
    instead of one of 16M colors). It is due to hardware limitation of 
-   MilleniumI/II and SVGALib compatibility.
+   Millennium I/II and SVGALib compatibility.
 
 
 Benchmarks
@@ -296,14 +296,14 @@
 It is time to redraw whole screen 1000 times in 1024x768, 60Hz. It is
 time for draw 6144000 characters on screen through /dev/vcsa
 (for 32bpp it is about 3GB of data (exactly 3000 MB); for 8x16 font in 
-16 seconds, i.e. 187MBps).
+16 seconds, i.e. 187 MBps).
 Times were obtained from one older version of driver, now they are about 3%
-faster, it is kernel-space only time on P-II/350MHz, Millenium I in 33MHz
+faster, it is kernel-space only time on P-II/350 MHz, Millennium I in 33 MHz
 PCI slot, G200 in AGP 2x slot. I did not test vgacon.
 
 NOACCEL
         8x16                 12x22
-        MilleniumI   G200    MilleniumI   G200
+        Millennium I  G200   Millennium I  G200
 8bpp    16.42         9.54   12.33         9.13
 16bpp   21.00        15.70   19.11        15.02
 24bpp   36.66        36.66   35.00        35.00
@@ -311,7 +311,7 @@
 
 ACCEL, nofastfont
         8x16                 12x22                6x11
-	MilleniumI   G200    MilleniumI   G200    MilleniumI   G200
+	Millennium I  G200   Millennium I  G200    Millennium I G200
 8bpp     7.79         7.24   13.55         7.78   30.00        21.01
 16bpp    9.13         7.78   16.16         7.78   30.00        21.01
 24bpp   14.17        10.72   18.69        10.24   34.99        21.01
@@ -319,7 +319,7 @@
 
 ACCEL, fastfont
         8x16                 12x22                6x11
-	MilleniumI   G200    MilleniumI   G200    MilleniumI   G200
+	Millennium I  G200    Millennium I G200   Millennium I  G200
 8bpp     8.41         6.01    6.54         4.37   16.00        10.51
 16bpp    9.54         9.12    8.76         6.17   17.52        14.01
 24bpp   15.00        12.36   11.67        10.00   22.01        18.32
@@ -327,10 +327,10 @@
 
 TEXT
         8x16
-	MilleniumI   G200
+	Millennium I  G200
 TEXT     3.29         1.50
 
 	
-* Yes, it is slower than Millenium I.
+* Yes, it is slower than Millennium I.
 --
 Petr Vandrovec <vandrove@vc.cvut.cz>
diff -u --recursive --new-file v2.2.7/linux/Documentation/fb/vesafb.txt linux/Documentation/fb/vesafb.txt
--- v2.2.7/linux/Documentation/fb/vesafb.txt	Fri Apr 16 14:47:30 1999
+++ linux/Documentation/fb/vesafb.txt	Thu Apr 29 11:53:41 1999
@@ -10,7 +10,7 @@
 
 This means we decide at boot time whenever we want to run in text or
 graphics mode.  Switching mode later on (in protected mode) is
-impossible; BIOS calls work in real mode only.  VESA BIOS Extentions
+impossible; BIOS calls work in real mode only.  VESA BIOS Extensions
 Version 2.0 are required, because we need a linear frame buffer.
 
 Advantages:
@@ -66,10 +66,10 @@
 mode at the "vga=ask" prompt. For example if you like to use 
 1024x768x256 colors you have to say "305" at this prompt.
 
-If this does not work, this might be becauce your BIOS does not support
-linear framebuffers or becauce it does not support this mode at all.
+If this does not work, this might be because your BIOS does not support
+linear framebuffers or because it does not support this mode at all.
 Even if your board does, it might be the BIOS which does not.  VESA BIOS
-Extentions v2.0 are required, 1.2 is NOT sufficient.  You will get a
+Extensions v2.0 are required, 1.2 is NOT sufficient.  You will get a
 "bad mode number" message if something goes wrong.
 
 1. Note: LILO cannot handle hex, for booting directly with 
@@ -99,8 +99,8 @@
    available) and boot linux with loadlin.
  * use a native driver (matroxfb/atyfb) instead if vesafb.  If none
    is available, write a new one!
- * VBE 3.0 might work too.  I havn't neither a gfx board with VBE 3.0
-   support nor the specs, so I havn't checked this yet.  But maybe...
+ * VBE 3.0 might work too.  I have neither a gfx board with VBE 3.0
+   support nor the specs, so I have not checked this yet.
 
 
 Configuration
@@ -108,7 +108,7 @@
 
 The VESA BIOS provides protected mode interface for changing
 some parameters.  vesafb can use it for palette changes and
-to pan the display.  It is turned off by default becauce it
+to pan the display.  It is turned off by default because it
 seems not to work with some BIOS versions, but there are options
 to turn it on.
 
@@ -124,7 +124,7 @@
 	interface.  The visible screen is just a window of the
 	video memory, console scrolling is done by changing the
 	start of the window.
-	pro:	* scrolling (fullscreen) is fast, becauce there is
+	pro:	* scrolling (fullscreen) is fast, because there is
 		  no need to copy around data.
 		* You'll get scrollback (the Shift-PgUp thing),
 		  the video memory can be used as scrollback buffer
diff -u --recursive --new-file v2.2.7/linux/Documentation/filesystems/00-INDEX linux/Documentation/filesystems/00-INDEX
--- v2.2.7/linux/Documentation/filesystems/00-INDEX	Fri Apr 16 14:47:30 1999
+++ linux/Documentation/filesystems/00-INDEX	Sun May  2 09:51:16 1999
@@ -1,5 +1,7 @@
 00-INDEX
 	- this file (info on some of the filesystems supported by linux).
+adfs.txt
+	- info and mount options for the Acorn Advanced Disc Filing System.
 affs.txt
 	- info and mount options for the Amiga Fast File System.
 coda.txt
diff -u --recursive --new-file v2.2.7/linux/Documentation/filesystems/adfs.txt linux/Documentation/filesystems/adfs.txt
--- v2.2.7/linux/Documentation/filesystems/adfs.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/filesystems/adfs.txt	Sun May  2 09:51:16 1999
@@ -0,0 +1,57 @@
+Mount options for ADFS
+----------------------
+
+  uid=nnn	All files in the partition will be owned by
+		user id nnn.  Default 0 (root).
+  gid=nnn	All files in the partition willbe in group
+		nnn.  Default 0 (root).
+  ownmask=nnn	The permission mask for ADFS 'owner' permissions
+		will be nnn.  Default 0700.
+  othmask=nnn	The permission mask for ADFS 'other' permissions
+		will be nnn.  Default 0077.
+
+Mapping of ADFS permissions to Linux permissions
+------------------------------------------------
+
+  ADFS permissions consist of the following:
+
+	Owner read
+	Owner write
+	Other read
+	Other write
+
+  (In older versions, an 'execute' permission did exist, but this
+   does not hold the same meaning as the Linux 'execute' permission
+   and is now obsolete).
+
+  The mapping is performed as follows:
+
+	Owner read				-> -r--r--r--
+	Owner write				-> --w--w---w
+	Owner read and filetype UnixExec	-> ---x--x--x
+    These are then masked by ownmask, eg 700	-> -rwx------
+	Possible owner mode permissions		-> -rwx------
+
+	Other read				-> -r--r--r--
+	Other write				-> --w--w--w-
+	Other read and filetype UnixExec	-> ---x--x--x
+    These are then masked by othmask, eg 077	-> ----rwxrwx
+	Possible other mode permissions		-> ----rwxrwx
+
+  Hence, with the default masks, if a file is owner read/write, and
+  not a UnixExec filetype, then the permissions will be:
+
+			-rw-------
+
+  However, if the masks were ownmask=0770,othmask=0007, then this would
+  be modified to:
+			-rw-rw----
+
+  There is no restriction on what you can do with these masks.  You may
+  wish that either read bits give read access to the file for all, but
+  keep the default write protection (ownmask=0755,othmask=0577):
+
+			-rw-r--r--
+
+  You can therefore tailor the permission translation to whatever you
+  desire the permissions should be under Linux.
diff -u --recursive --new-file v2.2.7/linux/Documentation/filesystems/coda.txt linux/Documentation/filesystems/coda.txt
--- v2.2.7/linux/Documentation/filesystems/coda.txt	Wed Jun 24 22:54:02 1998
+++ linux/Documentation/filesystems/coda.txt	Thu Apr 29 11:53:41 1999
@@ -776,7 +776,7 @@
   indicate confusion between the system call creat and the VFS operation
   create. The VFS operation create is only called to create new objects.
   This create call differs from the Unix one in that it is not invoked
-  to return a file descriptor. The trunctate and exclusive options,
+  to return a file descriptor. The truncate and exclusive options,
   together with the mode, could simply be part of the mode as it is
   under Unix.  There should be no flags argument; this is used in open
   (2) to return a file descriptor for READ or WRITE mode.
diff -u --recursive --new-file v2.2.7/linux/Documentation/filesystems/smbfs.txt linux/Documentation/filesystems/smbfs.txt
--- v2.2.7/linux/Documentation/filesystems/smbfs.txt	Fri Jan 23 18:10:31 1998
+++ linux/Documentation/filesystems/smbfs.txt	Thu Apr 29 11:53:41 1999
@@ -1,7 +1,7 @@
 Smbfs is a filesystem that implements the SMB protocol, which is the
 protocol used by Windows for Workgroups, Windows 95 and Windows NT.
 Smbfs was inspired by Samba, the program written by Andrew Tridgell
-that turns any unix host into a file server for DOS or Windows clients.
+that turns any Unix host into a file server for DOS or Windows clients.
 See ftp://nimbus.anu.edu.au/pub/tridge/samba/ for this interesting
 program suite and much more information on SMB, NetBIOS over TCP/IP,
 and explanations for concepts like netbios name or share.
diff -u --recursive --new-file v2.2.7/linux/Documentation/filesystems/vfat.txt linux/Documentation/filesystems/vfat.txt
--- v2.2.7/linux/Documentation/filesystems/vfat.txt	Wed Jun 24 22:54:02 1998
+++ linux/Documentation/filesystems/vfat.txt	Thu Apr 29 11:53:41 1999
@@ -177,7 +177,7 @@
 
 Because the extended FAT system is backward compatible, it is
 possible for old software to modify directory entries.  Measures must
-be taken to insure the validity of slots.  An extended FAT system can
+be taken to ensure the validity of slots.  An extended FAT system can
 verify that a slot does in fact belong to an 8.3 directory entry by
 the following:
 
diff -u --recursive --new-file v2.2.7/linux/Documentation/mtrr.txt linux/Documentation/mtrr.txt
--- v2.2.7/linux/Documentation/mtrr.txt	Thu May  7 22:51:46 1998
+++ linux/Documentation/mtrr.txt	Mon May 10 10:32:45 1999
@@ -62,6 +62,23 @@
 ioctl() interface, so users won't have to do anything. If you use a
 commercial X server, lobby your vendor to add support for MTRRs.
 ===============================================================================
+Creating overlapping MTRRs:
+
+%echo "base=0xfb000000 size=0x1000000 type=write-combining" >/proc/mtrr
+%echo "base=0xfb000000 size=0x1000 type=uncachable" >/proc/mtrr
+
+And the results: cat /proc/mtrr
+reg00: base=0x00000000 (   0MB), size=  64MB: write-back, count=1
+reg01: base=0xfb000000 (4016MB), size=  16MB: write-combining, count=1
+reg02: base=0xfb000000 (4016MB), size=   4kB: uncachable, count=1
+
+Some cards (especially Voodoo Graphics boards) need this 4 kB area 
+excluded from the beginning of the region because it is used for
+registers.
+
+NOTE: You can only create type=uncachable region, if the first
+region that you created is type=write-combining.
+===============================================================================
 Removing MTRRs from the shell:
 % echo "disable=2" >! /proc/mtrr
 ===============================================================================
diff -u --recursive --new-file v2.2.7/linux/Documentation/networking/filter.txt linux/Documentation/networking/filter.txt
--- v2.2.7/linux/Documentation/networking/filter.txt	Sun Jun  7 11:16:26 1998
+++ linux/Documentation/networking/filter.txt	Thu Apr 29 11:53:41 1999
@@ -12,7 +12,7 @@
 attach a filter onto any socket and allow or disallow certain
 types of data to come through the socket. LSF follows exactly
 the same filter code structure as the BSD Berkeley Packet Filter
-(BPF), so refering to the BSD bpf.4 manpage is very helpful in
+(BPF), so referring to the BSD bpf.4 manpage is very helpful in
 creating filters.
 
 LSF is much simpler than BPF. One does not have to worry about
diff -u --recursive --new-file v2.2.7/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt
--- v2.2.7/linux/Documentation/networking/ip-sysctl.txt	Thu Jan  7 15:11:35 1999
+++ linux/Documentation/networking/ip-sysctl.txt	Mon May 10 09:55:25 1999
@@ -96,7 +96,7 @@
 	Enable timestamps as defined in RFC1323.
 
 tcp_sack - BOOLEAN
-	Enable select acknowledgements.
+	Enable select acknowledgments.
 
 tcp_retrans_collapse - BOOLEAN
 	Bug-to-bug compatibility with some broken printers.
@@ -119,7 +119,7 @@
 icmp_paramprob_rate - INTEGER
 icmp_timeexceed_rate - INTEGER
 icmp_echoreply_rate - INTEGER (not enabled per default)
-	Limit the maximal rates for sending ICMP packets to specifc targets.
+	Limit the maximal rates for sending ICMP packets to specific targets.
 	0 to disable any limiting, otherwise the maximal rate in jiffies(1)
 	See the source for more information.
 
@@ -173,7 +173,7 @@
 bootp_relay - BOOLEAN
 	Accept packets with source address 0.b.c.d destined
 	not to this host as local ones. It is supposed, that
-	BOOTP relay deamon will catch and forward such packets.
+	BOOTP relay daemon will catch and forward such packets.
 
 	default FALSE
 	Not Implemented Yet.
@@ -211,4 +211,4 @@
 Updated by:
 Andi Kleen
 ak@muc.de
-$Id: ip-sysctl.txt,v 1.8 1999/01/02 16:37:06 davem Exp $
+$Id: ip-sysctl.txt,v 1.9 1999/05/08 02:58:44 davem Exp $
diff -u --recursive --new-file v2.2.7/linux/Documentation/networking/ipddp.txt linux/Documentation/networking/ipddp.txt
--- v2.2.7/linux/Documentation/networking/ipddp.txt	Sat May  2 14:19:51 1998
+++ linux/Documentation/networking/ipddp.txt	Thu Apr 29 11:53:41 1999
@@ -14,7 +14,7 @@
 IP over an AppleTalk network or you can provide IP gatewaying functions
 for your AppleTalk users.
 
-You can currently Encapsulate or Decapsulate AppleTalk-IP on LocalTalk,
+You can currently encapsulate or decapsulate AppleTalk-IP on LocalTalk,
 EtherTalk and PPPTalk. The only limit on the protocol is that of what
 kernel AppleTalk layer and drivers are available.
 
@@ -23,22 +23,22 @@
 Compiling AppleTalk-IP Decapsulation/Encapsulation
 =================================================
 
-AppleTalk-IP Decapsulation needs to be compiled into your kernel. You
-will need to turn on Appletalk-IP driver support. Then you will need to
-select ONE of the two options; IP to AppleTalk-IP Encapsulation support or
-AppleTalk-IP to IP Decapsulation support. If you compile the driver
+AppleTalk-IP decapsulation needs to be compiled into your kernel. You
+will need to turn on AppleTalk-IP driver support. Then you will need to
+select ONE of the two options; IP to AppleTalk-IP encapsulation support or
+AppleTalk-IP to IP decapsulation support. If you compile the driver
 statically you will only be able to use the driver for the function you have
 enabled in the kernel. If you compile the driver as a module you can
 select what mode you want it to run in via a module loading param.
-ipddp_mode=1 for AppleTalk-IP Encapsulation and ipddp_mode=2 for
-AppleTalk-IP to IP Decapsulation.
+ipddp_mode=1 for AppleTalk-IP encapsulation and ipddp_mode=2 for
+AppleTalk-IP to IP decapsulation.
 
 Basic instructions for user space tools
 =======================================
 
-To enable AppleTalk-IP Decapsulation/Encapsulation you will need the 
-proper tools. You can get the tools for Decapsulation from
-http://spacs1.spacs.k12.wi.us/~jschlst/MacGate and for Encapsulation
+To enable AppleTalk-IP decapsulation/encapsulation you will need the 
+proper tools. You can get the tools for decapsulation from
+http://spacs1.spacs.k12.wi.us/~jschlst/MacGate and for encapsulation
 from http://www.maths.unm.edu/~bradford/ltpc.html
 
 I will briefly describe the operation of the tools, but you will
@@ -61,8 +61,8 @@
 
 Common Uses of ipddp.c
 ----------------------
-Of course AppleTalk-IP Decapsulation and Encapsulation, but specificly
-Decapsulation is being used most for connecting LocalTalk networks to
+Of course AppleTalk-IP decapsulation and encapsulation, but specifically
+decapsulation is being used most for connecting LocalTalk networks to
 IP networks. Although it has been used on EtherTalk networks to allow
 Macs that are only able to tunnel IP over EtherTalk.
 
@@ -73,6 +73,6 @@
 Further Assistance
 -------------------
 You can contact me (Jay Schulist <Jay.Schulist@spacs.k12.wi.us>) with any
-questions reguarding Decapsulation or Encapsulation. Bradford W. Johnson
+questions regarding decapsulation or encapsulation. Bradford W. Johnson
 <johns393@maroon.tc.umn.edu> originally wrote the ipddp.c driver for IP
 encapsulation in AppleTalk.
diff -u --recursive --new-file v2.2.7/linux/Documentation/powerpc/smp.txt linux/Documentation/powerpc/smp.txt
--- v2.2.7/linux/Documentation/powerpc/smp.txt	Fri Oct 23 22:01:18 1998
+++ linux/Documentation/powerpc/smp.txt	Thu Apr 29 12:39:07 1999
@@ -5,11 +5,10 @@
 (Cort Dougan, cort@cs.nmt.edu) please email me if you have questions,
 comments or corrections.
 
-Last Change: 10.8.98
+Last Change: 3.31.99
 
-SMP support for Linux/PPC is still in its early stages and likely to
-be buggy for a while.  If you want to help by writing code or testing
-different hardware please email me!
+If you want to help by writing code or testing different hardware please
+email me!
 
 1. State of Supported Hardware
 
@@ -29,3 +28,7 @@
   BeBox
     BeBox support hasn't been added to the 2.1.X kernels from 2.0.X
     but work is being done and SMP support for BeBox is in the works.
+
+  CHRP
+    CHRP SMP works and is fairly solid.  It's been tested on the IBM F50
+    with 4 processors for quite some time now.
diff -u --recursive --new-file v2.2.7/linux/Documentation/sound/AD1816 linux/Documentation/sound/AD1816
--- v2.2.7/linux/Documentation/sound/AD1816	Tue Dec 22 14:16:53 1998
+++ linux/Documentation/sound/AD1816	Thu Apr 29 11:53:41 1999
@@ -105,7 +105,7 @@
 
 As the driver is still experimental and under development, you should
 watch out for updates.  Updates of the driver are available on the
-internet from one of my home pages:
+Internet from one of my home pages:
   http://www.student.informatik.tu-darmstadt.de/~tek/projects/linux.html
 or:
   http://www.tu-darmstadt.de/~tek01/projects/linux.html
diff -u --recursive --new-file v2.2.7/linux/Documentation/sound/AWE32 linux/Documentation/sound/AWE32
--- v2.2.7/linux/Documentation/sound/AWE32	Thu Jan  7 15:11:35 1999
+++ linux/Documentation/sound/AWE32	Thu Apr 29 11:53:41 1999
@@ -53,7 +53,7 @@
 (IO 2 (BASE 0x0E20)) (ACT Y) ))"
 
 Resources 0x0620, 0x0A20 and 0x0E20 should work. Other on-board devices: 
-Gameport and StereoEnhance are not required to be inited.
+Gameport and StereoEnhance are not required to be initialized.
 
 Now you can execute "isapnp /etc/isapnp.conf". No errors should be reported.
 If you correctly installed isapnptools, then isapnp will run every boot time.
diff -u --recursive --new-file v2.2.7/linux/Documentation/sound/AudioExcelDSP16 linux/Documentation/sound/AudioExcelDSP16
--- v2.2.7/linux/Documentation/sound/AudioExcelDSP16	Fri Jan  8 22:35:59 1999
+++ linux/Documentation/sound/AudioExcelDSP16	Thu Apr 29 11:53:41 1999
@@ -80,7 +80,7 @@
 2) Install your new kernel as the default boot kernel.
 3) Boot MS-DOS and configure the audio card with the boot time device
    driver, for MSS irq10 dma3 in our example.
-4) <ctrl>-<alt>-<del> and boot Linux. This will mantain the DOS configuration
+4) <ctrl>-<alt>-<del> and boot Linux. This will maintain the DOS configuration
    and will boot the new kernel with sound driver. The sound driver will find
    the audio card and will recognize and attach it.
 
diff -u --recursive --new-file v2.2.7/linux/Documentation/sound/ChangeLog.awe linux/Documentation/sound/ChangeLog.awe
--- v2.2.7/linux/Documentation/sound/ChangeLog.awe	Tue Dec 22 14:16:53 1998
+++ linux/Documentation/sound/ChangeLog.awe	Thu Apr 29 11:53:41 1999
@@ -81,7 +81,7 @@
 
 ver.0.3.3b
 	- Fix version number in awe_version.h
-	- Fix a small bug in noteoff/relese all
+	- Fix a small bug in noteoff/release all
 
 ver.0.3.3a
 	- Fix all notes/sounds off
diff -u --recursive --new-file v2.2.7/linux/Documentation/sound/INSTALL.awe linux/Documentation/sound/INSTALL.awe
--- v2.2.7/linux/Documentation/sound/INSTALL.awe	Tue Dec 22 14:16:53 1998
+++ linux/Documentation/sound/INSTALL.awe	Thu Apr 29 11:53:41 1999
@@ -17,7 +17,7 @@
 	http://www-jcr.lmh.ox.ac.uk/~pnp/
 
 ----------------------------------------------------------------
-* Installation on RedHat 5.0 Sound Driver
+* Installation on Red Hat 5.0 Sound Driver
 
 Please use install-rh.sh under RedHat5.0 directory.
 DO NOT USE install.sh below.
@@ -31,7 +31,7 @@
 	% su
 
   2. If you have never configured the kernel tree yet, run make config
-    once (to make depencies and symlinks).
+    once (to make dependencies and symlinks).
 
 	# cd /usr/src/linux
 	# make xconfig
@@ -40,7 +40,7 @@
 
 	# sh ./install.sh
 
-  4. Configure your kenrel
+  4. Configure your kernel
 
 	(for Linux 2.[01].x user)
 	# cd /usr/src/linux
@@ -77,7 +77,7 @@
     do it by isapnp tools.  Otherwise, skip to 8.
 
 	This section described only a brief explanation.  For more
-	detaills, please see AWE64-Mini-HOWTO or isapnp tools FAQ.
+	details, please see the AWE64-Mini-HOWTO or isapnp tools FAQ.
 
 	7a. If you have no isapnp.conf file, generate it by pnpdump.
 	    Otherwise, skip to 7d.
diff -u --recursive --new-file v2.2.7/linux/Documentation/sound/Introduction linux/Documentation/sound/Introduction
--- v2.2.7/linux/Documentation/sound/Introduction	Tue Dec 22 14:16:53 1998
+++ linux/Documentation/sound/Introduction	Thu Apr 29 11:53:41 1999
@@ -214,7 +214,7 @@
 
 3)  In /etc/conf.modules when using modprobe.
 
-4)  Via RedHat's /usr/sbin/sndconfig program (text based).
+4)  Via Red Hat's /usr/sbin/sndconfig program (text based).
 
 5)  Via the OSS soundconf program (with the commercial version
     of the OSS driver.
@@ -240,7 +240,7 @@
 
 6)  The comments and code in linux/drivers/sound.
 
-7)  The sndconfig and rhsound documentation from RedHat.
+7)  The sndconfig and rhsound documentation from Red Hat.
 
 8)  The Linux-sound mailing list:  sound-list@redhat.com
 
diff -u --recursive --new-file v2.2.7/linux/Documentation/sound/MAD16 linux/Documentation/sound/MAD16
--- v2.2.7/linux/Documentation/sound/MAD16	Wed Apr  8 19:36:24 1998
+++ linux/Documentation/sound/MAD16	Thu Apr 29 11:53:41 1999
@@ -23,3 +23,12 @@
 alias char-major-14 mad16
 options sb mad16=1
 options mad16 io=0x530 irq=7 dma=0 dma16=1  && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0
+
+
+To get the built in mixer to work this needs to be:
+
+options adlib_card io=0x388     # FM synthesizer
+options sb mad16=1
+options mad16 io=0x530 irq=7 dma=0 dma16=1 mpu_io=816 mpu_irq=5 && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0
+
+The addition of the "mpu_io=816 mpu_irq=5" to the mad16 options line is
diff -u --recursive --new-file v2.2.7/linux/Documentation/sound/OPL3-SA linux/Documentation/sound/OPL3-SA
--- v2.2.7/linux/Documentation/sound/OPL3-SA	Tue Feb 23 15:21:32 1999
+++ linux/Documentation/sound/OPL3-SA	Thu Apr 29 11:53:41 1999
@@ -15,7 +15,7 @@
 You'll need to know all of the relevant info (irq, dma, and io port) for the
 chip's WSS mode, since that is the mode the kernel sound driver uses, and of
 course you'll also need to know about where the MPU401 and OPL3 ports and
-irq's are if you want to use those.
+IRQs are if you want to use those.
 
 Here's the skinny on how to load it as a module:
 
@@ -24,14 +24,14 @@
 Module options in detail:
 
 	io:	This is the WSS's port base.
-	irq:	This is the WSS's irq.
-	dma:	This is the WSS's dma line. In my BIOS setup screen this was
+	irq:	This is the WSS's IRQ.
+	dma:	This is the WSS's DMA line. In my BIOS setup screen this was
 		listed as "WSS Play DMA"
-	dma2:	This is the WSS's secondary dma line. My BIOS calls it the
+	dma2:	This is the WSS's secondary DMA line. My BIOS calls it the
 		"WSS capture DMA"
 	
 	mpu_io:	This is the MPU401's port base.
-	mpu_irq: This is the MPU401's irq.
+	mpu_irq: This is the MPU401's IRQ.
 
 If you'd like to use the OPL3 FM Synthesizer, make sure you enable
 CONFIG_YM3812 (in 'make config'). That'll build the opl3.o module.
@@ -43,7 +43,7 @@
 
 Say 'y' or 'm' to "SoftOSS software wave table engine" in make config.
 
-If you said yes, the software synth is availible once you boot your new
+If you said yes, the software synth is available once you boot your new
 kernel.
 
 If you chose to build it as a module, just insmod the resulting softoss2.o
diff -u --recursive --new-file v2.2.7/linux/Documentation/sound/README.OSS linux/Documentation/sound/README.OSS
--- v2.2.7/linux/Documentation/sound/README.OSS	Tue Jan 19 11:32:50 1999
+++ linux/Documentation/sound/README.OSS	Thu Apr 29 11:53:41 1999
@@ -58,7 +58,7 @@
 	Mika Liljeberg	uLaw encoding and decoding routines
 	Jeff Tranter	Linux SOUND HOWTO document
 	Greg Lee	Volume computation algorithm for the GUS and
-			lot's of valuable suggestions.
+			lots of valuable suggestions.
 	Andy Warner	ISC port
 	Jim Lowe,
 	Amancio Hasty Jr	FreeBSD/NetBSD port
@@ -96,7 +96,7 @@
 or before even starting to do any work. Tell me what you suggest to be
 changed or what you have planned to do. Also ensure you are using the
 very latest (development) version of OSS/Free since the change may already be
-implemented there. In general it's major waste of time to try to improve
+implemented there. In general it's a major waste of time to try to improve a
 several months old version. Information about the latest version can be found
 from http://www.opensound.com/ossfree. In general there is no point in
 sending me patches relative to production kernels.
@@ -1314,8 +1314,8 @@
 This ESS proprietary feature is supported only by OSS/Linux.
 
 There are ES1688 based cards which use different interrupt pin assignment than
-recommended by ESS (5, 7, 9/2 and 10). In this case all IRQ's don't work.
-At least a card called (Pearl?) Hypersound 16 supports IRQ15 but it doesn't
+recommended by ESS (5, 7, 9/2 and 10). In this case all IRQs don't work.
+At least a card called (Pearl?) Hypersound 16 supports IRQ 15 but it doesn't
 work.
 
 ES1868 is a PnP chip which is (supposed to be) compatible with ESS1688
diff -u --recursive --new-file v2.2.7/linux/Documentation/sound/README.awe linux/Documentation/sound/README.awe
--- v2.2.7/linux/Documentation/sound/README.awe	Tue Dec 22 14:16:53 1998
+++ linux/Documentation/sound/README.awe	Thu Apr 29 11:53:41 1999
@@ -9,8 +9,8 @@
 
 This is a sound driver extension for SoundBlaster AWE32 and other
 compatible cards (AWE32-PnP, SB32, SB32-PnP, AWE64 & etc) to enable
-the wave synth operations.  The driver is provided for both Linux
-1.2.x and 2.[01].x kernels, and also FreeBSD, on Intel x86 and DEC
+the wave synth operations.  The driver is provided for Linux 1.2.x
+and 2.[012].x kernels, as well as FreeBSD, on Intel x86 and DEC
 Alpha systems.
 
 This driver was written by Takashi Iwai <iwai@ww.uni-erlangen.de>,
@@ -76,7 +76,7 @@
 	% sfxload synthgm
 	% drvmidi -L 2mbgmgs foo.mid
 
-This makes a big differece (believe me)!  For more details, please
+This makes a big difference (believe me)!  For more details, please
 refer to the FAQ list which is available on the URL above.
 
 The current chorus, reverb and equalizer status can be changed by
@@ -97,14 +97,14 @@
 shell script.
 
 - AWE_MODULE_SUPPORT
-    indicates your linux kernel supports module for each soundcard
-    (in recent 2.1 kernels and unofficial patched 2.0 kernels as
-     distributed in the RH5.0 package).
+    indicates your Linux kernel supports module for each sound card
+    (in recent 2.1 or 2.2 kernels and unofficial patched 2.0 kernels
+    as distributed in the RH5.0 package).
     This flag is automatically set when you're using 2.1.x kernels.
     You can pass the base address and memory size via the following
     module options,
 	io = base I/O port address (eg. 0x620)
-	memsize = DRAM size in Kbyes (eg. 512)
+	memsize = DRAM size in kilobytes (eg. 512)
     As default, AWE driver probes these values automatically.
 
 
@@ -117,15 +117,15 @@
     0 means to autodetect the address.
 
 - AWE_DEFAULT_MEM_SIZE		(default: not defined)
-    specifies the memory size of your AWE32 card in kilo bytes.
+    specifies the memory size of your AWE32 card in kilobytes.
     -1 means to autodetect its size.
     
 
 [Sample Table Size]
 From ver.0.4.0, sample tables are allocated dynamically (except
 Linux-1.2.x system), so you need NOT to touch these parameters.
-Linux-1.2.x users may need to increase these values to apropriate size 
-if larger DRAM is equipped with the soundcard.
+Linux-1.2.x users may need to increase these values to appropriate size 
+if the sound card is equipped with more DRAM.
 
 - AWE_MAX_SF_LISTS, AWE_MAX_SAMPLES, AWE_MAX_INFOS
 
@@ -139,7 +139,7 @@
     passthrough channels. 
 
 - AWE_DEBUG_ON			(default: defined)
-    turns on debuggin messages if defined.
+    turns on debugging messages if defined.
 
 - AWE_HAS_GUS_COMPATIBILITY	(default: defined)
     Enables GUS compatibility mode if defined, reading GUS patches and 
@@ -170,7 +170,7 @@
 - AWE_ALLOW_SAMPLE_SHARING	(default: defined)
    Allow sample sharing for differently loaded patches.
    This function is available only together with awesfx-0.4.3p3.
-   Note that this is still an experimantal option.
+   Note that this is still an experimental option.
 
 - DEF_FM_CHORUS_DEPTH		(default: 0x10)
     The default strength to be sent to the chorus effect engine.
@@ -183,8 +183,8 @@
 
 * ACKNOWLEDGMENTS
 
-Thanks to Witold Jachimczyk (witek@xfactor.wpi.edu) for many advices
-to programming of AWE32.  Many codes are brought from his AWE32-native 
+Thanks to Witold Jachimczyk (witek@xfactor.wpi.edu) for much advice
+on programming of AWE32.  Much code is brought from his AWE32-native 
 MOD player, ALMP.
 The port of awedrv to FreeBSD is done by Randall Hopper
 (rhh@ct.picker.com).
diff -u --recursive --new-file v2.2.7/linux/Documentation/sound/Wavefront linux/Documentation/sound/Wavefront
--- v2.2.7/linux/Documentation/sound/Wavefront	Thu Sep 17 17:53:34 1998
+++ linux/Documentation/sound/Wavefront	Thu Apr 29 11:53:41 1999
@@ -149,7 +149,7 @@
    .
    .
    .
-   make modules_isntall
+   make modules_install
 
 Here's my autoconf.h SOUND section:
 
diff -u --recursive --new-file v2.2.7/linux/Documentation/sysctl/vm.txt linux/Documentation/sysctl/vm.txt
--- v2.2.7/linux/Documentation/sysctl/vm.txt	Fri Apr 16 14:47:30 1999
+++ linux/Documentation/sysctl/vm.txt	Thu Apr 29 11:53:41 1999
@@ -178,7 +178,7 @@
 
 The Linux VM subsystem avoids excessive disk seeks by reading
 multiple pages on a page fault. The number of pages it reads
-is dependant on the amount of memory in your machine.
+is dependent on the amount of memory in your machine.
 
 The number of pages the kernel reads in at once is equal to
 2 ^ page-cluster. Values above 2 ^ 5 don't make much sense
diff -u --recursive --new-file v2.2.7/linux/MAINTAINERS linux/MAINTAINERS
--- v2.2.7/linux/MAINTAINERS	Wed Apr 28 11:37:29 1999
+++ linux/MAINTAINERS	Sat May  8 12:49:46 1999
@@ -779,14 +779,14 @@
 USB HUB AND UHCI DRIVERS
 P:	Johannes Erdfelt
 M:	jerdfelt@sventech.com
-L:	linux-usb@peloncho.fis.ucm.es
+L:	linux-usb@suse.com
 S:	Maintained
 
 USB OHCI DRIVER
 P:	Gregory P. Smith
 M:	greg@electricrain.com
 M:	greg@suitenine.com
-L:	linux-usb@peloncho.fis.ucm.es
+L:	linux-usb@suse.com
 S:	Maintained (not yet usable)
 W:	http://suitenine.com/usb/
 
diff -u --recursive --new-file v2.2.7/linux/Makefile linux/Makefile
--- v2.2.7/linux/Makefile	Wed Apr 28 11:37:29 1999
+++ linux/Makefile	Wed Apr 28 11:38:52 1999
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 2
-SUBLEVEL = 7
+SUBLEVEL = 8
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
diff -u --recursive --new-file v2.2.7/linux/REPORTING-BUGS linux/REPORTING-BUGS
--- v2.2.7/linux/REPORTING-BUGS	Tue Jan 19 11:32:50 1999
+++ linux/REPORTING-BUGS	Thu Apr 29 11:53:41 1999
@@ -1,6 +1,6 @@
 [Some of this is taken from Frohwalt Egerer's original linux-kernel FAQ]
 
-     What follows is a suggested proceedure for reporting Linux bugs. You
+     What follows is a suggested procedure for reporting Linux bugs. You
 aren't obliged to use the bug reporting format, it is provided as a guide
 to the kind of information that can be useful to developers - no more.
 
@@ -23,11 +23,11 @@
 This is a suggested format for a bug report sent to the Linux kernel mailing 
 list. Having a standardized bug report form makes it easier  for you not to 
 overlook things, and easier for the developers to find the pieces of 
-information they're really interested in.
+information they're really interested in. Don't feel you have to follow it.
 
    First run the ver_linux script included as scripts/ver_linux or
 at <URL:ftp://ftp.sai.msu.su/pub/Linux/ver_linux> It checks out
-the version of some important subsystems. Run it with the commnd
+the version of some important subsystems.  Run it with the command
 "sh scripts/ver_linux"
 
 Use that information to fill in all fields of the bug report form, and
diff -u --recursive --new-file v2.2.7/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v2.2.7/linux/arch/alpha/config.in	Tue Feb 23 15:21:32 1999
+++ linux/arch/alpha/config.in	Mon May 10 09:55:21 1999
@@ -54,12 +54,10 @@
 unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA
 unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS CONFIG_ALPHA_POLARIS
 unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA
-unset CONFIG_ALPHA_NEED_ROUNDING_EMULATION
 
 if [ "$CONFIG_ALPHA_GENERIC" = "y" ]
 then
 	define_bool CONFIG_PCI y
-	define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y
 fi
 if [ "$CONFIG_ALPHA_BOOK1" = "y" ]
 then
@@ -108,7 +106,7 @@
 	then
 		define_bool CONFIG_ALPHA_EV5 y
 	else
-	define_bool CONFIG_ALPHA_EV4 y
+		define_bool CONFIG_ALPHA_EV4 y
 	fi
 	define_bool CONFIG_ALPHA_T2 y
 fi
@@ -140,11 +138,6 @@
 if [ "$CONFIG_ALPHA_JENSEN" = "y" ]
 then
 	define_bool CONFIG_ALPHA_EV4 y
-fi
-if [ "$CONFIG_ALPHA_EV4" = "y" ]
-then
-	# EV45 and older do not support all rounding modes in hw:
-	define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y
 fi
 
 if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \
diff -u --recursive --new-file v2.2.7/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v2.2.7/linux/arch/alpha/kernel/entry.S	Tue Feb 23 15:21:32 1999
+++ linux/arch/alpha/kernel/entry.S	Mon May 10 09:55:21 1999
@@ -6,8 +6,6 @@
 
 #include <asm/system.h>
 
-#define halt	.long PAL_halt
-#define rti	.long PAL_rti
 #define SIGCHLD 20
 
 #define NR_SYSCALLS 371
@@ -98,7 +96,7 @@
 	call_pal PAL_swpipl;		\
 	stq	$21,HAE_CACHE($19);	\
 	stq	$21,0($20);		\
-	bis	$0,$0,$16;		\
+	mov	$0,$16;			\
 	call_pal PAL_swpipl;		\
 	ldq	$0,0($30);		\
 	ldq	$1,8($30);		\
@@ -127,8 +125,8 @@
 entInt:
 	SAVE_ALL
 	lda	$8,0x3fff
-	bic	$30,$8,$8
 	lda	$26,ret_from_sys_call
+	bic	$30,$8,$8
 	jsr	$31,do_entInt
 .end entInt
 
@@ -170,8 +168,8 @@
 entArith:
 	SAVE_ALL
 	lda	$8,0x3fff
-	bic	$30,$8,$8
 	lda	$26,ret_from_sys_call
+	bic	$30,$8,$8
 	jsr	$31,do_entArith
 .end entArith
 
@@ -181,8 +179,8 @@
 entIF:
 	SAVE_ALL
 	lda	$8,0x3fff
-	bic	$30,$8,$8
 	lda	$26,ret_from_sys_call
+	bic	$30,$8,$8
 	jsr	$31,do_entIF
 .end entIF
 
@@ -192,8 +190,8 @@
 entDbg:
 	SAVE_ALL
 	lda	$8,0x3fff
-	bic	$30,$8,$8
 	lda	$26,ret_from_sys_call
+	bic	$30,$8,$8
 	jsr	$31,do_entDbg
 .end entDbg
 
@@ -212,18 +210,18 @@
 kernel_clone:
 	.frame $30, 0, $26
 	.prologue 0
-	subq $30,6*8,$30
-	stq $31,0($30)
-	stq $26,8($30)
-	stq $29,16($30)
-	stq $16,24($30)
-	stq $17,32($30)
-	stq $18,40($30)
-	bis $31,2,$0	/* Register v0: syscall nr for fork() */
+	subq	$30,6*8,$30
+	stq	$31,0($30)
+	stq	$26,8($30)
+	stq	$29,16($30)
+	stq	$16,24($30)
+	stq	$17,32($30)
+	stq	$18,40($30)
+	bis	$31,2,$0	/* Register v0: syscall nr for fork() */
 	SAVE_ALL
-	bsr $26,sys_clone
-	stq $0,0($30)
-	br $31,ret_from_sys_call
+	bsr	$26,sys_clone
+	stq	$0,0($30)
+	br	ret_from_sys_call
 .end	kernel_clone
 
 /*
@@ -233,32 +231,32 @@
 .globl	__kernel_thread
 .ent	__kernel_thread
 __kernel_thread:
-	ldgp $29,0($27)		/* we can be called from a module */
+	ldgp	$29,0($27)	/* we can be called from a module */
 	.frame $30, 4*8, $26
-	subq $30,4*8,$30
-	stq $10,16($30)
-	stq $9,8($30)
-	stq $26,0($30)
+	subq	$30,4*8,$30
+	stq	$10,16($30)
+	stq	$9,8($30)
+	stq	$26,0($30)
 	.prologue 1
-	bis $17,$17,$9		/* save fn */
-	bis $18,$18,$10		/* save arg */
-	bsr $26,kernel_clone
-	bne $20,1f		/* $20 is non-zero in child */
-	ldq $26,0($30)
-	ldq $9,8($30)
-	ldq $10,16($30)
-	addq $30,4*8,$30
-	ret $31,($26),1
+	mov	$17,$9		/* save fn */		
+	mov	$18,$10		/* save arg */
+	bsr	$26,kernel_clone
+	bne	$20,1f		/* $20 is non-zero in child */
+	ldq	$26,0($30)
+	ldq	$9,8($30)
+	ldq	$10,16($30)
+	addq	$30,4*8,$30
+	ret	$31,($26),1
 /* this is in child: look out as we don't have any stack here.. */
-1:	bis $9,$9,$27		/* get fn */
-	lda $8,0x3fff
-	bis $10,$10,$16		/* get arg */
-	bic $30,$8,$8		/* get current */
-	jsr $26,($27)
+1:	mov	$9,$27		/* get fn */
+	lda	$8,0x3fff
+	mov	$10,$16		/* get arg */
+	bic	$30,$8,$8	/* get current */
+	jsr	$26,($27)
 	ldgp	$29,0($26)
-	bis $0,$0,$16
-	jsr $26,sys_exit
-	call_pal PAL_halt
+	mov	$0,$16
+	mov	$31,$26
+	jsr	$31,sys_exit
 .end	__kernel_thread
 
 /*
@@ -286,202 +284,199 @@
 .align 3
 .ent	do_switch_stack
 do_switch_stack:
-	lda $30,-SWITCH_STACK_SIZE($30)
-	stq  $9,0($30)
-	stq $10,8($30)
-	stq $11,16($30)
-	stq $12,24($30)
-	stq $13,32($30)
-	stq $14,40($30)
-	stq $15,48($30)
-	stq $26,56($30)
-	stt $f0,64($30)
-	stt $f1,72($30)
-	stt $f2,80($30)
-	stt $f3,88($30)
-	stt $f4,96($30)
-	stt $f5,104($30)
-	stt $f6,112($30)
-	stt $f7,120($30)
-	stt $f8,128($30)
-	stt $f9,136($30)
-	stt $f10,144($30)
-	stt $f11,152($30)
-	stt $f12,160($30)
-	stt $f13,168($30)
-	stt $f14,176($30)
-	stt $f15,184($30)
-	stt $f16,192($30)
-	stt $f17,200($30)
-	stt $f18,208($30)
-	stt $f19,216($30)
-	stt $f20,224($30)
-	stt $f21,232($30)
-	stt $f22,240($30)
-	stt $f23,248($30)
-	stt $f24,256($30)
-	stt $f25,264($30)
-	stt $f26,272($30)
-	stt $f27,280($30)
-	mf_fpcr $f0		# get fpcr
-	stt $f28,288($30)
-	stt $f29,296($30)
-	stt $f30,304($30)
-	stt $f0,312($30)	# save fpcr in slot of $f31
-	ldt $f0,64($30)		# dont let "do_switch_stack" change fp state.
-	ret $31,($1),1
+	lda	$30,-SWITCH_STACK_SIZE($30)
+	stq	$9,0($30)
+	stq	$10,8($30)
+	stq	$11,16($30)
+	stq	$12,24($30)
+	stq	$13,32($30)
+	stq	$14,40($30)
+	stq	$15,48($30)
+	stq	$26,56($30)
+	stt	$f0,64($30)
+	stt	$f1,72($30)
+	stt	$f2,80($30)
+	stt	$f3,88($30)
+	stt	$f4,96($30)
+	stt	$f5,104($30)
+	stt	$f6,112($30)
+	stt	$f7,120($30)
+	stt	$f8,128($30)
+	stt	$f9,136($30)
+	stt	$f10,144($30)
+	stt	$f11,152($30)
+	stt	$f12,160($30)
+	stt	$f13,168($30)
+	stt	$f14,176($30)
+	stt	$f15,184($30)
+	stt	$f16,192($30)
+	stt	$f17,200($30)
+	stt	$f18,208($30)
+	stt	$f19,216($30)
+	stt	$f20,224($30)
+	stt	$f21,232($30)
+	stt	$f22,240($30)
+	stt	$f23,248($30)
+	stt	$f24,256($30)
+	stt	$f25,264($30)
+	stt	$f26,272($30)
+	stt	$f27,280($30)
+	mf_fpcr	$f0		# get fpcr
+	stt	$f28,288($30)
+	stt	$f29,296($30)
+	stt	$f30,304($30)
+	stt	$f0,312($30)	# save fpcr in slot of $f31
+	ldt	$f0,64($30)	# dont let "do_switch_stack" change fp state.
+	ret	$31,($1),1
 .end do_switch_stack
 
 .align 3
 .ent	undo_switch_stack
 undo_switch_stack:
-	ldq  $9,0($30)
-	ldq $10,8($30)
-	ldq $11,16($30)
-	ldq $12,24($30)
-	ldq $13,32($30)
-	ldq $14,40($30)
-	ldq $15,48($30)
-	ldq $26,56($30)
-	ldt $f30,312($30)	# get saved fpcr
-	ldt $f0,64($30)
-	ldt $f1,72($30)
-	ldt $f2,80($30)
-	ldt $f3,88($30)
-	mt_fpcr $f30		# install saved fpcr
-	ldt $f4,96($30)
-	ldt $f5,104($30)
-	ldt $f6,112($30)
-	ldt $f7,120($30)
-	ldt $f8,128($30)
-	ldt $f9,136($30)
-	ldt $f10,144($30)
-	ldt $f11,152($30)
-	ldt $f12,160($30)
-	ldt $f13,168($30)
-	ldt $f14,176($30)
-	ldt $f15,184($30)
-	ldt $f16,192($30)
-	ldt $f17,200($30)
-	ldt $f18,208($30)
-	ldt $f19,216($30)
-	ldt $f20,224($30)
-	ldt $f21,232($30)
-	ldt $f22,240($30)
-	ldt $f23,248($30)
-	ldt $f24,256($30)
-	ldt $f25,264($30)
-	ldt $f26,272($30)
-	ldt $f27,280($30)
-	ldt $f28,288($30)
-	ldt $f29,296($30)
-	ldt $f30,304($30)
-	lda $30,SWITCH_STACK_SIZE($30)
-	ret $31,($1),1
+	ldq	$9,0($30)
+	ldq	$10,8($30)
+	ldq	$11,16($30)
+	ldq	$12,24($30)
+	ldq	$13,32($30)
+	ldq	$14,40($30)
+	ldq	$15,48($30)
+	ldq	$26,56($30)
+	ldt	$f30,312($30)	# get saved fpcr
+	ldt	$f0,64($30)
+	ldt	$f1,72($30)
+	ldt	$f2,80($30)
+	ldt	$f3,88($30)
+	mt_fpcr	$f30		# install saved fpcr
+	ldt	$f4,96($30)
+	ldt	$f5,104($30)
+	ldt	$f6,112($30)
+	ldt	$f7,120($30)
+	ldt	$f8,128($30)
+	ldt	$f9,136($30)
+	ldt	$f10,144($30)
+	ldt	$f11,152($30)
+	ldt	$f12,160($30)
+	ldt	$f13,168($30)
+	ldt	$f14,176($30)
+	ldt	$f15,184($30)
+	ldt	$f16,192($30)
+	ldt	$f17,200($30)
+	ldt	$f18,208($30)
+	ldt	$f19,216($30)
+	ldt	$f20,224($30)
+	ldt	$f21,232($30)
+	ldt	$f22,240($30)
+	ldt	$f23,248($30)
+	ldt	$f24,256($30)
+	ldt	$f25,264($30)
+	ldt	$f26,272($30)
+	ldt	$f27,280($30)
+	ldt	$f28,288($30)
+	ldt	$f29,296($30)
+	ldt	$f30,304($30)
+	lda	$30,SWITCH_STACK_SIZE($30)
+	ret	$31,($1),1
 .end undo_switch_stack
 
 .align 3
 .globl	entUna
 .ent	entUna
 entUna:
-	lda $30,-256($30)
-	stq $0,0($30)
-	ldq $0,256($30)		/* get PS */
-	stq $1,8($30)
-	stq $2,16($30)
-	stq $3,24($30)
-	and $0,8,$0		/* user mode? */
-	stq $4,32($30)
-	bne $0,entUnaUser	/* yup -> do user-level unaligned fault */
-	stq $5,40($30)
-	stq $6,48($30)
-	stq $7,56($30)
-	stq $8,64($30)
-	stq $9,72($30)
-	stq $10,80($30)
-	stq $11,88($30)
-	stq $12,96($30)
-	stq $13,104($30)
-	stq $14,112($30)
-	stq $15,120($30)
+	lda	$30,-256($30)
+	stq	$0,0($30)
+	ldq	$0,256($30)	/* get PS */
+	stq	$1,8($30)
+	stq	$2,16($30)
+	stq	$3,24($30)
+	and	$0,8,$0		/* user mode? */
+	stq	$4,32($30)
+	bne	$0,entUnaUser	/* yup -> do user-level unaligned fault */
+	stq	$5,40($30)
+	stq	$6,48($30)
+	stq	$7,56($30)
+	stq	$8,64($30)
+	stq	$9,72($30)
+	stq	$10,80($30)
+	stq	$11,88($30)
+	stq	$12,96($30)
+	stq	$13,104($30)
+	stq	$14,112($30)
+	stq	$15,120($30)
 	/* 16-18 PAL-saved */
-	stq $19,152($30)
-	stq $20,160($30)
-	stq $21,168($30)
-	stq $22,176($30)
-	stq $23,184($30)
-	stq $24,192($30)
-	stq $25,200($30)
-	stq $26,208($30)
-	stq $27,216($30)
-	stq $28,224($30)
-	stq $29,232($30)
-	stq $30,240($30)
-	stq $31,248($30)
-	lda $8,0x3fff
-	bic $30,$8,$8
-	jsr $26,do_entUna
-	ldq $0,0($30)
-	ldq $1,8($30)
-	ldq $2,16($30)
-	ldq $3,24($30)
-	ldq $4,32($30)
-	ldq $5,40($30)
-	ldq $6,48($30)
-	ldq $7,56($30)
-	ldq $8,64($30)
-	ldq $9,72($30)
-	ldq $10,80($30)
-	ldq $11,88($30)
-	ldq $12,96($30)
-	ldq $13,104($30)
-	ldq $14,112($30)
-	ldq $15,120($30)
+	stq	$19,152($30)
+	stq	$20,160($30)
+	stq	$21,168($30)
+	stq	$22,176($30)
+	stq	$23,184($30)
+	stq	$24,192($30)
+	stq	$25,200($30)
+	stq	$26,208($30)
+	stq	$27,216($30)
+	stq	$28,224($30)
+	stq	$29,232($30)
+	lda	$8,0x3fff
+	stq	$31,248($30)
+	bic	$30,$8,$8
+	jsr	$26,do_entUna
+	ldq	$0,0($30)
+	ldq	$1,8($30)
+	ldq	$2,16($30)
+	ldq	$3,24($30)
+	ldq	$4,32($30)
+	ldq	$5,40($30)
+	ldq	$6,48($30)
+	ldq	$7,56($30)
+	ldq	$8,64($30)
+	ldq	$9,72($30)
+	ldq	$10,80($30)
+	ldq	$11,88($30)
+	ldq	$12,96($30)
+	ldq	$13,104($30)
+	ldq	$14,112($30)
+	ldq	$15,120($30)
 	/* 16-18 PAL-saved */
-	ldq $19,152($30)
-	ldq $20,160($30)
-	ldq $21,168($30)
-	ldq $22,176($30)
-	ldq $23,184($30)
-	ldq $24,192($30)
-	ldq $25,200($30)
-	ldq $26,208($30)
-	ldq $27,216($30)
-	ldq $28,224($30)
-	ldq $29,232($30)
-	ldq $30,240($30)
-	lda $30,256($30)
-	rti
+	ldq	$19,152($30)
+	ldq	$20,160($30)
+	ldq	$21,168($30)
+	ldq	$22,176($30)
+	ldq	$23,184($30)
+	ldq	$24,192($30)
+	ldq	$25,200($30)
+	ldq	$26,208($30)
+	ldq	$27,216($30)
+	ldq	$28,224($30)
+	ldq	$29,232($30)
+	lda	$30,256($30)
+	call_pal PAL_rti
 .end entUna
 
 .align 3
 .ent	entUnaUser
 entUnaUser:
-	ldq $0,0($30)			/* restore original $0 */
-	lda $30,256($30)		/* pop entUna's stack frame */
-	SAVE_ALL			/* setup normal kernel stack */
-	lda $30,-56($30)
-	stq $9,0($30)
-	stq $10,8($30)
-	stq $11,16($30)
-	stq $12,24($30)
-	stq $13,32($30)
-	stq $14,40($30)
-	stq $15,48($30)
-	lda $8,0x3fff
-	addq $30,56,$19
-	bic $30,$8,$8
-	jsr $26,do_entUnaUser
-	ldq $9,0($30)
-	ldq $10,8($30)
-	ldq $11,16($30)
-	ldq $12,24($30)
-	ldq $13,32($30)
-	ldq $14,40($30)
-	ldq $15,48($30)
-	lda $30,56($30)
-	br $31,ret_from_sys_call
-
+	ldq	$0,0($30)	/* restore original $0 */
+	lda	$30,256($30)	/* pop entUna's stack frame */
+	SAVE_ALL		/* setup normal kernel stack */
+	lda	$30,-56($30)
+	stq	$9,0($30)
+	stq	$10,8($30)
+	stq	$11,16($30)
+	stq	$12,24($30)
+	stq	$13,32($30)
+	stq	$14,40($30)
+	stq	$15,48($30)
+	lda	$8,0x3fff
+	addq	$30,56,$19
+	bic	$30,$8,$8
+	jsr	$26,do_entUnaUser
+	ldq	$9,0($30)
+	ldq	$10,8($30)
+	ldq	$11,16($30)
+	ldq	$12,24($30)
+	ldq	$13,32($30)
+	ldq	$14,40($30)
+	ldq	$15,48($30)
+	lda	$30,56($30)
+	br	ret_from_sys_call
 .end	entUnaUser
 
 /*
@@ -491,36 +486,36 @@
 .globl	sys_fork
 .ent	sys_fork
 sys_fork:
-	bsr $1,do_switch_stack
-	bis $31,SIGCHLD,$16
-	bis $31,$31,$17
-	bis $30,$30,$18
-	jsr $26,alpha_clone
-	bsr $1,undo_switch_stack
-	ret $31,($26),1
+	bsr	$1,do_switch_stack
+	bis	$31,SIGCHLD,$16
+	mov	$31,$17
+	mov	$30,$18
+	jsr	$26,alpha_clone
+	bsr	$1,undo_switch_stack
+	ret	$31,($26),1
 .end	sys_fork
 
 .align 3
 .globl	sys_clone
 .ent	sys_clone
 sys_clone:
-	bsr $1,do_switch_stack
+	bsr	$1,do_switch_stack
 	/* arg1 and arg2 come from the user */
-	bis $30,$30,$18
-	jsr $26,alpha_clone
-	bsr $1,undo_switch_stack
-	ret $31,($26),1
+	mov	$30,$18
+	jsr	$26,alpha_clone
+	bsr	$1,undo_switch_stack
+	ret	$31,($26),1
 .end	sys_clone
 
 .align 3
 .globl	sys_vfork
 .ent	sys_vfork
 sys_vfork:
-	bsr $1,do_switch_stack
-	bis $30,$30,$16
-	jsr $26,alpha_vfork
-	bsr $1,undo_switch_stack
-	ret $31,($26),1
+	bsr	$1,do_switch_stack
+	mov	$30,$16
+	jsr	$26,alpha_vfork
+	bsr	$1,undo_switch_stack
+	ret	$31,($26),1
 .end	sys_vfork
 
 .align 3
@@ -528,12 +523,12 @@
 .ent    alpha_switch_to
 alpha_switch_to:
 	.prologue 0
-	bsr $1,do_switch_stack
+	bsr	$1,do_switch_stack
 	call_pal PAL_swpctx
-	lda $16,-2($31)
-	call_pal PAL_tbi
-	bsr $1,undo_switch_stack
-	ret $31,($26),1
+	unop
+	bsr	$1,undo_switch_stack
+	mov	$17,$0
+	ret	$31,($26),1
 .end alpha_switch_to
 
 /*
@@ -592,7 +587,7 @@
 	bne	$5,signal_return
 restore_all:
 	RESTORE_ALL
-	rti
+	call_pal PAL_rti
 
 
 /* PTRACE syscall handler */
@@ -620,7 +615,7 @@
 	s8addq	$0,$2,$2
 	beq	$1,1f
 	ldq	$27,0($2)
-1:	jsr	$26,($27),alpha_ni_syscall
+1:	jsr	$26,($27),sys_gettimeofday
 	ldgp	$29,0($26)
 
 	/* check return.. */
@@ -646,15 +641,15 @@
 	stq	$1,72($30)	/* a3 for return */
 
 	bsr	$1,do_switch_stack
-	bis	$19,$19,$9	/* save old syscall number */
-	bis	$20,$20,$10	/* save old a3 */
+	mov	$19,$9		/* save old syscall number */
+	mov	$20,$10		/* save old a3 */
 	jsr     $26,syscall_trace
-	bis	$9,$9,$19
-	bis	$10,$10,$20
+	mov	$9,$19
+	mov	$10,$20
 	bsr	$1,undo_switch_stack
 
-	bis	$31,$31,$26	/* tell "ret_from_sys_call" that we can restart */
-	br	$31,ret_from_sys_call
+	mov	$31,$26		/* tell "ret_from_sys_call" we can restart */
+	br	ret_from_sys_call
 
 	.align 3
 handle_bottom_half:
@@ -665,7 +660,7 @@
 	ldq	$19,0($30)
 	ldq	$20,8($30)
 	addq	$30,16,$30
-	br	$31,ret_from_handle_bh
+	br	ret_from_handle_bh
 
 	.align 3
 syscall_error:
@@ -683,38 +678,35 @@
 	subq	$31,$0,$0	/* with error in v0 */
 	addq	$31,1,$1	/* set a3 for errno return */
 	stq	$0,0($30)
-	bis	$31,$31,$26	/* tell "ret_from_sys_call" we can restart */
+	mov	$31,$26		/* tell "ret_from_sys_call" we can restart */
 	stq	$1,72($30)	/* a3 for return */
-	br	$31,ret_from_sys_call
+	br	ret_from_sys_call
 
 ret_success:
 	stq	$0,0($30)
 	stq	$31,72($30)	/* a3=0 => no error */
-	br	$31,ret_from_sys_call
+	br	ret_from_sys_call
 
 .align 3
 signal_return:
-	bis	$30,$30,$17
+	mov	$30,$17
 	br	$1,do_switch_stack
-	bis	$30,$30,$18
-	bis	$31,$31,$16
+	mov	$30,$18
+	mov	$31,$16
 	jsr	$26,do_signal
 	bsr	$1,undo_switch_stack
-	br	$31,restore_all
+	br	restore_all
 .end entSys
 
 #ifdef __SMP__
-        .globl  ret_from_smpfork
+        .globl  ret_from_smp_fork
 .align 3
-.ent ret_from_smpfork
-ret_from_smpfork:
-	.set at
-	mb	/* Make the changed data visible before the freed lock. */
-	stq	$31,scheduler_lock	
+.ent ret_from_smp_fork
+ret_from_smp_fork:
 	lda	$26,ret_from_sys_call
+	mov	$17,$16
 	jsr	$31,schedule_tail
-	.set noat
-.end ret_from_smpfork
+.end ret_from_smp_fork
 #endif /* __SMP__ */
 
 .align 3
@@ -727,51 +719,51 @@
 	ldq	$19,0($30)
 	ldq	$20,8($30)
 	addq	$30,16,$30
-	br	$31,ret_from_reschedule
+	br	ret_from_reschedule
 .end reschedule
 
 .align 3
 .ent sys_sigreturn
 sys_sigreturn:
-	bis	$30,$30,$17
+	mov	$30,$17
+	lda	$18,-SWITCH_STACK_SIZE($30)
 	lda	$30,-SWITCH_STACK_SIZE($30)
-	bis	$30,$30,$18
 	jsr	$26,do_sigreturn
 	br	$1,undo_switch_stack
-	br	$31,ret_from_sys_call
+	br	ret_from_sys_call
 .end sys_sigreturn
 
 .align 3
 .ent sys_rt_sigreturn
 sys_rt_sigreturn:
-	bis	$30,$30,$17
+	mov	$30,$17
+	lda	$18,-SWITCH_STACK_SIZE($30)
 	lda	$30,-SWITCH_STACK_SIZE($30)
-	bis	$30,$30,$18
 	jsr	$26,do_rt_sigreturn
 	br	$1,undo_switch_stack
-	br	$31,ret_from_sys_call
+	br	ret_from_sys_call
 .end sys_rt_sigreturn
 
 .align 3
 .ent sys_sigsuspend
 sys_sigsuspend:
-	bis	$30,$30,$17
+	mov	$30,$17
 	br	$1,do_switch_stack
-	bis	$30,$30,$18
+	mov	$30,$18
 	jsr	$26,do_sigsuspend
 	lda	$30,SWITCH_STACK_SIZE($30)
-	br	$31,ret_from_sys_call
+	br	ret_from_sys_call
 .end sys_sigsuspend
 
 .align 3
 .ent sys_rt_sigsuspend
 sys_rt_sigsuspend:
-	bis	$30,$30,$18
+	mov	$30,$18
 	br	$1,do_switch_stack
-	bis	$30,$30,$19
+	mov	$30,$19
 	jsr	$26,do_rt_sigsuspend
 	lda	$30,SWITCH_STACK_SIZE($30)
-	br	$31,ret_from_sys_call
+	br	ret_from_sys_call
 .end sys_rt_sigsuspend
 
 	.data
diff -u --recursive --new-file v2.2.7/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v2.2.7/linux/arch/alpha/kernel/osf_sys.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/alpha/kernel/osf_sys.c	Mon May 10 09:55:21 1999
@@ -141,6 +141,7 @@
 	struct inode *inode;
 	struct osf_dirent_callback buf;
 
+	lock_kernel();
 	error = -EBADF;
 	file = fget(fd);
 	if (!file)
@@ -173,6 +174,7 @@
 out_putf:
 	fput(file);
 out:
+	unlock_kernel();
 	return error;
 }
 
@@ -883,7 +885,21 @@
 	case GSI_IEEE_FP_CONTROL:
 		/* Return current software fp control & status bits.  */
 		/* Note that DU doesn't verify available space here.  */
-		w = current->tss.flags & IEEE_SW_MASK;
+
+		/* EV6 implements most of the bits in hardware.  If
+		   UNDZ is not set, UNFD is maintained in software.  */
+		if (implver() == IMPLVER_EV6) {
+			unsigned long fpcr = rdfpcr();
+			w = ieee_fpcr_to_swcr(fpcr);
+			if (!(fpcr & FPCR_UNDZ)) {
+				w &= ~IEEE_TRAP_ENABLE_UNF;
+				w |= current->tss.flags & IEEE_TRAP_ENABLE_UNF;
+			}
+		} else {
+			/* Otherwise we are forced to do everything in sw.  */
+			w = current->tss.flags & IEEE_SW_MASK;
+		}
+
 		if (put_user(w, (unsigned long *) buffer))
 			return -EFAULT;
 		return 0;
@@ -933,7 +949,7 @@
 {
 	switch (op) {
 	case SSI_IEEE_FP_CONTROL: {
-		unsigned long swcr, fpcr;
+		unsigned long swcr, fpcr, undz;
 
 		/* 
 		 * Alpha Architecture Handbook 4.7.7.3:
@@ -948,11 +964,12 @@
 		current->tss.flags &= ~IEEE_SW_MASK;
 		current->tss.flags |= swcr & IEEE_SW_MASK;
 
-		/* Update the real fpcr.  For exceptions that are disabled in
-		   software but have not been seen, enable the exception in
-		   hardware so that we can update our software status mask.  */
-		fpcr = rdfpcr() & (~FPCR_MASK | FPCR_DYN_MASK);
-		fpcr |= ieee_swcr_to_fpcr(swcr | (~swcr & IEEE_STATUS_MASK)>>16);
+		/* Update the real fpcr.  Keep UNFD off if not UNDZ.  */
+		fpcr = rdfpcr();
+		undz = (fpcr & FPCR_UNDZ);
+		fpcr &= ~(FPCR_MASK | FPCR_DYN_MASK | FPCR_UNDZ);
+		fpcr |= ieee_swcr_to_fpcr(swcr);
+		fpcr &= ~(undz << 1);
 		wrfpcr(fpcr);
 		   
 		return 0;
@@ -1407,8 +1424,9 @@
 	    copy_from_user(&txc.tick, &txc_p->tick, sizeof(struct timex32) - 
 			   offsetof(struct timex32, time)))
 	  return -EFAULT;
-	
-	if ((ret = do_adjtimex(&txc)))
+
+	ret = do_adjtimex(&txc);	
+	if (ret < 0)
 	  return ret;
 	
 	/* copy back to timex32 */
@@ -1418,5 +1436,5 @@
 	    (put_tv32(&txc_p->time, &txc.time)))
 	  return -EFAULT;
 
-	return 0;
+	return ret;
 }
diff -u --recursive --new-file v2.2.7/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c
--- v2.2.7/linux/arch/alpha/kernel/process.c	Wed Jan 20 23:14:04 1999
+++ linux/arch/alpha/kernel/process.c	Mon May 10 09:55:21 1999
@@ -237,10 +237,13 @@
 
 void flush_thread(void)
 {
-	/* Arrange for each exec'ed process to start off with a 
-	   clean slate with respect to the FPU.  */
+	/* Arrange for each exec'ed process to start off with a clean slate
+	   with respect to the FPU.  This is all exceptions disabled.  Note
+           that EV6 defines UNFD valid only with UNDZ, which we don't want
+	   for IEEE conformance -- so that disabled bit remains in software.  */
+
 	current->tss.flags &= ~IEEE_SW_MASK;
-	wrfpcr(FPCR_DYN_NORMAL);
+	wrfpcr(FPCR_DYN_NORMAL | FPCR_INVD | FPCR_DZED | FPCR_OVFD | FPCR_INED);
 }
 
 void release_thread(struct task_struct *dead_task)
@@ -270,8 +273,6 @@
 			(struct pt_regs *) (swstack+1));
 }
 
-extern void ret_from_sys_call(void);
-extern void ret_from_smpfork(void);
 /*
  * Copy an alpha thread..
  *
@@ -282,9 +283,13 @@
  * Use the passed "regs" pointer to determine how much space we need
  * for a kernel fork().
  */
+
 int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
 	struct task_struct * p, struct pt_regs * regs)
 {
+	extern void ret_from_sys_call(void);
+	extern void ret_from_smp_fork(void);
+
 	struct pt_regs * childregs;
 	struct switch_stack * childstack, *stack;
 	unsigned long stack_offset;
@@ -292,18 +297,18 @@
 	stack_offset = PAGE_SIZE - sizeof(struct pt_regs);
 	if (!(regs->ps & 8))
 		stack_offset = (PAGE_SIZE-1) & (unsigned long) regs;
-	childregs = (struct pt_regs *) (stack_offset + PAGE_SIZE + (unsigned long)p);
+	childregs = (struct pt_regs *) (stack_offset + PAGE_SIZE + (long)p);
 		
 	*childregs = *regs;
 	childregs->r0 = 0;
 	childregs->r19 = 0;
-	childregs->r20 = 1;	/* OSF/1 has some strange fork() semantics.. */
+	childregs->r20 = 1;	/* OSF/1 has some strange fork() semantics.  */
 	regs->r20 = 0;
 	stack = ((struct switch_stack *) regs) - 1;
 	childstack = ((struct switch_stack *) childregs) - 1;
 	*childstack = *stack;
 #ifdef __SMP__
-	childstack->r26 = (unsigned long) ret_from_smpfork;
+	childstack->r26 = (unsigned long) ret_from_smp_fork;
 #else
 	childstack->r26 = (unsigned long) ret_from_sys_call;
 #endif
@@ -328,10 +333,12 @@
 	dump->start_code  = current->mm->start_code;
 	dump->start_data  = current->mm->start_data;
 	dump->start_stack = rdusp() & ~(PAGE_SIZE - 1);
-	dump->u_tsize = (current->mm->end_code - dump->start_code) >> PAGE_SHIFT;
-	dump->u_dsize = (current->mm->brk + (PAGE_SIZE - 1) - dump->start_data) >> PAGE_SHIFT;
-	dump->u_ssize =
-	  (current->mm->start_stack - dump->start_stack + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	dump->u_tsize = ((current->mm->end_code - dump->start_code)
+			 >> PAGE_SHIFT);
+	dump->u_dsize = ((current->mm->brk + PAGE_SIZE-1 - dump->start_data)
+			 >> PAGE_SHIFT);
+	dump->u_ssize = (current->mm->start_stack - dump->start_stack
+			 + PAGE_SIZE-1) >> PAGE_SHIFT;
 
 	/*
 	 * We store the registers in an order/format that is
diff -u --recursive --new-file v2.2.7/linux/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c
--- v2.2.7/linux/arch/alpha/kernel/smp.c	Mon Mar 29 11:09:11 1999
+++ linux/arch/alpha/kernel/smp.c	Mon May 10 09:55:21 1999
@@ -37,7 +37,18 @@
 #define DBGS(args)
 #endif
 
-struct ipi_msg_flush_tb_struct ipi_msg_flush_tb __cacheline_aligned;
+struct ipi_msg_flush_tb_struct {
+	volatile unsigned int flush_tb_mask;
+	union {
+		struct mm_struct *	flush_mm;
+		struct vm_area_struct *	flush_vma;
+	} p;
+	unsigned long flush_addr;
+	unsigned long flush_end;
+};
+
+static struct ipi_msg_flush_tb_struct ipi_msg_flush_tb __cacheline_aligned;
+static spinlock_t flush_tb_lock = SPIN_LOCK_UNLOCKED;
 
 struct cpuinfo_alpha cpu_data[NR_CPUS];
 
@@ -786,7 +797,7 @@
 	unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
 	long timeout = 1000000;
 
-	spin_lock_own(&kernel_flag, "flush_tlb_all");
+	spin_lock(&flush_tb_lock);
 
 	ipi_msg_flush_tb.flush_tb_mask = to_whom;
 	send_ipi_message(to_whom, IPI_TLB_ALL);
@@ -803,6 +814,8 @@
 		       ipi_msg_flush_tb.flush_tb_mask);
 		ipi_msg_flush_tb.flush_tb_mask = 0;
 	}
+
+	spin_unlock(&flush_tb_lock);
 }
 
 void
@@ -811,7 +824,7 @@
 	unsigned long to_whom = cpu_present_map ^ (1 << smp_processor_id());
 	long timeout = 1000000;
 
-	spin_lock_own(&kernel_flag, "flush_tlb_mm");
+	spin_lock(&flush_tb_lock);
 
 	ipi_msg_flush_tb.flush_tb_mask = to_whom;
 	ipi_msg_flush_tb.p.flush_mm = mm;
@@ -833,6 +846,8 @@
 		       ipi_msg_flush_tb.flush_tb_mask);
 		ipi_msg_flush_tb.flush_tb_mask = 0;
 	}
+
+	spin_unlock(&flush_tb_lock);
 }
 
 void
@@ -843,7 +858,7 @@
 	struct mm_struct * mm = vma->vm_mm;
 	int timeout = 1000000;
 
-	spin_lock_own(&kernel_flag, "flush_tlb_page");
+	spin_lock(&flush_tb_lock);
 
 	ipi_msg_flush_tb.flush_tb_mask = to_whom;
 	ipi_msg_flush_tb.p.flush_vma = vma;
@@ -866,6 +881,8 @@
 		       ipi_msg_flush_tb.flush_tb_mask);
 		ipi_msg_flush_tb.flush_tb_mask = 0;
 	}
+
+	spin_unlock(&flush_tb_lock);
 }
 
 void
diff -u --recursive --new-file v2.2.7/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- v2.2.7/linux/arch/alpha/kernel/traps.c	Tue Feb 23 15:21:32 1999
+++ linux/arch/alpha/kernel/traps.c	Mon May 10 09:55:21 1999
@@ -125,13 +125,16 @@
 	    unsigned long a2, unsigned long a3, unsigned long a4,
 	    unsigned long a5, struct pt_regs regs)
 {
-	if ((summary & 1)) {
-		/*
-		 * Software-completion summary bit is set, so try to
-		 * emulate the instruction.
-		 */
-		if (alpha_fp_emul_imprecise(&regs, write_mask)) {
-			return;		/* emulation was successful */
+	if (summary & 1) {
+		/* Software-completion summary bit is set, so try to
+		   emulate the instruction.  */
+		if (implver() == IMPLVER_EV6) {
+			/* Whee!  EV6 has precice exceptions.  */
+			if (alpha_fp_emul(regs.pc - 4))
+				return;
+		} else {
+			if (alpha_fp_emul_imprecise(&regs, write_mask))
+				return;
 		}
 	}
 
@@ -141,7 +144,7 @@
 		current->comm, regs.pc, summary, write_mask);
 #endif
 	die_if_kernel("Arithmetic fault", &regs, 0, 0);
-	force_sig(SIGFPE, current);
+	send_sig(SIGFPE, current, 1);
 	unlock_kernel();
 }
 
@@ -150,14 +153,17 @@
 	 unsigned long a2, unsigned long a3, unsigned long a4,
 	 unsigned long a5, struct pt_regs regs)
 {
-	lock_kernel();
 	die_if_kernel("Instruction fault", &regs, type, 0);
 	switch (type) {
 	      case 0: /* breakpoint */
 		if (ptrace_cancel_bpt(current)) {
 			regs.pc -= 4;	/* make pc point to former bpt */
 		}
-		force_sig(SIGTRAP, current);
+		send_sig(SIGTRAP, current, 1);
+		break;
+
+	      case 1: /* bugcheck */
+		send_sig(SIGTRAP, current, 1);
 		break;
 
 	      case 2: /* gentrap */
@@ -171,14 +177,13 @@
 		switch ((long) regs.r16) {
 		      case GEN_INTOVF: case GEN_INTDIV: case GEN_FLTOVF:
 		      case GEN_FLTDIV: case GEN_FLTUND: case GEN_FLTINV:
-		      case GEN_FLTINE:
-			force_sig(SIGFPE, current);
+		      case GEN_FLTINE: case GEN_ROPRAND:
+			send_sig(SIGFPE, current, 1);
 			break;
 
 		      case GEN_DECOVF:
 		      case GEN_DECDIV:
 		      case GEN_DECINV:
-		      case GEN_ROPRAND:
 		      case GEN_ASSERTERR:
 		      case GEN_NULPTRERR:
 		      case GEN_STKOVF:
@@ -193,42 +198,29 @@
 		      case GEN_SUBRNG5:
 		      case GEN_SUBRNG6:
 		      case GEN_SUBRNG7:
-			force_sig(SIGILL, current);
+			send_sig(SIGTRAP, current, 1);
 			break;
 		}
 		break;
 
-	      case 1: /* bugcheck */
 	      case 3: /* FEN fault */
-		force_sig(SIGILL, current);
+		send_sig(SIGILL, current, 1);
 		break;
 
 	      case 4: /* opDEC */
-#ifdef CONFIG_ALPHA_NEED_ROUNDING_EMULATION
-		{
-			unsigned int opcode;
-
-			/* get opcode of faulting instruction: */
-			get_user(opcode, (__u32*)(regs.pc - 4));
-			opcode >>= 26;
-			if (opcode == 0x16) {
-				/*
-				 * It's a FLTI instruction, emulate it
-				 * (we don't do no stinkin' VAX fp...)
-				 */
-				if (!alpha_fp_emul(regs.pc - 4))
-					force_sig(SIGFPE, current);
-				break;
-			}
+		if (implver() == IMPLVER_EV4) {
+			/* EV4 does not implement anything except normal
+			   rounding.  Everything else will come here as
+			   an illegal instruction.  Emulate them.  */
+			if (alpha_fp_emul(regs.pc - 4))
+				return;
 		}
-#endif
-		force_sig(SIGILL, current);
+		send_sig(SIGILL, current, 1);
 		break;
 
 	      default:
 		panic("do_entIF: unexpected instruction-fault type");
 	}
-	unlock_kernel();
 }
 
 /* There is an ifdef in the PALcode in MILO that enables a 
@@ -877,14 +869,14 @@
 give_sigsegv:
 	regs->pc -= 4;  /* make pc point to faulting insn */
 	lock_kernel();
-	force_sig(SIGSEGV, current);
+	send_sig(SIGSEGV, current, 1);
 	unlock_kernel();
 	return;
 
 give_sigbus:
 	regs->pc -= 4;
 	lock_kernel();
-	force_sig(SIGBUS, current);
+	send_sig(SIGBUS, current, 1);
 	unlock_kernel();
 	return;
 }
diff -u --recursive --new-file v2.2.7/linux/arch/alpha/lib/copy_user.S linux/arch/alpha/lib/copy_user.S
--- v2.2.7/linux/arch/alpha/lib/copy_user.S	Wed Apr 28 11:37:29 1999
+++ linux/arch/alpha/lib/copy_user.S	Fri Apr 30 08:22:19 1999
@@ -109,7 +109,7 @@
 $66:
 	EXI( ldq $1,0($7) )
 	subq $4,8,$4
-	stq $1,0($6)
+	EXO( stq $1,0($6) )
 	addq $7,8,$7
 	subq $0,8,$0
 	addq $6,8,$6
diff -u --recursive --new-file v2.2.7/linux/arch/alpha/math-emu/fp-emul.c linux/arch/alpha/math-emu/fp-emul.c
--- v2.2.7/linux/arch/alpha/math-emu/fp-emul.c	Tue Aug 18 22:02:02 1998
+++ linux/arch/alpha/math-emu/fp-emul.c	Mon May 10 09:55:21 1999
@@ -13,6 +13,7 @@
 #define OPC_INTL	0x11
 #define OPC_INTS	0x12
 #define OPC_INTM	0x13
+#define OPC_FLTC	0x14
 #define OPC_FLTV	0x15
 #define OPC_FLTI	0x16
 #define OPC_FLTL	0x17
@@ -21,33 +22,37 @@
 
 #define	OPC_JSR		0x1a
 
+#define OP_FUN(OP,FUN)	((OP << 26) | (FUN << 5))
+
 /*
- * "Base" function codes for the FLTI-class instructions.  These
- * instructions all have opcode 0x16.  Note that in most cases these
- * actually correspond to the "chopped" form of the instruction.  Not
- * to worry---we extract the qualifier bits separately and deal with
- * them separately.  Notice that base function code 0x2c is used for
- * both CVTTS and CVTST.  The other bits in the function code are used
- * to distinguish the two.
+ * "Base" function codes for the FLTI-class instructions.
+ * Note that in most cases these actually correspond to the "chopped"
+ * form of the instruction.  Not to worry---we extract the qualifier
+ * bits separately and deal with them separately.  Notice that base
+ * function code 0x2c is used for both CVTTS and CVTST.  The other bits
+ * in the function code are used to distinguish the two.
  */
-#define FLTI_FUNC_ADDS			0x000
-#define FLTI_FUNC_ADDT			0x020
-#define FLTI_FUNC_CMPTEQ		0x025
-#define FLTI_FUNC_CMPTLT		0x026
-#define FLTI_FUNC_CMPTLE		0x027
-#define FLTI_FUNC_CMPTUN		0x024
-#define FLTI_FUNC_CVTTS_or_CVTST	0x02c
-#define FLTI_FUNC_CVTTQ			0x02f
-#define FLTI_FUNC_CVTQS			0x03c
-#define FLTI_FUNC_CVTQT			0x03e
-#define FLTI_FUNC_DIVS			0x003
-#define FLTI_FUNC_DIVT			0x023
-#define FLTI_FUNC_MULS			0x002
-#define FLTI_FUNC_MULT			0x022
-#define FLTI_FUNC_SUBS			0x001
-#define FLTI_FUNC_SUBT			0x021
+#define FLTI_FUNC_ADDS			OP_FUN(OPC_FLTI, 0x000)
+#define FLTI_FUNC_ADDT			OP_FUN(OPC_FLTI, 0x020)
+#define FLTI_FUNC_CMPTEQ		OP_FUN(OPC_FLTI, 0x025)
+#define FLTI_FUNC_CMPTLT		OP_FUN(OPC_FLTI, 0x026)
+#define FLTI_FUNC_CMPTLE		OP_FUN(OPC_FLTI, 0x027)
+#define FLTI_FUNC_CMPTUN		OP_FUN(OPC_FLTI, 0x024)
+#define FLTI_FUNC_CVTTS_or_CVTST	OP_FUN(OPC_FLTI, 0x02c)
+#define FLTI_FUNC_CVTTQ			OP_FUN(OPC_FLTI, 0x02f)
+#define FLTI_FUNC_CVTQS			OP_FUN(OPC_FLTI, 0x03c)
+#define FLTI_FUNC_CVTQT			OP_FUN(OPC_FLTI, 0x03e)
+#define FLTI_FUNC_DIVS			OP_FUN(OPC_FLTI, 0x003)
+#define FLTI_FUNC_DIVT			OP_FUN(OPC_FLTI, 0x023)
+#define FLTI_FUNC_MULS			OP_FUN(OPC_FLTI, 0x002)
+#define FLTI_FUNC_MULT			OP_FUN(OPC_FLTI, 0x022)
+#define FLTI_FUNC_SUBS			OP_FUN(OPC_FLTI, 0x001)
+#define FLTI_FUNC_SUBT			OP_FUN(OPC_FLTI, 0x021)
+
+#define FLTC_FUNC_SQRTS			OP_FUN(OPC_FLTC, 0x00B)
+#define FLTC_FUNC_SQRTT			OP_FUN(OPC_FLTC, 0x02B)
 
-#define FLTI_FUNC_CVTQL			0x030	/* opcode 0x17 */
+#define FLTL_FUNC_CVTQL			OP_FUN(OPC_FLTL, 0x030)
 
 #define MISC_TRAPB	0x0000
 #define MISC_EXCB	0x0400
@@ -101,7 +106,7 @@
 long
 alpha_fp_emul (unsigned long pc)
 {
-	unsigned long opcode, fa, fb, fc, func, mode;
+	unsigned long op_fun, fa, fb, fc, func, mode;
 	unsigned long fpcw = current->tss.flags;
 	unsigned long va, vb, vc, res, fpcr;
 	__u32 insn;
@@ -110,10 +115,11 @@
 
 	get_user(insn, (__u32*)pc);
 	fc     = (insn >>  0) &  0x1f;	/* destination register */
-	func   = (insn >>  5) & 0x7ff;
 	fb     = (insn >> 16) &  0x1f;
 	fa     = (insn >> 21) &  0x1f;
-	opcode = insn >> 26;
+	func   = (insn >>  5) & 0x7ff;
+	mode   = (insn >>  5) & 0xc0;
+	op_fun = insn & OP_FUN(0x3f, 0x3f);
 	
 	va = alpha_read_fp_reg(fa);
 	vb = alpha_read_fp_reg(fb);
@@ -123,7 +129,6 @@
 	 * Try the operation in software.  First, obtain the rounding
 	 * mode...
 	 */
-	mode = func & 0xc0;
 	if (mode == 0xc0) {
 	    /* dynamic---get rounding mode from fpcr: */
 	    mode = ((fpcr & FPCR_DYN_MASK) >> FPCR_DYN_SHIFT) << ROUND_SHIFT;
@@ -135,8 +140,7 @@
 		something_is_wrong();
 	}
 
-	/* least 6 bits contain operation code: */
-	switch (func & 0x3f) {
+	switch (op_fun) {
 	      case FLTI_FUNC_CMPTEQ:
 		res = ieee_CMPTEQ(va, vb, &vc);
 		break;
@@ -153,7 +157,7 @@
 		res = ieee_CMPTUN(va, vb, &vc);
 		break;
 
-	      case FLTI_FUNC_CVTQL:
+	      case FLTL_FUNC_CVTQL:
 		/*
 		 * Notice: We can get here only due to an integer
 		 * overflow.  Such overflows are reported as invalid
@@ -222,6 +226,14 @@
 		res = ieee_CVTTQ(mode, vb, &vc);
 		break;
 
+	      case FLTC_FUNC_SQRTS:
+		res = ieee_SQRTS(mode, vb, &vc);
+		break;
+
+	      case FLTC_FUNC_SQRTT:
+		res = ieee_SQRTT(mode, vb, &vc);
+		break;
+
 	      default:
 		printk("alpha_fp_emul: unexpected function code %#lx at %#lx\n",
 		       func & 0x3f, pc);
@@ -247,7 +259,7 @@
 
 		/* Update hardware control register */
 		fpcr &= (~FPCR_MASK | FPCR_DYN_MASK);
-		fpcr |= ieee_swcr_to_fpcr(fpcw | (~fpcw&IEEE_STATUS_MASK)>>16);
+		fpcr |= ieee_swcr_to_fpcr(fpcw);
 		wrfpcr(fpcr);
 
 		/* Do we generate a signal?  */
@@ -319,6 +331,7 @@
 			write_mask &= ~(1UL << rc);
 			break;
 
+		      case OPC_FLTC:
 		      case OPC_FLTV:
 		      case OPC_FLTI:
 		      case OPC_FLTL:
@@ -326,13 +339,11 @@
 			break;
 		}
 		if (!write_mask) {
-			if ((opcode == OPC_FLTI || opcode == OPC_FLTL)
-			    && alpha_fp_emul(trigger_pc))
-			{
-			    /* re-execute insns in trap-shadow: */
-			    regs->pc = trigger_pc + 4;
-			    MOD_DEC_USE_COUNT;
-			    return 1;
+			if (alpha_fp_emul(trigger_pc)) {
+				/* re-execute insns in trap-shadow: */
+				regs->pc = trigger_pc + 4;
+				MOD_DEC_USE_COUNT;
+				return 1;
 			}
 			break;
 		}
diff -u --recursive --new-file v2.2.7/linux/arch/alpha/math-emu/ieee-math.c linux/arch/alpha/math-emu/ieee-math.c
--- v2.2.7/linux/arch/alpha/math-emu/ieee-math.c	Wed Sep  9 14:51:04 1998
+++ linux/arch/alpha/math-emu/ieee-math.c	Mon May 10 09:55:21 1999
@@ -22,6 +22,7 @@
  * functions are used on exceptional numbers only (well, assuming you
  * don't turn on the "trap on inexact"...).
  */
+#include <linux/sched.h>
 #include "ieee-math.h"
 
 #define STICKY_S	0x20000000	/* both in longword 0 of fraction */
@@ -1339,4 +1340,42 @@
 	normalize(&op_c);
 	op_c.e -= 9;		/* remove excess exp from original shift */
 	return round_t_ieee(f, &op_c, c);
+}
+
+/*
+ * Sqrt a = b, where a and b are ieee s-floating numbers.  "f"
+ * contains the rounding mode etc.
+ */
+unsigned long
+ieee_SQRTS (int f, unsigned long a, unsigned long *b)
+{
+	fpclass_t a_type;
+	EXTENDED op_a, op_b;
+
+	*b = IEEE_QNaN;
+	a_type = extend_ieee(a, &op_a, SINGLE);
+	if (op_a.s == 0) {
+		/* FIXME -- handle positive denormals.  */
+		send_sig(SIGFPE, current, 1);
+	}
+	return FPCR_INV;
+}
+
+/*
+ * Sqrt a = b, where a and b are ieee t-floating numbers.  "f"
+ * contains the rounding mode etc.
+ */
+unsigned long
+ieee_SQRTT (int f, unsigned long a, unsigned long *b)
+{
+	fpclass_t a_type;
+	EXTENDED op_a, op_b;
+
+	*b = IEEE_QNaN;
+	a_type = extend_ieee(a, &op_a, DOUBLE);
+	if (op_a.s == 0) {
+		/* FIXME -- handle positive denormals.  */
+		send_sig(SIGFPE, current, 1);
+	}
+	return FPCR_INV;
 }
diff -u --recursive --new-file v2.2.7/linux/arch/alpha/math-emu/ieee-math.h linux/arch/alpha/math-emu/ieee-math.h
--- v2.2.7/linux/arch/alpha/math-emu/ieee-math.h	Thu Dec 21 22:22:05 1995
+++ linux/arch/alpha/math-emu/ieee-math.h	Mon May 10 09:55:21 1999
@@ -48,5 +48,7 @@
 				unsigned long *c);
 extern unsigned long ieee_DIVT (int rm, unsigned long a, unsigned long b,
 				unsigned long *c);
+extern unsigned long ieee_SQRTS (int rm, unsigned long a, unsigned long *b);
+extern unsigned long ieee_SQRTT (int rm, unsigned long a, unsigned long *b);
 
 #endif /* __ieee_math_h__ */
diff -u --recursive --new-file v2.2.7/linux/arch/arm/kernel/sys_arm.c linux/arch/arm/kernel/sys_arm.c
--- v2.2.7/linux/arch/arm/kernel/sys_arm.c	Tue Dec 22 14:16:53 1998
+++ linux/arch/arm/kernel/sys_arm.c	Sat May  8 11:14:01 1999
@@ -77,12 +77,14 @@
 		goto out;
 	if (!(a.flags & MAP_ANONYMOUS)) {
 		error = -EBADF;
-		if (a.fd >= current->files->max_fds || 
-		    !(file = current->files->fd[a.fd]))
+		file = fget(a.fd);
+		if (!file)
 			goto out;
 	}
 	a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset);
+	if (file)
+		fput(file);
 out:
 	unlock_kernel();
 	return error;
diff -u --recursive --new-file v2.2.7/linux/arch/arm/mm/Makefile linux/arch/arm/mm/Makefile
--- v2.2.7/linux/arch/arm/mm/Makefile	Fri May  8 23:14:42 1998
+++ linux/arch/arm/mm/Makefile	Sat May  8 11:06:56 1999
@@ -8,37 +8,30 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 all:	lib first_rule
-ifeq ($(MACHINE),a5k)
-MMARCH=arc
-else
-MMARCH=$(MACHINE)
-endif
 
 O_TARGET := mm.o
-O_OBJS   := init.o extable.o fault-$(PROCESSOR).o mm-$(MMARCH).o
+O_OBJS   := init.o extable.o fault-$(PROCESSOR).o small_page.o
 
 ifeq ($(PROCESSOR),armo)
  O_OBJS += proc-arm2,3.o
 endif
 
 ifeq ($(PROCESSOR),armv)
- O_OBJS += small_page.o proc-arm6,7.o proc-sa110.o
+ O_OBJS += mm-$(MACHINE).o proc-arm6,7.o proc-sa110.o ioremap.o
 endif
 
 include $(TOPDIR)/Rules.make
 
-proc-arm2,3.o:	../lib/constants.h
-proc-arm6,7.o:	../lib/constants.h
-proc-sa110.o:	../lib/constants.h
-
 %.o: %.S
-ifneq ($(CONFIG_BINUTILS_NEW),y)
-	$(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..$@.tmp.s
-	$(CC) $(CFLAGS:-pipe=) -c -o $@ ..$@.tmp.s
-	$(RM) ..$@.tmp.s
-else
 	$(CC) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $<
-endif
 
 .PHONY:	lib
 lib:;	@$(MAKE) -C ../lib constants.h
+
+# Special dependencies
+fault-armv.o: fault-common.c
+fault-armo.o: fault-common.c
+proc-arm2,3.o:	../lib/constants.h
+proc-arm6,7.o:	../lib/constants.h
+proc-sa110.o:	../lib/constants.h
+
diff -u --recursive --new-file v2.2.7/linux/arch/arm/mm/fault-armo.c linux/arch/arm/mm/fault-armo.c
--- v2.2.7/linux/arch/arm/mm/fault-armo.c	Tue Dec 22 14:16:53 1998
+++ linux/arch/arm/mm/fault-armo.c	Sat May  8 11:06:56 1999
@@ -1,11 +1,10 @@
 /*
- *  linux/arch/arm/mm/fault.c
+ *  linux/arch/arm/mm/fault-armo.c
  *
  *  Copyright (C) 1995  Linus Torvalds
- *  Modifications for ARM processor (c) 1995, 1996 Russell King
+ *  Modifications for ARM processor (c) 1995-1999 Russell King
  */
 
-#include <linux/config.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -15,8 +14,7 @@
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -27,35 +25,32 @@
 #define FAULT_CODE_WRITE	0x02
 #define FAULT_CODE_USER		0x01
 
-struct pgtable_cache_struct quicklists;
+#define DO_COW(m)		((m) & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW))
+#define READ_FAULT(m)		(!((m) & FAULT_CODE_WRITE))
 
-void __bad_pmd(pmd_t *pmd)
+#include "fault-common.c"
+
+static void *alloc_table(int size, int prio)
 {
-	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-#ifdef CONFIG_DEBUG_ERRORS
-	__backtrace();
-#endif
-	set_pmd(pmd, mk_pmd(BAD_PAGETABLE));
+	if (size != 128)
+		printk("invalid table size\n");
+	return (void *)get_page_8k(prio);
 }
 
-void __bad_pmd_kernel(pmd_t *pmd)
+void free_table(void *table)
 {
-	printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
-#ifdef CONFIG_DEBUG_ERRORS
-	__backtrace();
-#endif
-	set_pmd(pmd, mk_pmd(BAD_PAGETABLE));
+	free_page_8k((unsigned long)table);
 }
 
 pgd_t *get_pgd_slow(void)
 {
-	pgd_t *pgd = (pgd_t *) kmalloc(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL);
+	pgd_t *pgd = (pgd_t *)alloc_table(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL);
 	pgd_t *init;
-	
+
 	if (pgd) {
 		init = pgd_offset(&init_mm, 0);
-		memzero (pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
-		memcpy (pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+		memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
+		memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
 			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR);
 	}
 	return pgd;
@@ -65,17 +60,17 @@
 {
 	pte_t *pte;
 
-	pte = (pte_t *) kmalloc (PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL);
+	pte = (pte_t *)alloc_table(PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL);
 	if (pmd_none(*pmd)) {
 		if (pte) {
-			memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR);
+			memzero(pte, PTRS_PER_PTE * BYTES_PER_PTR);
 			set_pmd(pmd, mk_pmd(pte));
 			return pte + offset;
 		}
 		set_pmd(pmd, mk_pmd(BAD_PAGETABLE));
 		return NULL;
 	}
-	kfree (pte);
+	free_table((void *)pte);
 	if (pmd_bad(*pmd)) {
 		__bad_pmd(pmd);
 		return NULL;
@@ -83,126 +78,22 @@
 	return (pte_t *) pmd_page(*pmd) + offset;
 }
 
-extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret);
-
-static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs,
-			       struct task_struct *tsk, struct mm_struct *mm)
-{
-	/*
-	 * Oops. The kernel tried to access some bad page. We'll have to
-	 * terminate things with extreme prejudice.
-	 */
-	pgd_t *pgd;
-	if (addr < PAGE_SIZE)
-	    printk (KERN_ALERT "Unable to handle kernel NULL pointer dereference");
-	else
-	    printk (KERN_ALERT "Unable to handle kernel paging request");
-	printk (" at virtual address %08lx\n", addr);
-	printk (KERN_ALERT "current->tss.memmap = %08lX\n", tsk->tss.memmap);
-	pgd = pgd_offset (mm, addr);
-	printk (KERN_ALERT "*pgd = %08lx", pgd_val (*pgd));
-	if (!pgd_none (*pgd)) {
-		pmd_t *pmd;
-		pmd = pmd_offset (pgd, addr);
-		printk (", *pmd = %08lx", pmd_val (*pmd));
-		if (!pmd_none (*pmd))
-			printk (", *pte = %08lx", pte_val (*pte_offset (pmd, addr)));
-	}
-	printk ("\n");
-	die_if_kernel ("Oops", regs, mode, SIGKILL);
-	do_exit (SIGKILL);
-}
-
-static void
-handle_dataabort (unsigned long addr, int mode, struct pt_regs *regs)
-{
-	struct task_struct *tsk;
-	struct mm_struct *mm;
-	struct vm_area_struct *vma;
-	unsigned long fixup;
-
-	lock_kernel();
-	tsk = current;
-	mm = tsk->mm;
-
-	down(&mm->mmap_sem);
-	vma = find_vma (mm, addr);
-	if (!vma)
-		goto bad_area;
-	if (addr >= vma->vm_start)
-		goto good_area;
-	if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack (vma, addr))
-		goto bad_area;
-
-	/*
-	 * Ok, we have a good vm_area for this memory access, so
-	 * we can handle it..
-	 */
-good_area:
-	if (!(mode & FAULT_CODE_WRITE)) { /* write? */
-		if (!(vma->vm_flags & (VM_READ|VM_EXEC)))
-			goto bad_area;
-	} else {
-		if (!(vma->vm_flags & VM_WRITE))
-			goto bad_area;
-	}
-	handle_mm_fault (tsk, vma, addr, mode & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW));
-	up(&mm->mmap_sem);
-	goto out;
-
-	/*
-	 * Something tried to access memory that isn't in our memory map..
-	 * Fix it, but check if it's kernel or user first..
-	 */
-bad_area:
-	up(&mm->mmap_sem);
-	if (mode & FAULT_CODE_USER) {
-//extern int console_loglevel;
-//cli();
-		tsk->tss.error_code = mode;
-		tsk->tss.trap_no = 14;
-//console_loglevel = 9;
-		printk ("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n",
-			tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode);
-//#ifdef DEBUG
-		show_regs (regs);
-		c_backtrace (regs->ARM_fp, 0);
-//#endif
-		force_sig(SIGSEGV, tsk);
-//while (1);
-		goto out;
-	}
-
-	/* Are we prepared to handle this kernel fault?  */
-	if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) {
-		printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n",
-			tsk->comm, regs->ARM_pc, addr, fixup);
-		regs->ARM_pc = fixup;
-		goto out;
-	}
-
-
-	kernel_page_fault (addr, mode, regs, tsk, mm);
-out:
-	unlock_kernel();
-}
-
 /*
  * Handle a data abort.  Note that we have to handle a range of addresses
  * on ARM2/3 for ldm.  If both pages are zero-mapped, then we have to force
- * a copy-on-write
+ * a copy-on-write.  However, on the second page, we always force COW.
  */
 asmlinkage void
-do_DataAbort (unsigned long min_addr, unsigned long max_addr, int mode, struct pt_regs *regs)
+do_DataAbort(unsigned long min_addr, unsigned long max_addr, int mode, struct pt_regs *regs)
 {
-	handle_dataabort (min_addr, mode, regs);
+	do_page_fault(min_addr, mode, regs);
 
 	if ((min_addr ^ max_addr) >> PAGE_SHIFT)
-		handle_dataabort (max_addr, mode | FAULT_CODE_FORCECOW, regs);
+		do_page_fault(max_addr, mode | FAULT_CODE_FORCECOW, regs);
 }
 
 asmlinkage int
-do_PrefetchAbort (unsigned long addr, int mode, struct pt_regs *regs)
+do_PrefetchAbort(unsigned long addr, struct pt_regs *regs)
 {
 #if 0
 	if (the memc mapping for this page exists - can check now...) {
@@ -210,6 +101,6 @@
 		return 0;
 	}
 #endif
-	handle_dataabort (addr, mode, regs);
+	do_page_fault(addr, FAULT_CODE_USER|FAULT_CODE_PREFETCH, regs);
 	return 1;
 }
diff -u --recursive --new-file v2.2.7/linux/arch/arm/mm/fault-armv.c linux/arch/arm/mm/fault-armv.c
--- v2.2.7/linux/arch/arm/mm/fault-armv.c	Tue Dec 22 14:16:53 1998
+++ linux/arch/arm/mm/fault-armv.c	Sat May  8 11:06:56 1999
@@ -1,10 +1,11 @@
 /*
- *  linux/arch/arm/mm/fault.c
+ *  linux/arch/arm/mm/fault-armv.c
  *
  *  Copyright (C) 1995  Linus Torvalds
- *  Modifications for ARM processor (c) 1995, 1996 Russell King
+ *  Modifications for ARM processor (c) 1995-1999 Russell King
  */
 
+#include <linux/config.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -14,43 +15,37 @@
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
+#include <asm/unaligned.h>
 
 #define FAULT_CODE_READ		0x02
 #define FAULT_CODE_USER		0x01
 
-struct pgtable_cache_struct quicklists;
+#define DO_COW(m)		(!((m) & FAULT_CODE_READ))
+#define READ_FAULT(m)		((m) & FAULT_CODE_READ)
 
-void __bad_pmd(pmd_t *pmd)
-{
-	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-	set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
-}
-
-void __bad_pmd_kernel(pmd_t *pmd)
-{
-	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
-	set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
-}
+#include "fault-common.c"
 
 pgd_t *get_pgd_slow(void)
 {
 	/*
 	 * need to get a 16k page for level 1
 	 */
-	pgd_t *pgd = (pgd_t *) __get_free_pages(GFP_KERNEL,2);
+	pgd_t *pgd = (pgd_t *)__get_free_pages(GFP_KERNEL,2);
 	pgd_t *init;
-	
+
 	if (pgd) {
 		init = pgd_offset(&init_mm, 0);
-		memzero ((void *)pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
-		memcpy (pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+		memzero(pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR);
+		memcpy(pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
 			(PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR);
+		clean_cache_area(pgd, PTRS_PER_PGD * BYTES_PER_PTR);
 	}
 	return pgd;
 }
@@ -59,17 +54,19 @@
 {
 	pte_t *pte;
 
-	pte = (pte_t *) get_small_page(GFP_KERNEL);
+	pte = (pte_t *)get_page_2k(GFP_KERNEL);
 	if (pmd_none(*pmd)) {
 		if (pte) {
-			memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR);
+			memzero(pte, 2 * PTRS_PER_PTE * BYTES_PER_PTR);
+			clean_cache_area(pte, PTRS_PER_PTE * BYTES_PER_PTR);
+			pte += PTRS_PER_PTE;
 			set_pmd(pmd, mk_user_pmd(pte));
 			return pte + offset;
 		}
 		set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
 		return NULL;
 	}
-	free_small_page ((unsigned long) pte);
+	free_page_2k((unsigned long)pte);
 	if (pmd_bad(*pmd)) {
 		__bad_pmd(pmd);
 		return NULL;
@@ -81,17 +78,19 @@
 {
 	pte_t *pte;
 
-	pte = (pte_t *) get_small_page(GFP_KERNEL);
+	pte = (pte_t *)get_page_2k(GFP_KERNEL);
 	if (pmd_none(*pmd)) {
 		if (pte) {
-			memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR);
+			memzero(pte, 2 * PTRS_PER_PTE * BYTES_PER_PTR);
+			clean_cache_area(pte, PTRS_PER_PTE * BYTES_PER_PTR);
+			pte += PTRS_PER_PTE;
 			set_pmd(pmd, mk_kernel_pmd(pte));
 			return pte + offset;
 		}
 		set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
 		return NULL;
 	}
-	free_small_page ((unsigned long) pte);
+	free_page_2k((unsigned long)pte);
 	if (pmd_bad(*pmd)) {
 		__bad_pmd_kernel(pmd);
 		return NULL;
@@ -99,10 +98,8 @@
 	return (pte_t *) pmd_page(*pmd) + offset;
 }
 
-extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret);
-
 #ifdef DEBUG
-static int sp_valid (unsigned long *sp)
+static int sp_valid(unsigned long *sp)
 {
 	unsigned long addr = (unsigned long) sp;
 
@@ -114,187 +111,371 @@
 }
 #endif
 
-static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs,
-			       struct task_struct *tsk, struct mm_struct *mm)
+#ifdef CONFIG_ALIGNMENT_TRAP
+/*
+ * 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998
+ * /proc/sys/debug/alignment, modified and integrated into
+ * Linux 2.1 by Russell King
+ *
+ * NOTE!!! This is not portable onto the ARM6/ARM7 processors yet.  Also,
+ * it seems to give a severe performance impact (1 abort/ms - NW runs at
+ * ARM6 speeds) with GCC 2.7.2.2 - needs checking with a later GCC/EGCS.
+ *
+ * IMHO, I don't think that the trap handler is advantageous on ARM6,7
+ * processors (they'll run like an ARM3).  We'll see.
+ */
+#define CODING_BITS(i)	(i & 0x0e000000)
+
+#define LDST_I_BIT(i)	(i & (1 << 26))		/* Immediate constant	*/
+#define LDST_P_BIT(i)	(i & (1 << 24))		/* Preindex		*/
+#define LDST_U_BIT(i)	(i & (1 << 23))		/* Add offset		*/
+#define LDST_W_BIT(i)	(i & (1 << 21))		/* Writeback		*/
+#define LDST_L_BIT(i)	(i & (1 << 20))		/* Load			*/
+
+#define LDSTH_I_BIT(i)	(i & (1 << 22))		/* half-word immed	*/
+#define LDM_S_BIT(i)	(i & (1 << 22))		/* write CPSR from SPSR	*/
+
+#define RN_BITS(i)	((i >> 16) & 15)	/* Rn			*/
+#define RD_BITS(i)	((i >> 12) & 15)	/* Rd			*/
+#define RM_BITS(i)	(i & 15)		/* Rm			*/
+
+#define REGMASK_BITS(i)	(i & 0xffff)
+#define OFFSET_BITS(i)	(i & 0x0fff)
+
+#define IS_SHIFT(i)	(i & 0x0ff0)
+#define SHIFT_BITS(i)	((i >> 7) & 0x1f)
+#define SHIFT_TYPE(i)	(i & 0x60)
+#define SHIFT_LSL	0x00
+#define SHIFT_LSR	0x20
+#define SHIFT_ASR	0x40
+#define SHIFT_RORRRX	0x60
+
+static unsigned long ai_user;
+static unsigned long ai_sys;
+static unsigned long ai_skipped;
+static unsigned long ai_half;
+static unsigned long ai_word;
+static unsigned long ai_multi;
+
+static int proc_alignment_read(char *page, char **start, off_t off,
+			       int count, int *eof, void *data)
 {
-	/*
-	 * Oops. The kernel tried to access some bad page. We'll have to
-	 * terminate things with extreme prejudice.
-	 */
-	pgd_t *pgd;
-	if (addr < PAGE_SIZE)
-	    printk (KERN_ALERT "Unable to handle kernel NULL pointer dereference");
-	else
-	    printk (KERN_ALERT "Unable to handle kernel paging request");
-	printk (" at virtual address %08lx\n", addr);
-	printk (KERN_ALERT "current->tss.memmap = %08lX\n", tsk->tss.memmap);
-	pgd = pgd_offset (mm, addr);
-	printk (KERN_ALERT "*pgd = %08lx", pgd_val (*pgd));
-	if (!pgd_none (*pgd)) {
-		pmd_t *pmd;
-		pmd = pmd_offset (pgd, addr);
-		printk (", *pmd = %08lx", pmd_val (*pmd));
-		if (!pmd_none (*pmd))
-			printk (", *pte = %08lx", pte_val (*pte_offset (pmd, addr)));
-	}
-	printk ("\n");
-	die_if_kernel ("Oops", regs, mode, SIGKILL);
-	do_exit (SIGKILL);
+	char *p = page;
+	int len;
+
+	p += sprintf(p, "User:\t\t%li\n", ai_user);
+	p += sprintf(p, "System:\t\t%li\n", ai_sys);
+	p += sprintf(p, "Skipped:\t%li\n", ai_skipped);
+	p += sprintf(p, "Half:\t\t%li\n", ai_half);
+	p += sprintf(p, "Word:\t\t%li\n", ai_word);
+	p += sprintf(p, "Multi:\t\t%li\n", ai_multi);
+
+	len = (p - page) - off;
+	if (len < 0)
+		len = 0;
+
+	*eof = (len <= count) ? 1 : 0;
+	*start = page + off;
+
+	return len;
 }
 
-static void page_fault (unsigned long addr, int mode, struct pt_regs *regs)
+/*
+ * This needs to be done after sysctl_init, otherwise sys/
+ * will be overwritten.
+ */
+void __init alignment_init(void)
 {
-	struct task_struct *tsk;
-	struct mm_struct *mm;
-	struct vm_area_struct *vma;
-	unsigned long fixup;
-
-	lock_kernel();
-	tsk = current;
-	mm = tsk->mm;
-
-	down(&mm->mmap_sem);
-	vma = find_vma (mm, addr);
-	if (!vma)
-		goto bad_area;
-	if (vma->vm_start <= addr)
-		goto good_area;
-	if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack (vma, addr))
-		goto bad_area;
+	struct proc_dir_entry *e;
 
-	/*
-	 * Ok, we have a good vm_area for this memory access, so
-	 * we can handle it..
-	 */
-good_area:
-	if (mode & FAULT_CODE_READ) { /* read? */
-		if (!(vma->vm_flags & (VM_READ|VM_EXEC)))
-			goto bad_area;
-	} else {
-		if (!(vma->vm_flags & VM_WRITE))
-			goto bad_area;
+	e = create_proc_entry("sys/debug/alignment", S_IFREG | S_IRUGO, NULL);
+
+	if (e)
+		e->read_proc = proc_alignment_read;
+}
+
+static int
+do_alignment_exception(struct pt_regs *regs)
+{
+	unsigned int instr, rd, rn, correction, nr_regs, regbits;
+	unsigned long eaddr;
+	union { unsigned long un; signed long sn; } offset;
+
+	if (user_mode(regs)) {
+		set_cr(cr_no_alignment);
+		ai_user += 1;
+		return 0;
 	}
-	handle_mm_fault (tsk, vma, addr & PAGE_MASK, !(mode & FAULT_CODE_READ));
-	up(&mm->mmap_sem);
-	goto out;
 
-	/*
-	 * Something tried to access memory that isn't in our memory map..
-	 * Fix it, but check if it's kernel or user first..
-	 */
-bad_area:
-	up(&mm->mmap_sem);
-	if (mode & FAULT_CODE_USER) {
-		tsk->tss.error_code = mode;
-		tsk->tss.trap_no = 14;
-		printk ("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n",
-			tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode);
-#ifdef DEBUG
-		{
-			unsigned int i, j;
-			unsigned long *sp = (unsigned long *) (regs->ARM_sp - 128);
-			for (j = 0; j < 20 && sp_valid (sp); j++) {
-				printk ("%p: ", sp);
-				for (i = 0; i < 8 && sp_valid (sp); i += 1, sp++)
-					printk ("%08lx ", *sp);
-				printk ("\n");
+	ai_sys += 1;
+
+	instr = *(unsigned long *)instruction_pointer(regs);
+	correction = 4; /* sometimes 8 on ARMv3 */
+	regs->ARM_pc += correction + 4;
+
+	rd = RD_BITS(instr);
+	rn = RN_BITS(instr);
+	eaddr = regs->uregs[rn];
+
+	switch(CODING_BITS(instr)) {
+	case 0x00000000:
+		if ((instr & 0x0ff00ff0) == 0x01000090) {
+			ai_skipped += 1;
+			printk(KERN_ERR "Unaligned trap: not handling swp instruction\n");
+			return 1;
+		}
+
+		if (((instr & 0x0e000090) == 0x00000090) && (instr & 0x60) != 0) {
+			ai_half += 1;
+			if (LDSTH_I_BIT(instr))
+				offset.un = (instr & 0xf00) >> 4 | (instr & 15);
+			else
+				offset.un = regs->uregs[RM_BITS(instr)];
+
+			if (LDST_P_BIT(instr)) {
+				if (LDST_U_BIT(instr))
+					eaddr += offset.un;
+				else
+					eaddr -= offset.un;
 			}
+
+			if (LDST_L_BIT(instr))
+				regs->uregs[rd] = get_unaligned((unsigned short *)eaddr);
+			else
+				put_unaligned(regs->uregs[rd], (unsigned short *)eaddr);
+
+			/* signed half-word? */
+			if (instr & 0x40)
+				regs->uregs[rd] = (long)((short) regs->uregs[rd]);
+
+			if (!LDST_P_BIT(instr)) {
+				if (LDST_U_BIT(instr))
+					eaddr += offset.un;
+				else
+					eaddr -= offset.un;
+				regs->uregs[rn] = eaddr;
+			} else if (LDST_W_BIT(instr))
+				regs->uregs[rn] = eaddr;
+			break;
 		}
-		show_regs (regs);
-		c_backtrace (regs->ARM_fp, regs->ARM_cpsr);
-#endif
-		force_sig(SIGSEGV, tsk);
-		goto out;
-	}
 
-	/* Are we prepared to handle this kernel fault?  */
-	if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) {
-		printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n",
-			tsk->comm, regs->ARM_pc, addr, fixup);
-		regs->ARM_pc = fixup;
-		goto out;
+	default:
+		ai_skipped += 1;
+		panic("Alignment trap: not handling instruction %08X at %08lX",
+				instr, regs->ARM_pc - correction - 4);
+		break;
+
+	case 0x04000000:
+		offset.un = OFFSET_BITS(instr);
+		goto ldr_str;
+
+	case 0x06000000:
+		offset.un = regs->uregs[RM_BITS(instr)];
+
+		if (IS_SHIFT(instr)) {
+			unsigned int shiftval = SHIFT_BITS(instr);
+
+			switch(SHIFT_TYPE(instr)) {
+			case SHIFT_LSL:
+				offset.un <<= shiftval;
+				break;
+
+			case SHIFT_LSR:
+				offset.un >>= shiftval;
+				break;
+
+			case SHIFT_ASR:
+				offset.sn >>= shiftval;
+				break;
+
+			case SHIFT_RORRRX:
+				if (shiftval == 0) {
+					offset.un >>= 1;
+					if (regs->ARM_cpsr & CC_C_BIT)
+						offset.un |= 1 << 31;
+				} else
+					offset.un = offset.un >> shiftval |
+							  offset.un << (32 - shiftval);
+				break;
+			}
+		}
+
+	ldr_str:
+		ai_word += 1;
+		if (LDST_P_BIT(instr)) {
+			if (LDST_U_BIT(instr))
+				eaddr += offset.un;
+			else
+				eaddr -= offset.un;
+		} else {
+			if (LDST_W_BIT(instr)) {
+				printk(KERN_ERR "Not handling ldrt/strt correctly\n");
+				return 1;
+			}
+		}
+
+		if (LDST_L_BIT(instr)) {
+			regs->uregs[rd] = get_unaligned((unsigned long *)eaddr);
+			if (rd == 15)
+				correction = 0;
+		} else
+			put_unaligned(regs->uregs[rd], (unsigned long *)eaddr);
+
+		if (!LDST_P_BIT(instr)) {
+			if (LDST_U_BIT(instr))
+				eaddr += offset.un;
+			else
+				eaddr -= offset.un;
+
+			regs->uregs[rn] = eaddr;
+		} else if (LDST_W_BIT(instr))
+			regs->uregs[rn] = eaddr;
+		break;
+
+	case 0x08000000:
+		if (LDM_S_BIT(instr))
+			panic("Alignment trap: not handling LDM with s-bit\n");
+		ai_multi += 1;
+
+		for (regbits = REGMASK_BITS(instr), nr_regs = 0; regbits; regbits >>= 1)
+			nr_regs += 4;
+
+		if  (!LDST_U_BIT(instr))
+			eaddr -= nr_regs;
+
+		if ((LDST_U_BIT(instr) == 0 && LDST_P_BIT(instr) == 0) ||
+		    (LDST_U_BIT(instr)      && LDST_P_BIT(instr)))
+			eaddr += 4;
+
+		for (regbits = REGMASK_BITS(instr), rd = 0; regbits; regbits >>= 1, rd += 1)
+			if (regbits & 1) {
+				if (LDST_L_BIT(instr)) {
+					regs->uregs[rd] = get_unaligned((unsigned long *)eaddr);
+					if (rd == 15)
+						correction = 0;
+				} else
+					put_unaligned(regs->uregs[rd], (unsigned long *)eaddr);
+				eaddr += 4;
+			}
+
+		if (LDST_W_BIT(instr)) {
+			if (LDST_P_BIT(instr) && !LDST_U_BIT(instr))
+				eaddr -= nr_regs;
+			else if (LDST_P_BIT(instr))
+				eaddr -= 4;
+			else if (!LDST_U_BIT(instr))
+				eaddr -= 4 + nr_regs;
+			regs->uregs[rn] = eaddr;
+		}
+		break;
 	}
 
-	kernel_page_fault (addr, mode, regs, tsk, mm);
-out:
-	unlock_kernel();
+	regs->ARM_pc -= correction;
+
+	return 0;
 }
 
-/*
- * Handle a data abort.  Note that we have to handle a range of addresses
- * on ARM2/3 for ldm.  If both pages are zero-mapped, then we have to force
- * a copy-on-write
- */
+#endif
+
 asmlinkage void
-do_DataAbort (unsigned long addr, int fsr, int error_code, struct pt_regs *regs)
+do_DataAbort(unsigned long addr, int fsr, int error_code, struct pt_regs *regs)
 {
 	if (user_mode(regs))
 		error_code |= FAULT_CODE_USER;
+
 #define DIE(signr,nam)\
 		force_sig(signr, current);\
-		die_if_kernel(nam, regs, fsr, signr);\
-		break;
+		die(nam, regs, fsr);\
+		do_exit(signr);\
+		break
 
 	switch (fsr & 15) {
-	case 2:
-		DIE(SIGKILL, "Terminal exception")
+	/*
+	 *  0 - vector exception
+	 */
 	case 0:
-		DIE(SIGSEGV, "Vector exception")
+		force_sig(SIGSEGV, current);
+		if (!user_mode(regs)) {
+			die("vector exception", regs, fsr);
+			do_exit(SIGSEGV);
+		}
+		break;
+
+	/*
+	 * 15 - permission fault on page
+	 *  5 - page-table entry descriptor fault
+	 *  7 - first-level descriptor fault
+	 */
+	case 15: case 5: case 7:
+		do_page_fault(addr, error_code, regs);
+		break;
+
+	/*
+	 * 13 - permission fault on section
+	 */
+	case 13:
+		force_sig(SIGSEGV, current);
+		if (!user_mode(regs)) {
+			die("section permission fault", regs, fsr);
+			do_exit(SIGSEGV);
+		} else {
+#ifdef CONFIG_DEBUG_USER
+			printk("%s: permission fault on section, "
+			       "address=0x%08lx, code %d\n",
+			       current->comm, addr, error_code);
+#ifdef DEBUG
+			{
+				unsigned int i, j;
+				unsigned long *sp;
+
+				sp = (unsigned long *) (regs->ARM_sp - 128);
+				for (j = 0; j < 20 && sp_valid(sp); j++) {
+					printk("%p: ", sp);
+					for (i = 0; i < 8 && sp_valid(sp); i += 1, sp++)
+						printk("%08lx ", *sp);
+					printk("\n");
+				}
+				show_regs(regs);
+				c_backtrace(regs->ARM_fp, regs->ARM_cpsr);
+			}
+#endif
+#endif
+		}
+		break;
+
 	case 1:
 	case 3:
-		DIE(SIGBUS, "Alignment exception")
+#ifdef CONFIG_ALIGNMENT_TRAP
+		if (!do_alignment_exception(regs))
+			break;
+#endif
+		/*
+		 * this should never happen
+		 */
+		DIE(SIGBUS, "Alignment exception");
+		break;
+
+	case 2:
+		DIE(SIGKILL, "Terminal exception");
 	case 12:
 	case 14:
-		DIE(SIGBUS, "External abort on translation")
+		DIE(SIGBUS, "External abort on translation");
 	case 9:
 	case 11:
-		DIE(SIGSEGV, "Domain fault")
-	case 13:/* permission fault on section */
-#ifdef DEBUG
-		{
-			unsigned int i, j;
-			unsigned long *sp;
-
-			printk ("%s: section permission fault (bad address=0x%08lx, code %d)\n",
-				current->comm, addr, error_code);
-			sp = (unsigned long *) (regs->ARM_sp - 128);
-			for (j = 0; j < 20 && sp_valid (sp); j++) {
-				printk ("%p: ", sp);
-				for (i = 0; i < 8 && sp_valid (sp); i += 1, sp++)
-					printk ("%08lx ", *sp);
-				printk ("\n");
-			}
-			show_regs (regs);
-			c_backtrace(regs->ARM_fp, regs->ARM_cpsr);
-		}
-#endif
-		DIE(SIGSEGV, "Permission fault")
+		DIE(SIGSEGV, "Domain fault");
 
-	case 15:/* permission fault on page */
-	case 5:	/* page-table entry descriptor fault */
-	case 7:	/* first-level descriptor fault */
-		page_fault (addr, error_code, regs);
-		break;
 	case 4:
 	case 6:
-		DIE(SIGBUS, "External abort on linefetch")
+		DIE(SIGBUS, "External abort on linefetch");
 	case 8:
 	case 10:
-		DIE(SIGBUS, "External abort on non-linefetch")
+		DIE(SIGBUS, "External abort on non-linefetch");
 	}
 }
 
 asmlinkage int
-do_PrefetchAbort (unsigned long addr, struct pt_regs *regs)
+do_PrefetchAbort(unsigned long addr, struct pt_regs *regs)
 {
-#if 0
-	/* does this still apply ? */
-	if (the memc mapping for this page exists - can check now...) {
-		printk ("Page in, but got abort (undefined instruction?)\n");
-		return 0;
-	}
-#endif
-	page_fault (addr, FAULT_CODE_USER|FAULT_CODE_READ, regs);
+	do_page_fault(addr, FAULT_CODE_USER|FAULT_CODE_READ, regs);
 	return 1;
 }
-
diff -u --recursive --new-file v2.2.7/linux/arch/arm/mm/fault-common.c linux/arch/arm/mm/fault-common.c
--- v2.2.7/linux/arch/arm/mm/fault-common.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mm/fault-common.c	Sat May  8 11:06:56 1999
@@ -0,0 +1,188 @@
+/*
+ *  linux/arch/arm/mm/fault-common.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Modifications for ARM processor (c) 1995-1999 Russell King
+ */
+#include <linux/config.h>
+
+extern void die(char *msg, struct pt_regs *regs, unsigned int err);
+
+void __bad_pmd(pmd_t *pmd)
+{
+	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+#ifdef CONFIG_DEBUG_ERRORS
+	__backtrace();
+#endif
+	set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE));
+}
+
+void __bad_pmd_kernel(pmd_t *pmd)
+{
+	printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
+#ifdef CONFIG_DEBUG_ERRORS
+	__backtrace();
+#endif
+	set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE));
+}
+
+static void
+kernel_page_fault(unsigned long addr, int mode, struct pt_regs *regs,
+		  struct task_struct *tsk, struct mm_struct *mm)
+{
+	char *reason;
+	/*
+	 * Oops. The kernel tried to access some bad page. We'll have to
+	 * terminate things with extreme prejudice.
+	 */
+	pgd_t *pgd;
+
+	if (addr < PAGE_SIZE)
+		reason = "NULL pointer dereference";
+	else
+		reason = "paging request";
+
+	printk(KERN_ALERT "Unable to handle kernel %s at virtual address %08lx\n",
+		reason, addr);
+	printk(KERN_ALERT "memmap = %08lX, pgd = %p\n", tsk->tss.memmap, mm->pgd);
+	pgd = pgd_offset(mm, addr);
+	printk(KERN_ALERT "*pgd = %08lx", pgd_val(*pgd));
+
+	do {
+		pmd_t *pmd;
+		pte_t *pte;
+
+		if (pgd_none(*pgd))
+			break;
+
+		if (pgd_bad(*pgd)) {
+			printk("(bad)\n");
+			break;
+		}
+
+		pmd = pmd_offset(pgd, addr);
+		printk(", *pmd = %08lx", pmd_val(*pmd));
+
+		if (pmd_none(*pmd))
+			break;
+
+		if (pmd_bad(*pmd)) {
+			printk("(bad)\n");
+			break;
+		}
+
+		pte = pte_offset(pmd, addr);
+		printk(", *pte = %08lx", pte_val(*pte));
+		printk(", *ppte = %08lx", pte_val(pte[-PTRS_PER_PTE]));
+	} while(0);
+
+	printk("\n");
+	die("Oops", regs, mode);
+
+	do_exit(SIGKILL);
+}
+
+static void do_page_fault(unsigned long addr, int mode, struct pt_regs *regs)
+{
+	struct task_struct *tsk;
+	struct mm_struct *mm;
+	struct vm_area_struct *vma;
+	unsigned long fixup;
+
+	tsk = current;
+	mm  = tsk->mm;
+
+	/*
+	 * If we're in an interrupt or have no user
+	 * context, we must not take the fault..
+	 */
+	if (in_interrupt() || mm == &init_mm)
+		goto no_context;
+
+	down(&mm->mmap_sem);
+	vma = find_vma(mm, addr);
+	if (!vma)
+		goto bad_area;
+	if (vma->vm_start <= addr)
+		goto good_area;
+	if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack(vma, addr))
+		goto bad_area;
+
+	/*
+	 * Ok, we have a good vm_area for this memory access, so
+	 * we can handle it..
+	 */
+good_area:
+	if (READ_FAULT(mode)) { /* read? */
+		if (!(vma->vm_flags & (VM_READ|VM_EXEC)))
+			goto bad_area;
+	} else {
+		if (!(vma->vm_flags & VM_WRITE))
+			goto bad_area;
+	}
+
+	/*
+	 * If for any reason at all we couldn't handle the fault,
+	 * make sure we exit gracefully rather than endlessly redo
+	 * the fault.
+	 */
+	if (!handle_mm_fault(tsk, vma, addr & PAGE_MASK, DO_COW(mode)))
+		goto do_sigbus;
+
+	up(&mm->mmap_sem);
+	return;
+
+	/*
+	 * Something tried to access memory that isn't in our memory map..
+	 * Fix it, but check if it's kernel or user first..
+	 */
+bad_area:
+	up(&mm->mmap_sem);
+
+	/* User mode accesses just cause a SIGSEGV */
+	if (mode & FAULT_CODE_USER) {
+		tsk->tss.error_code = mode;
+		tsk->tss.trap_no = 14;
+#ifdef CONFIG_DEBUG_USER
+		printk("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n",
+			tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode);
+#endif
+		force_sig(SIGSEGV, tsk);
+		return;
+	}
+
+no_context:
+	/* Are we prepared to handle this kernel fault?  */
+	if ((fixup = search_exception_table(instruction_pointer(regs))) != 0) {
+#ifdef DEBUG
+		printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n",
+			tsk->comm, regs->ARM_pc, addr, fixup);
+#endif
+		regs->ARM_pc = fixup;
+		return;
+	}
+
+	kernel_page_fault(addr, mode, regs, tsk, mm);
+	return;
+
+do_sigbus:
+	/*
+	 * We ran out of memory, or some other thing happened to us that made
+	 * us unable to handle the page fault gracefully.
+	 */
+	up(&mm->mmap_sem);
+
+	/*
+	 * Send a sigbus, regardless of whether we were in kernel
+	 * or user mode.
+	 */
+	tsk->tss.error_code = mode;
+	tsk->tss.trap_no = 14;
+	force_sig(SIGBUS, tsk);
+
+	/* Kernel mode? Handle exceptions or die */
+	if (!(mode & FAULT_CODE_USER))
+		goto no_context;
+}
+
+
diff -u --recursive --new-file v2.2.7/linux/arch/arm/mm/init.c linux/arch/arm/mm/init.c
--- v2.2.7/linux/arch/arm/mm/init.c	Tue Dec 22 14:16:53 1998
+++ linux/arch/arm/mm/init.c	Sat May  8 11:06:56 1999
@@ -29,6 +29,9 @@
 #include <asm/proc/mm-init.h>
 
 pgd_t swapper_pg_dir[PTRS_PER_PGD];
+#ifndef CONFIG_NO_PGT_CACHE
+struct pgtable_cache_struct quicklists;
+#endif
 
 extern char _etext, _stext, _edata, __bss_start, _end;
 extern char __init_begin, __init_end;
@@ -36,6 +39,7 @@
 int do_check_pgt_cache(int low, int high)
 {
 	int freed = 0;
+#ifndef CONFIG_NO_PGT_CACHE
 	if(pgtable_cache_size > high) {
 		do {
 			if(pgd_quicklist)
@@ -46,6 +50,7 @@
 				free_pte_slow(get_pte_fast()), freed++;
 		} while(pgtable_cache_size > low);
 	}
+#endif
 	return freed;
 }
 
@@ -63,17 +68,18 @@
  * data and COW.
  */
 #if PTRS_PER_PTE != 1
-unsigned long *empty_bad_page_table;
+pte_t *empty_bad_page_table;
 
 pte_t *__bad_pagetable(void)
 {
-	int i;
 	pte_t bad_page;
+	int i;
 
 	bad_page = BAD_PAGE;
 	for (i = 0; i < PTRS_PER_PTE; i++)
-		empty_bad_page_table[i] = (unsigned long)pte_val(bad_page);
-	return (pte_t *) empty_bad_page_table;
+		set_pte(empty_bad_page_table + i, bad_page);
+
+	return empty_bad_page_table;
 }
 #endif
 
@@ -128,8 +134,11 @@
 	empty_bad_page = (unsigned long *)start_mem;
 	start_mem += PAGE_SIZE;
 #if PTRS_PER_PTE != 1
-	empty_bad_page_table = (unsigned long *)start_mem;
-	start_mem += PTRS_PER_PTE * sizeof (void *);
+#ifdef CONFIG_CPU_32
+	start_mem += PTRS_PER_PTE * BYTES_PER_PTR;
+#endif
+	empty_bad_page_table = (pte_t *)start_mem;
+	start_mem += PTRS_PER_PTE * BYTES_PER_PTR;
 #endif
 	memzero (empty_zero_page, PAGE_SIZE);
 	start_mem = setup_pagetables (start_mem, end_mem);
@@ -137,6 +146,9 @@
 	flush_tlb_all();
 	update_memc_all();
 
+	end_mem &= PAGE_MASK;
+	high_memory = (void *)end_mem;
+
 	return free_area_init(start_mem, end_mem);
 }
 
@@ -161,19 +173,18 @@
 	/* mark usable pages in the mem_map[] */
 	mark_usable_memory_areas(&start_mem, end_mem);
 
+#define BETWEEN(w,min,max) ((w) >= (unsigned long)(min) && \
+			    (w) < (unsigned long)(max))
+
 	for (tmp = PAGE_OFFSET; tmp < end_mem ; tmp += PAGE_SIZE) {
 		if (PageReserved(mem_map+MAP_NR(tmp))) {
-			if (tmp >= KERNTOPHYS(_stext) &&
-			    tmp < KERNTOPHYS(_edata)) {
-				if (tmp < KERNTOPHYS(_etext))
-					codepages++;
-				else
-					datapages++;
-			} else if (tmp >= KERNTOPHYS(__init_begin)
-				   && tmp < KERNTOPHYS(__init_end))
+			if (BETWEEN(tmp, &__init_begin, &__init_end))
 				initpages++;
-			else if (tmp >= KERNTOPHYS(__bss_start)
-				 && tmp < (unsigned long) start_mem)
+			else if (BETWEEN(tmp, &_stext, &_etext))
+				codepages++;
+			else if (BETWEEN(tmp, &_etext, &_edata))
+				datapages++;
+			else if (BETWEEN(tmp, &__bss_start, start_mem))
 				datapages++;
 			else
 				reservedpages++;
@@ -181,13 +192,16 @@
 		}
 		atomic_set(&mem_map[MAP_NR(tmp)].count, 1);
 #ifdef CONFIG_BLK_DEV_INITRD
-		if (!initrd_start || (tmp < initrd_start || tmp >= initrd_end))
+		if (!initrd_start || !BETWEEN(tmp, initrd_start, initrd_end))
 #endif
 			free_page(tmp);
 	}
-	printk ("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n",
+
+#undef BETWEEN
+
+	printk ("Memory: %luk/%luM available (%dk code, %dk reserved, %dk data, %dk init)\n",
 		 (unsigned long) nr_free_pages << (PAGE_SHIFT-10),
-		 max_mapnr << (PAGE_SHIFT-10),
+		 max_mapnr >> (20 - PAGE_SHIFT),
 		 codepages << (PAGE_SHIFT-10),
 		 reservedpages << (PAGE_SHIFT-10),
 		 datapages << (PAGE_SHIFT-10),
@@ -203,17 +217,45 @@
 #endif
 }
 
-void free_initmem (void)
+static void free_area(unsigned long addr, unsigned long end, char *s)
 {
-	unsigned long addr;
+	unsigned int size = (end - addr) >> 10;
 
-	addr = (unsigned long)(&__init_begin);
-	for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+	for (; addr < end; addr += PAGE_SIZE) {
 		mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
 		atomic_set(&mem_map[MAP_NR(addr)].count, 1);
 		free_page(addr);
 	}
-	printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
+
+	if (size)
+		printk(" %dk %s", size, s);
+}
+
+void free_initmem (void)
+{
+	printk("Freeing unused kernel memory:");
+
+	free_area((unsigned long)(&__init_begin),
+		  (unsigned long)(&__init_end),
+		  "init");
+
+#ifdef CONFIG_FOOTBRIDGE
+	{
+	extern int __netwinder_begin, __netwinder_end, __ebsa285_begin, __ebsa285_end;
+
+	if (!machine_is_netwinder())
+		free_area((unsigned long)(&__netwinder_begin),
+			  (unsigned long)(&__netwinder_end),
+			  "netwinder");
+
+	if (!machine_is_ebsa285() && !machine_is_cats())
+		free_area((unsigned long)(&__ebsa285_begin),
+			  (unsigned long)(&__ebsa285_end),
+			  "ebsa285/cats");
+	}
+#endif
+
+	printk("\n");
 }
 
 void si_meminfo(struct sysinfo *val)
diff -u --recursive --new-file v2.2.7/linux/arch/arm/mm/ioremap.c linux/arch/arm/mm/ioremap.c
--- v2.2.7/linux/arch/arm/mm/ioremap.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mm/ioremap.c	Sat May  8 11:06:56 1999
@@ -0,0 +1,149 @@
+/*
+ * arch/arm/mm/ioremap.c
+ *
+ * Re-map IO memory to kernel address space so that we can access it.
+ *
+ * (C) Copyright 1995 1996 Linus Torvalds
+ *
+ * Hacked for ARM by Phil Blundell <philb@gnu.org>
+ * Hacked to allow all architectures to build, and various cleanups
+ * by Russell King
+ */
+
+/*
+ * This allows a driver to remap an arbitrary region of bus memory into
+ * virtual space.  One should *only* use readl, writel, memcpy_toio and
+ * so on with such remapped areas.
+ *
+ * Because the ARM only has a 32-bit address space we can't address the
+ * whole of the (physical) PCI space at once.  PCI huge-mode addressing
+ * allows us to circumvent this restriction by splitting PCI space into
+ * two 2GB chunks and mapping only one at a time into processor memory.
+ * We use MMU protection domains to trap any attempt to access the bank
+ * that is not currently mapped.  (This isn't fully implemented yet.)
+ *
+ * DC21285 currently has a bug in that the PCI address extension
+ * register affects the address of any writes waiting in the outbound
+ * FIFO.  Unfortunately, it is not possible to tell the DC21285 to
+ * flush this - flushing the area causes the bus to lock.
+ */
+
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+
+static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+	unsigned long phys_addr, pgprot_t pgprot)
+{
+	unsigned long end;
+
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end > PMD_SIZE)
+		end = PMD_SIZE;
+	do {
+		if (!pte_none(*pte))
+			printk("remap_area_pte: page already exists\n");
+		set_pte(pte, mk_pte_phys(phys_addr, pgprot));
+		address += PAGE_SIZE;
+		phys_addr += PAGE_SIZE;
+		pte++;
+	} while (address < end);
+}
+
+static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
+	unsigned long phys_addr, unsigned long flags)
+{
+	unsigned long end;
+	pgprot_t pgprot;
+
+	address &= ~PGDIR_MASK;
+	end = address + size;
+
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+
+	phys_addr -= address;
+	pgprot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE | flags);
+	do {
+		pte_t * pte = pte_alloc_kernel(pmd, address);
+		if (!pte)
+			return -ENOMEM;
+		remap_area_pte(pte, address, end - address, address + phys_addr, pgprot);
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	} while (address < end);
+	return 0;
+}
+
+static int remap_area_pages(unsigned long address, unsigned long phys_addr,
+				 unsigned long size, unsigned long flags)
+{
+	pgd_t * dir;
+	unsigned long end = address + size;
+
+	phys_addr -= address;
+	dir = pgd_offset(&init_mm, address);
+	flush_cache_all();
+	while (address < end) {
+		pmd_t *pmd = pmd_alloc_kernel(dir, address);
+		if (!pmd)
+			return -ENOMEM;
+		if (remap_area_pmd(pmd, address, end - address,
+					 phys_addr + address, flags))
+			return -ENOMEM;
+		set_pgdir(address, *dir);
+		address = (address + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	}
+	flush_tlb_all();
+	return 0;
+}
+
+/*
+ * Remap an arbitrary physical address space into the kernel virtual
+ * address space. Needed when the kernel wants to access high addresses
+ * directly.
+ *
+ * NOTE! We need to allow non-page-aligned mappings too: we will obviously
+ * have to convert them into an offset in a page-aligned mapping, but the
+ * caller shouldn't need to know that small detail.
+ *
+ * 'flags' are the extra L_PTE_ flags that you want to specify for this
+ * mapping.  See include/asm-arm/proc-armv/pgtable.h for more information.
+ */
+void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
+{
+	void * addr;
+	struct vm_struct * area;
+	unsigned long offset;
+
+	/*
+	 * Mappings have to be page-aligned
+	 */
+	offset = phys_addr & ~PAGE_MASK;
+	size = PAGE_ALIGN(size + offset);
+
+	/*
+	 * Don't allow mappings that wrap..
+	 */
+	if (!size || size > phys_addr + size)
+		return NULL;
+
+	/*
+	 * Ok, go for it..
+	 */
+	area = get_vm_area(size);
+	if (!area)
+		return NULL;
+	addr = area->addr;
+	if (remap_area_pages(VMALLOC_VMADDR(addr), phys_addr, size, flags)) {
+		vfree(addr);
+		return NULL;
+	}
+	return (void *) (offset + (char *)addr);
+}
+
+void iounmap(void *addr)
+{
+	return vfree((void *) (PAGE_MASK & (unsigned long) addr));
+}
diff -u --recursive --new-file v2.2.7/linux/arch/arm/mm/mm-arc.c linux/arch/arm/mm/mm-arc.c
--- v2.2.7/linux/arch/arm/mm/mm-arc.c	Tue Jul 21 00:15:30 1998
+++ linux/arch/arm/mm/mm-arc.c	Wed Dec 31 16:00:00 1969
@@ -1,82 +0,0 @@
-/*
- * arch/arm/mm/mm-arc.c
- *
- * Extra MM routines for the Archimedes architecture
- *
- * Copyright (C) 1998 Russell King
- */
-#include <linux/init.h>
-#include <asm/hardware.h>
-#include <asm/pgtable.h>
-
-unsigned long phys_screen_end;
-
-/*
- * This routine needs more work to make it dynamically release/allocate mem!
- */
-__initfunc(unsigned long map_screen_mem(unsigned long log_start, unsigned long kmem, int update))
-{
-	static int updated = 0;
-
-	if (updated)
-		return 0;
-
-	updated = update;
-
-	if (update) {
-		unsigned long address = log_start, offset;
-		pgd_t *pgdp;
-
-		kmem = (kmem + 3) & ~3;
-
-		pgdp = pgd_offset (&init_mm, address);				/* +31 */
-		offset = SCREEN_START;
-		while (address < SCREEN1_END) {
-			unsigned long addr_pmd, end_pmd;
-			pmd_t *pmdp;
-
-			/* if (pgd_none (*pgdp)) alloc pmd */
-			pmdp = pmd_offset (pgdp, address);			/* +0 */
-			addr_pmd = address & ~PGDIR_MASK;			/* 088000 */
-			end_pmd = addr_pmd + SCREEN1_END - address;		/* 100000 */
-			if (end_pmd > PGDIR_SIZE)
-				end_pmd = PGDIR_SIZE;
-
-			do {
-				unsigned long addr_pte, end_pte;
-				pte_t *ptep;
-
-				if (pmd_none (*pmdp)) {
-					pte_t *new_pte = (pte_t *)kmem;
-					kmem += PTRS_PER_PTE * BYTES_PER_PTR;
-					memzero (new_pte, PTRS_PER_PTE * BYTES_PER_PTR);
-					set_pmd (pmdp, mk_pmd(new_pte));
-				}
-
-				ptep = pte_offset (pmdp, addr_pmd);		/* +11 */
-				addr_pte = addr_pmd & ~PMD_MASK;		/* 088000 */
-				end_pte = addr_pte + end_pmd - addr_pmd;	/* 100000 */
-				if (end_pte > PMD_SIZE)
-					end_pte = PMD_SIZE;
-
-				do {
-					set_pte (ptep, mk_pte(offset, PAGE_KERNEL));
-					addr_pte += PAGE_SIZE;
-					offset += PAGE_SIZE;
-					ptep++;
-				} while (addr_pte < end_pte);
-
-				pmdp++;
-				addr_pmd = (addr_pmd + PMD_SIZE) & PMD_MASK;
-			} while (addr_pmd < end_pmd);
-
-			address = (address + PGDIR_SIZE) & PGDIR_MASK;
-			pgdp ++;
-		}
-
-		phys_screen_end = offset;
-		flush_tlb_all ();
-		update_memc_all ();
-	}
-	return kmem;
-}
diff -u --recursive --new-file v2.2.7/linux/arch/arm/mm/mm-armv.c linux/arch/arm/mm/mm-armv.c
--- v2.2.7/linux/arch/arm/mm/mm-armv.c	Wed Sep  9 14:51:05 1998
+++ linux/arch/arm/mm/mm-armv.c	Sat May  8 11:06:57 1999
@@ -37,7 +37,8 @@
 		virtual = mp->virtual;
 		physical = mp->physical;
 		length = mp->length;
-		prot = (mp->prot_read ? PTE_AP_READ : 0) | (mp->prot_write ? PTE_AP_WRITE : 0);
+		prot = (mp->prot_read ? L_PTE_USER : 0) | (mp->prot_write ? L_PTE_WRITE : 0)
+			| L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY;
 
 		while ((virtual & 1048575 || physical & 1048575) && length >= PAGE_SIZE) {
 			alloc_init_page(&start_mem, virtual, physical, mp->domain, prot);
@@ -56,7 +57,8 @@
 			physical += 1048576;
 		}
 
-		prot = (mp->prot_read ? PTE_AP_READ : 0) | (mp->prot_write ? PTE_AP_WRITE : 0);
+		prot = (mp->prot_read ? L_PTE_USER : 0) | (mp->prot_write ? L_PTE_WRITE : 0)
+			| L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY;
 
 		while (length >= PAGE_SIZE) {
 			alloc_init_page(&start_mem, virtual, physical, mp->domain, prot);
diff -u --recursive --new-file v2.2.7/linux/arch/arm/mm/mm-ebsa285.c linux/arch/arm/mm/mm-ebsa285.c
--- v2.2.7/linux/arch/arm/mm/mm-ebsa285.c	Tue Dec 22 14:16:53 1998
+++ linux/arch/arm/mm/mm-ebsa285.c	Wed Dec 31 16:00:00 1969
@@ -1,39 +0,0 @@
-/*
- * arch/arm/mm/mm-ebsa285.c
- *
- * Extra MM routines for the EBSA285 architecture
- *
- * Copyright (C) 1998 Russell King, Dave Gilbert.
- */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/init.h>
- 
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/io.h>
-#include <asm/proc/mm-init.h>
-#include <asm/dec21285.h>
-
-/*
- * This is to allow us to fiddle with the EEPROM
- *  This entry will go away in time, once the fmu
- *  can mmap() the flash.
- *
- * These ones are so that we can fiddle
- *  with the various cards (eg VGA)
- *  until we're happy with them...
- */
-#define MAPPING \
-  { 0xd8000000, DC21285_FLASH,		      0x00400000, DOMAIN_USER, 1, 1 },	/* EEPROM */	    \
-  { 0xdc000000, 0x7c000000,		      0x00100000, DOMAIN_USER, 1, 1 },	/* VGA */	    \
-  { 0xe0000000, DC21285_PCI_MEM,	      0x18000000, DOMAIN_USER, 1, 1 },	/* VGA */	    \
-  { 0xf8000000, DC21285_PCI_TYPE_0_CONFIG,    0x01000000, DOMAIN_IO  , 0, 1 },	/* Type 0 Config */ \
-  { 0xf9000000, DC21285_PCI_TYPE_1_CONFIG,    0x01000000, DOMAIN_IO  , 0, 1 },	/* Type 1 Config */ \
-  { PCI_IACK,	DC21285_PCI_IACK,	      0x01000000, DOMAIN_IO  , 0, 1 },	/* PCI IACK	 */ \
-  { 0xfd000000, DC21285_OUTBOUND_WRITE_FLUSH, 0x01000000, DOMAIN_IO  , 0, 1 },	/* Out wrflsh	 */ \
-  { 0xfe000000, DC21285_ARMCSR_BASE,	      0x01000000, DOMAIN_IO  , 0, 1 },	/* CSR		 */ \
-  { 0xffe00000, DC21285_PCI_IO, 	      0x00100000, DOMAIN_IO  , 0, 1 },	/* PCI I/O	 */ \
-  { 0xfff00000, 0x40000000,		      0x00100000, DOMAIN_IO  , 0, 1 },	/* X-Bus	 */
-
-#include "mm-armv.c"
diff -u --recursive --new-file v2.2.7/linux/arch/arm/mm/mm-footbridge.c linux/arch/arm/mm/mm-footbridge.c
--- v2.2.7/linux/arch/arm/mm/mm-footbridge.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/arm/mm/mm-footbridge.c	Sat May  8 11:06:57 1999
@@ -0,0 +1,91 @@
+/*
+ * arch/arm/mm/mm-ebsa285.c
+ *
+ * Extra MM routines for the EBSA285 architecture
+ *
+ * Copyright (C) 1998 Russell King, Dave Gilbert.
+ */
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+ 
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/io.h>
+#include <asm/proc/mm-init.h>
+#include <asm/dec21285.h>
+
+/*
+ * The first entry allows us to fiddle with the EEPROM from user-space.
+ *  This entry will go away in time, once the fmu32 can mmap() the
+ *  flash.  It can't at the moment.
+ *
+ * If you want to fiddle with PCI VGA cards from user space, then
+ * change the '0, 1 }' for the PCI MEM and PCI IO to '1, 1 }'
+ * You can then access the PCI bus at 0xe0000000 and 0xffe00000.
+ */
+
+#ifdef CONFIG_HOST_FOOTBRIDGE
+
+/*
+ * The mapping when the footbridge is in host mode.
+ */
+#define MAPPING \
+ { FLASH_BASE,   DC21285_FLASH,			FLASH_SIZE,	DOMAIN_IO, 0, 1 }, \
+ { PCIMEM_BASE,  DC21285_PCI_MEM,		PCIMEM_SIZE,	DOMAIN_IO, 0, 1 }, \
+ { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG,	PCICFG0_SIZE,	DOMAIN_IO, 0, 1 }, \
+ { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG,	PCICFG1_SIZE,	DOMAIN_IO, 0, 1 }, \
+ { PCIIACK_BASE, DC21285_PCI_IACK,		PCIIACK_SIZE,	DOMAIN_IO, 0, 1 }, \
+ { WFLUSH_BASE,  DC21285_OUTBOUND_WRITE_FLUSH,	WFLUSH_SIZE,	DOMAIN_IO, 0, 1 }, \
+ { ARMCSR_BASE,  DC21285_ARMCSR_BASE,		ARMCSR_SIZE,	DOMAIN_IO, 0, 1 }, \
+ { PCIO_BASE,    DC21285_PCI_IO,		PCIO_SIZE,	DOMAIN_IO, 0, 1 }, \
+ { XBUS_BASE,    0x40000000,			XBUS_SIZE,	DOMAIN_IO, 0, 1 }
+
+#else
+
+/*
+ * These two functions convert virtual addresses to PCI addresses
+ * and PCI addresses to virtual addresses.  Note that it is only
+ * legal to use these on memory obtained via get_free_page or
+ * kmalloc.
+ */
+unsigned long __virt_to_bus(unsigned long res)
+{
+#ifdef CONFIG_DEBUG_ERRORS
+	if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) {
+		printk("__virt_to_phys: invalid virtual address 0x%08lx\n", res);
+		__backtrace();
+	}
+#endif
+	return (res - PAGE_OFFSET) + (*CSR_PCISDRAMBASE & 0xfffffff0);
+}
+
+unsigned long __bus_to_virt(unsigned long res)
+{
+	res -= (*CSR_PCISDRAMBASE & 0xfffffff0);
+	res += PAGE_OFFSET;
+
+#ifdef CONFIG_DEBUG_ERRORS
+	if (res < PAGE_OFFSET || res >= (unsigned long)high_memory) {
+		printk("__phys_to_virt: invalid virtual address 0x%08lx\n", res);
+		__backtrace();
+	}
+#endif
+	return res;
+}
+
+/*
+ * The mapping when the footbridge is in add-in mode.
+ */
+#define MAPPING \
+ { PCIO_BASE,	 DC21285_PCI_IO,		PCIO_SIZE,	DOMAIN_IO, 0, 1 }, \
+ { XBUS_BASE,	 0x40000000,			XBUS_SIZE,	DOMAIN_IO, 0, 1 }, \
+ { ARMCSR_BASE,  DC21285_ARMCSR_BASE,		ARMCSR_SIZE,	DOMAIN_IO, 0, 1 }, \
+ { WFLUSH_BASE,	 DC21285_OUTBOUND_WRITE_FLUSH,	WFLUSH_SIZE,	DOMAIN_IO, 0, 1 }, \
+ { FLASH_BASE,	 DC21285_FLASH,			FLASH_SIZE,	DOMAIN_IO, 0, 1 }, \
+ { PCIMEM_BASE,	 DC21285_PCI_MEM,		PCIMEM_SIZE,	DOMAIN_IO, 0, 1 }
+
+#endif
+
+#include "mm-armv.c"
diff -u --recursive --new-file v2.2.7/linux/arch/arm/mm/mm-vnc.c linux/arch/arm/mm/mm-vnc.c
--- v2.2.7/linux/arch/arm/mm/mm-vnc.c	Tue Dec 22 14:16:53 1998
+++ linux/arch/arm/mm/mm-vnc.c	Wed Dec 31 16:00:00 1969
@@ -1,31 +0,0 @@
-/*
- * arch/arm/mm/mm-vnc.c
- *
- * Extra MM routines for the Corel VNC architecture
- *
- * Copyright (C) 1998 Russell King
- */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/init.h>
- 
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/io.h>
-#include <asm/proc/mm-init.h>
-#include <asm/dec21285.h>
-
-/* Table describing the MMU translation mapping
- * mainly used to set up the I/O mappings.
- */ 
-#define MAPPING \
-  { 0xd0000000, DC21285_FLASH,		      0x00800000, DOMAIN_IO  , 0, 1 },	/* Flash	 */ \
-  { 0xe0000000, DC21285_PCI_MEM,	      0x18000000, DOMAIN_IO  , 0, 1 },	/* PCI Mem 	 */ \
-  { 0xf8000000, DC21285_PCI_TYPE_0_CONFIG,    0x01000000, DOMAIN_IO  , 0, 1 },	/* Type 0 Config */ \
-  { 0xf9000000, DC21285_PCI_TYPE_1_CONFIG,    0x01000000, DOMAIN_IO  , 0, 1 },	/* Type 1 Config */ \
-  { PCI_IACK,	DC21285_PCI_IACK,	      0x01000000, DOMAIN_IO  , 0, 1 },	/* PCI IACK	 */ \
-  { 0xfd000000, DC21285_OUTBOUND_WRITE_FLUSH, 0x01000000, DOMAIN_IO  , 0, 1 },	/* Out wrflsh	 */ \
-  { 0xfe000000, DC21285_ARMCSR_BASE,	      0x01000000, DOMAIN_IO  , 0, 1 },	/* CSR		 */ \
-  { 0xffe00000, DC21285_PCI_IO, 	      0x00100000, DOMAIN_IO  , 0, 1 },	/* PCI I/O	 */ \
-
-#include "mm-armv.c"
diff -u --recursive --new-file v2.2.7/linux/arch/arm/mm/proc-arm2,3.S linux/arch/arm/mm/proc-arm2,3.S
--- v2.2.7/linux/arch/arm/mm/proc-arm2,3.S	Sun Jun  7 11:16:26 1998
+++ linux/arch/arm/mm/proc-arm2,3.S	Sat May  8 11:07:16 1999
@@ -193,7 +193,7 @@
 		movs	pc, lr
 
 _arm2_3_check_bugs:
-		movs	pc, lr
+		bics	pc, lr, #0x04000000		@ Clear FIQ disable bit
 
 /*
  * Processor specific - ARM2
@@ -206,6 +206,8 @@
  * Params  : prev	Old task structure
  *	   : next	New task structure for process to run
  *
+ * Returns : prev
+ *
  * Purpose : Perform a task switch, saving the old processes state, and restoring
  *	     the new.
  *
@@ -218,15 +220,15 @@
 		str	sp, [r0, #TSS_SAVE]		@ Save sp_SVC
 		ldr	sp, [r1, #TSS_SAVE]		@ Get saved sp_SVC
 		mov	r4, r1
-		add	r0, r1, #TSS_MEMCMAP		@ Remap MEMC
+		add	r7, r1, #TSS_MEMCMAP		@ Remap MEMC
 		ldr	r1, LC0
 		ldr	r1, [r1]
-1:		ldmia	r0!, {r2, r3, r5, r6}
+1:		ldmia	r7!, {r2, r3, r5, r6}
 		strb	r2, [r2]
 		strb	r3, [r3]
 		strb	r5, [r5]
 		strb	r6, [r6]
-		ldmia	r0!, {r2, r3, r5, r6}
+		ldmia	r7!, {r2, r3, r5, r6}
 		strb	r2, [r2]
 		strb	r3, [r3]
 		strb	r5, [r5]
@@ -318,6 +320,8 @@
  * Params  : prev	Old task structure
  *	   : next	New task structure for process to run
  *
+ * Returns : prev
+ *
  * Purpose : Perform a task switch, saving the old processes state, and restoring
  *	     the new.
  *
@@ -330,22 +334,22 @@
 		str	sp, [r0, #TSS_SAVE]		@ Save sp_SVC
 		ldr	sp, [r1, #TSS_SAVE]		@ Get saved sp_SVC
 		mov	r4, r1
-		add	r0, r1, #TSS_MEMCMAP		@ Remap MEMC
+		add	r7, r1, #TSS_MEMCMAP		@ Remap MEMC
 		ldr	r1, LC0
 		ldr	r1, [r1]
-1:		ldmia	r0!, {r2, r3, r5, r6}
+1:		ldmia	r7!, {r2, r3, r5, r6}
 		strb	r2, [r2]
 		strb	r3, [r3]
 		strb	r5, [r5]
 		strb	r6, [r6]
-		ldmia	r0!, {r2, r3, r5, r6}
+		ldmia	r7!, {r2, r3, r5, r6}
 		strb	r2, [r2]
 		strb	r3, [r3]
 		strb	r5, [r5]
 		strb	r6, [r6]
 		subs	r1, r1, #8
 		bhi	1b
-		mcr	p15, 0, r0, c1, c0, 0		@ flush cache
+		mcr	p15, 0, r7, c1, c0, 0		@ flush cache
 		ldmfd	sp!, {r4 - r9, fp, pc}^		@ Load all regs saved previously
 /*
  * Function: arm3_remap_memc (struct task_struct *tsk)
diff -u --recursive --new-file v2.2.7/linux/arch/arm/mm/proc-arm6,7.S linux/arch/arm/mm/proc-arm6,7.S
--- v2.2.7/linux/arch/arm/mm/proc-arm6,7.S	Wed Sep  9 14:51:05 1998
+++ linux/arch/arm/mm/proc-arm6,7.S	Sat May  8 11:07:16 1999
@@ -52,13 +52,14 @@
 		blt	1b
 		mov	pc, lr
 
-@LC0:		.word	_current
 /*
  * Function: arm6_7_switch_to (struct task_struct *prev, struct task_struct *next)
  *
  * Params  : prev	Old task structure
  *	   : next	New task structure for process to run
  *
+ * Returns : prev
+ *
  * Purpose : Perform a task switch, saving the old processes state, and restoring
  *	     the new.
  *
@@ -72,15 +73,15 @@
 		stmfd	sp!, {ip}			@ Save cpsr_SVC
 		str	sp, [r0, #TSS_SAVE]		@ Save sp_SVC
 		ldr	sp, [r1, #TSS_SAVE]		@ Get saved sp_SVC
-		ldr	r0, [r1, #TSK_ADDR_LIMIT]
-		teq	r0, #0
-		moveq	r0, #DOM_KERNELDOMAIN
-		movne	r0, #DOM_USERDOMAIN
-		mcr	p15, 0, r0, c3, c0		@ Set domain reg
-		ldr	r0, [r1, #TSS_MEMMAP]		@ Page table pointer
+		ldr	r2, [r1, #TSK_ADDR_LIMIT]
+		teq	r2, #0
+		moveq	r2, #DOM_KERNELDOMAIN
+		movne	r2, #DOM_USERDOMAIN
+		mcr	p15, 0, r2, c3, c0		@ Set domain reg
+		ldr	r2, [r1, #TSS_MEMMAP]		@ Page table pointer
 		mov	r1, #0
 		mcr	p15, 0, r1, c7, c0, 0		@ flush cache
-		mcr	p15, 0, r0, c2, c0, 0		@ update page table ptr
+		mcr	p15, 0, r2, c2, c0, 0		@ update page table ptr
 		mcr	p15, 0, r1, c5, c0, 0		@ flush TLBs
 		ldmfd	sp!, {ip}
 		msr	spsr, ip			@ Save tasks CPSR into SPSR for this return
@@ -369,6 +370,35 @@
 		mov	pc, lr
 
 /*
+ * Function: arm6_7_set_pte(pte_t *ptep, pte_t pte)
+ * Params  : r0 = Address to set
+ *	   : r1 = value to set
+ * Purpose : Set a PTE and flush it out of any WB cache
+ */
+		.align	5
+_arm6_7_set_pte:
+		str	r1, [r0], #-1024		@ linux version
+
+		bic	r2, r1, #0xff0
+		bic	r2, r2, #3
+		orr	r2, r2, #HPTE_TYPE_SMALL
+
+		tst	r1, #LPTE_USER | LPTE_EXEC
+		orrne	r2, r2, #HPTE_AP_READ
+
+		tst	r1, #LPTE_WRITE
+		tstne	r1, #LPTE_DIRTY
+		orrne	r2, r2, #HPTE_AP_WRITE
+
+		tst	r1, #LPTE_PRESENT
+		tstne	r1, #LPTE_YOUNG
+		moveq	r2, #0
+
+		str	r2, [r0]			@ hardware version
+		mcr	p15, 0, r0, c7, c10, 1		@ clean D entry	 (drain is done by TLB fns)
+		mov	pc, lr
+
+/*
  * Function: _arm6_7_reset
  *
  * Notes   : This sets up everything for a reset
@@ -405,8 +435,12 @@
 		.word	_arm6_7_flush_tlb_all		@ 44
 		.word	_arm6_7_flush_tlb_area		@ 48
 		.word	_arm6_set_pmd			@ 52
-		.word	_arm6_7_reset			@ 54
-		.word	_arm6_7_flush_cache		@ 58
+		.word	_arm6_7_set_pte			@ 56
+		.word	_arm6_7_reset			@ 60
+		.word	_arm6_7_flush_cache		@ 64
+
+		.word	_arm6_7_flush_cache		@ 68
+		.word	_arm6_7_flush_cache		@ 72
 
 /*
  * Purpose : Function pointers used to access above functions - all calls
@@ -431,8 +465,9 @@
 		.word	_arm6_7_flush_tlb_all		@ 44
 		.word	_arm6_7_flush_tlb_area		@ 48
 		.word	_arm7_set_pmd			@ 52
-		.word	_arm6_7_reset			@ 56
-		.word	_arm6_7_flush_cache		@ 60
-
+		.word	_arm6_7_set_pte			@ 56
+		.word	_arm6_7_reset			@ 60
 		.word	_arm6_7_flush_cache		@ 64
+
 		.word	_arm6_7_flush_cache		@ 68
+		.word	_arm6_7_flush_cache		@ 72
diff -u --recursive --new-file v2.2.7/linux/arch/arm/mm/proc-sa110.S linux/arch/arm/mm/proc-sa110.S
--- v2.2.7/linux/arch/arm/mm/proc-sa110.S	Tue Dec 22 14:16:53 1998
+++ linux/arch/arm/mm/proc-sa110.S	Sat May  8 11:07:16 1999
@@ -8,6 +8,7 @@
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
+#include <asm/hardware.h>
 #include "../lib/constants.h"
 
 /* This is the maximum size of an area which will be flushed.  If the area
@@ -21,7 +22,6 @@
 
 /*
  * Function: sa110_flush_cache_all (void)
- *
  * Purpose : Flush all cache lines
  */
 		.align	5
@@ -33,7 +33,7 @@
 		ands	r1, r1, #1
 		eor	r1, r1, #1
 		str	r1, [r3]
-		ldr	ip, =0xdf000000
+		ldr	ip, =FLUSH_BASE
 		addne	ip, ip, #32768
 		add	r1, ip, #16384			@ only necessary for 16k
 1:		ldr	r3, [ip], #32
@@ -47,11 +47,9 @@
 
 /*
  * Function: sa110_flush_cache_area (unsigned long address, int end, int flags)
- *
  * Params  : address	Area start address
  *	   : end	Area end address
  *	   : flags	b0 = I cache as well
- *
  * Purpose : clean & flush all cache lines associated with this area of memory
  */
 		.align	5
@@ -74,10 +72,8 @@
 
 /*
  * Function: sa110_cache_wback_area(unsigned long address, unsigned long end)
- *
  * Params  : address	Area start address
  *	   : end	Area end address
- *
  * Purpose : ensure all dirty cachelines in the specified area have been
  *	     written out to memory (for DMA)
  */
@@ -99,13 +95,10 @@
 
 /*
  * Function: sa110_cache_purge_area(unsigned long address, unsigned long end)
- *
  * Params  : address	Area start address
  *	   : end	Area end address
- *
  * Purpose : throw away all D-cached data in specified region without
- *	     an obligation to write it ack.
- *
+ *	     an obligation to write it back.
  * Note    : Must clean the D-cached entries around the boundaries if the
  *	     start and/or end address are not cache aligned.
  */
@@ -124,9 +117,7 @@
 
 /*
  * Function: sa110_flush_cache_entry (unsigned long address)
- *
  * Params  : address	Address of cache line to flush
- *
  * Purpose : clean & flush an entry
  */
 		.align	5
@@ -138,24 +129,23 @@
 		mov	pc, lr
 
 /*
- * Function: sa110_flush_cache_pte (unsigned long address)
- *
+ * Function: sa110_clean_cache_area(unsigned long start, unsigned long size)
  * Params  : address	Address of cache line to clean
- *
  * Purpose : Ensure that physical memory reflects cache at this location
  *	     for page table purposes.
  */
-_sa110_flush_cache_pte:
-		mcr	p15, 0, r0, c7, c10, 1		@ clean D entry	 (drain is done by TLB fns)
+_sa110_clean_cache_area:
+1:		mcr	p15, 0, r0, c7, c10, 1		@ clean D entry	 (drain is done by TLB fns)
+		add	r0, r0, #32
+		subs	r1, r1, #32
+		bhi	1b
 		mov	pc, lr
 
 /*
  * Function: sa110_flush_ram_page (unsigned long page)
- *
  * Params  : address	Area start address
  *	   : size	size of area
  *	   : flags	b0 = I cache as well
- *
  * Purpose : clean & flush all cache lines associated with this area of memory
  */
 		.align	5
@@ -176,7 +166,6 @@
 
 /*
  * Function: sa110_flush_tlb_all (void)
- *
  * Purpose : flush all TLB entries in all caches
  */
 		.align	5
@@ -188,11 +177,9 @@
 
 /*
  * Function: sa110_flush_tlb_area (unsigned long address, unsigned long end, int flags)
- *
  * Params  : address	Area start address
  *	   : end	Area end address
  *	   : flags	b0 = I cache as well
- *
  * Purpose : flush a TLB entry
  */
 		.align	5
@@ -212,22 +199,21 @@
 
 		.align	5
 _sa110_flush_icache_area:
-		mov	r3, #0
 1:		mcr	p15, 0, r0, c7, c10, 1		@ Clean D entry
 		add	r0, r0, #32
-		cmp	r0, r1
-		blt	1b
+		subs	r1, r1, #32
+		bhi	1b
+		mov	r0, #0
+		mcr	p15, 0, r0, c7, c10, 4		@ drain WB
 		mcr	p15, 0, r0, c7, c5, 0		@ flush I cache
 		mov	pc, lr
 /*
  * Function: sa110_switch_to (struct task_struct *prev, struct task_struct *next)
- *
  * Params  : prev	Old task structure
  *	   : next	New task structure for process to run
- *
+ * Returns : prev
  * Purpose : Perform a task switch, saving the old processes state, and restoring
  *	     the new.
- *
  * Notes   : We don't fiddle with the FP registers here - we postpone this until
  *	     the new task actually uses FP.  This way, we don't swap FP for tasks
  *	     that do not require it.
@@ -237,20 +223,30 @@
 		stmfd	sp!, {r4 - r9, fp, lr}		@ Store most regs on stack
 		mrs	ip, cpsr
 		stmfd	sp!, {ip}			@ Save cpsr_SVC
+		ldr	r2, [r0, #TSS_MEMMAP]		@ Get old page tables
 		str	sp, [r0, #TSS_SAVE]		@ Save sp_SVC
 		ldr	sp, [r1, #TSS_SAVE]		@ Get saved sp_SVC
-		ldr	r0, [r1, #TSK_ADDR_LIMIT]
-		teq	r0, #0
-		moveq	r0, #DOM_KERNELDOMAIN
-		movne	r0, #DOM_USERDOMAIN
-		mcr	p15, 0, r0, c3, c0		@ Set segment
-		ldr	r0, [r1, #TSS_MEMMAP]		@ Page table pointer
+		ldr	r4, [r1, #TSK_ADDR_LIMIT]
+		teq	r4, #0
+		moveq	r4, #DOM_KERNELDOMAIN
+		movne	r4, #DOM_USERDOMAIN
+		mcr	p15, 0, r4, c3, c0		@ Set segment
+		ldr	r4, [r1, #TSS_MEMMAP]		@ Page table pointer
+/*
+ * Flushing the cache is nightmarishly slow, so we take any excuse
+ * to get out of it.  If the old page table is the same as the new,
+ * this is a CLONE_VM relative of the old task and there is no need
+ * to flush.  The overhead of the tests isn't even on the radar
+ * compared to the cost of the flush itself.
+ */
+		teq	r4, r2
+		beq	2f
 		ldr	r3, =Lclean_switch
 		ldr	r2, [r3]
 		ands	r2, r2, #1
 		eor	r2, r2, #1
 		str	r2, [r3]
-		ldr	r2, =0xdf000000
+		ldr	r2, =FLUSH_BASE
 		addne	r2, r2, #32768
 		add	r1, r2, #16384			@ only necessary for 16k
 1:		ldr	r3, [r2], #32
@@ -259,19 +255,16 @@
 		mov	r1, #0
 		mcr	p15, 0, r1, c7, c5, 0		@ flush I cache
 		mcr	p15, 0, r1, c7, c10, 4		@ drain WB
-		mcr	p15, 0, r0, c2, c0, 0		@ load page table pointer
+		mcr	p15, 0, r4, c2, c0, 0		@ load page table pointer
 		mcr	p15, 0, r1, c8, c7, 0		@ flush TLBs
-		ldmfd	sp!, {ip}
+2:		ldmfd	sp!, {ip}
 		msr	spsr, ip			@ Save tasks CPSR into SPSR for this return
 		ldmfd	sp!, {r4 - r9, fp, pc}^		@ Load all regs saved previously
 
 /*
  * Function: sa110_data_abort ()
- *
  * Params  : r0 = address of aborted instruction
- *
  * Purpose : obtain information about current aborted instruction
- *
  * Returns : r0 = address of abort
  *	   : r1 = FSR
  *	   : r2 != 0 if writing
@@ -288,12 +281,10 @@
 		mov	pc, lr
 
 /*
- * Function: sa110_set_pmd ()
- *
+ * Function: sa110_set_pmd(pmd_t *pmdp, pmd_t pmd)
  * Params  : r0 = Address to set
  *	   : r1 = value to set
- *
- * Purpose : Set a PMD and flush it out of any WB cache
+ * Purpose : Set a PMD and flush it out
  */
 		.align	5
 _sa110_set_pmd:	str	r1, [r0]
@@ -301,23 +292,51 @@
 		mov	pc, lr
 
 /*
+ * Function: sa110_set_pte(pte_t *ptep, pte_t pte)
+ * Params  : r0 = Address to set
+ *	   : r1 = value to set
+ * Purpose : Set a PTE and flush it out
+ */
+		.align	5
+_sa110_set_pte:	str	r1, [r0], #-1024		@ linux version
+
+		eor	r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY
+
+		bic	r2, r1, #0xff0
+		bic	r2, r2, #3
+		orr	r2, r2, #HPTE_TYPE_SMALL
+
+		tst	r1, #LPTE_USER | LPTE_EXEC	@ User or Exec?
+		orrne	r2, r2, #HPTE_AP_READ
+
+		tst	r1, #LPTE_WRITE | LPTE_DIRTY	@ Write and Dirty?
+		orreq	r2, r2, #HPTE_AP_WRITE
+
+		tst	r1, #LPTE_PRESENT | LPTE_YOUNG	@ Present and Young?
+		movne	r2, #0
+
+		str	r2, [r0]			@ hardware version
+		mov	r0, r0
+		mcr	p15, 0, r0, c7, c10, 1		@ clean D entry	 (drain is done by TLB fns)
+		mov	pc, lr
+
+/*
  * Function: sa110_check_bugs (void)
  *	   : sa110_proc_init (void)
  *	   : sa110_proc_fin (void)
- *
  * Notes   : This processor does not require these
  */
 _sa110_check_bugs:
 		mrs	ip, cpsr
 		bic	ip, ip, #F_BIT
 		msr	cpsr, ip
+
 _sa110_proc_init:
 _sa110_proc_fin:
 		mov	pc, lr
 
 /*
  * Function: sa110_reset
- *
  * Notes   : This sets up everything for a reset
  */
 _sa110_reset:	mrs	r1, cpsr
@@ -350,14 +369,15 @@
 		.word	_sa110_flush_cache_all		@ 24
 		.word	_sa110_flush_cache_area		@ 28
 		.word	_sa110_flush_cache_entry	@ 32
-		.word	_sa110_flush_cache_pte		@ 36
+		.word	_sa110_clean_cache_area		@ 36
 		.word	_sa110_flush_ram_page		@ 40
 		.word	_sa110_flush_tlb_all		@ 44
 		.word	_sa110_flush_tlb_area		@ 48
 
 		.word	_sa110_set_pmd			@ 52
-		.word	_sa110_reset			@ 56
-		.word	_sa110_flush_icache_area	@ 60
+		.word	_sa110_set_pte			@ 56
+		.word	_sa110_reset			@ 60
+		.word	_sa110_flush_icache_area	@ 64
 
-		.word	_sa110_cache_wback_area		@ 64
-		.word	_sa110_cache_purge_area		@ 68
+		.word	_sa110_cache_wback_area		@ 68
+		.word	_sa110_cache_purge_area		@ 72
diff -u --recursive --new-file v2.2.7/linux/arch/arm/mm/small_page.c linux/arch/arm/mm/small_page.c
--- v2.2.7/linux/arch/arm/mm/small_page.c	Wed Sep  9 14:51:05 1998
+++ linux/arch/arm/mm/small_page.c	Sat May  8 11:06:57 1999
@@ -5,6 +5,8 @@
  *
  * Changelog:
  *  26/01/1996	RMK	Cleaned up various areas to make little more generic
+ *  07/02/1999	RMK	Support added for 16K and 32K page sizes
+ *			containing 8K blocks
  */
 
 #include <linux/signal.h>
@@ -19,21 +21,32 @@
 #include <linux/swap.h>
 #include <linux/smp.h>
 
-#define SMALL_ALLOC_SHIFT	(10)
+#if PAGE_SIZE == 4096
+/* 2K blocks */
+#define SMALL_ALLOC_SHIFT	(11)
+#define NAME(x)			x##_2k
+#elif PAGE_SIZE == 32768 || PAGE_SIZE == 16384
+/* 8K blocks */
+#define SMALL_ALLOC_SHIFT	(13)
+#define NAME(x)			x##_8k
+#endif
+
 #define SMALL_ALLOC_SIZE	(1 << SMALL_ALLOC_SHIFT)
 #define NR_BLOCKS		(PAGE_SIZE / SMALL_ALLOC_SIZE)
+#define BLOCK_MASK		((1 << NR_BLOCKS) - 1)
 
-#if NR_BLOCKS != 4
-#error I only support 4 blocks per page!
-#endif
-
-#define USED(pg)		((atomic_read(&(pg)->count) >> 8) & 15)
+#define USED(pg)		((atomic_read(&(pg)->count) >> 8) & BLOCK_MASK)
 #define SET_USED(pg,off)	(atomic_read(&(pg)->count) |= 256 << off)
 #define CLEAR_USED(pg,off)	(atomic_read(&(pg)->count) &= ~(256 << off))
+#define ALL_USED		BLOCK_MASK
 #define IS_FREE(pg,off)		(!(atomic_read(&(pg)->count) & (256 << off)))
-#define PAGE_PTR(page,block)	((struct free_small_page *)((page) + \
+#define SM_PAGE_PTR(page,block)	((struct free_small_page *)((page) + \
 					((block) << SMALL_ALLOC_SHIFT)))
 
+#if NR_BLOCKS != 2 && NR_BLOCKS != 4
+#error I only support 2 or 4 blocks per page
+#endif
+
 struct free_small_page {
 	unsigned long next;
 	unsigned long prev;
@@ -52,6 +65,7 @@
 	1,	/* 0001 */
 	0,	/* 0010 */
 	2,	/* 0011 */
+#if NR_BLOCKS == 4
 	0,	/* 0100 */
 	1,	/* 0101 */
 	0,	/* 0110 */
@@ -64,6 +78,7 @@
 	1,	/* 1101 */
 	0,	/* 1110 */
 	4	/* 1111 */
+#endif
 };
 
 static inline void clear_page_links(unsigned long page)
@@ -72,7 +87,7 @@
 	int i;
 
 	for (i = 0; i < NR_BLOCKS; i++) {
-		fsp = PAGE_PTR(page, i);
+		fsp = SM_PAGE_PTR(page, i);
 		fsp->next = fsp->prev = 0;
 	}
 }
@@ -90,7 +105,7 @@
 	for (i = 0; i < NR_BLOCKS; i++) {
 		if (mask & (1 << i))
 			continue;
-		fsp = PAGE_PTR(page, i);
+		fsp = SM_PAGE_PTR(page, i);
 		fsp->prev = prev;
 	}
 }
@@ -108,12 +123,12 @@
 	for (i = 0; i < NR_BLOCKS; i++) {
 		if (mask & (1 << i))
 			continue;
-		fsp = PAGE_PTR(page, i);
+		fsp = SM_PAGE_PTR(page, i);
 		fsp->next = next;
 	}
 }
 
-unsigned long get_small_page(int priority)
+unsigned long NAME(get_page)(int priority)
 {
 	struct free_small_page *fsp;
 	unsigned long new_page;
@@ -129,8 +144,8 @@
 	page = mem_map + MAP_NR(small_page_ptr);
 	offset = offsets[USED(page)];
 	SET_USED(page, offset);
-	new_page = (unsigned long)PAGE_PTR(small_page_ptr, offset);
-	if (USED(page) == 15) {
+	new_page = (unsigned long)SM_PAGE_PTR(small_page_ptr, offset);
+	if (USED(page) == ALL_USED) {
 		fsp = (struct free_small_page *)new_page;
 		set_page_links_prev (fsp->next, 0);
 		small_page_ptr = fsp->next;
@@ -156,30 +171,31 @@
 	goto again;
 }
 
-void free_small_page(unsigned long spage)
+void NAME(free_page)(unsigned long spage)
 {
 	struct free_small_page *ofsp, *cfsp;
 	unsigned long flags;
 	struct page *page;
 	int offset, oldoffset;
 
+	if (!spage)
+		goto none;
+
 	offset = (spage >> SMALL_ALLOC_SHIFT) & (NR_BLOCKS - 1);
 	spage -= offset << SMALL_ALLOC_SHIFT;
 
 	page = mem_map + MAP_NR(spage);
-	if (!PageReserved(page) || !USED(page)) {
-		printk ("Trying to free non-small page from %p\n", __builtin_return_address(0));
-		return;
-	}
-	if (IS_FREE(page, offset)) {
-		printk ("Trying to free free small page from %p\n", __builtin_return_address(0));
-		return;
-	}
+	if (!PageReserved(page) || !USED(page))
+		goto non_small;
+
+	if (IS_FREE(page, offset))
+		goto free;
+
 	save_flags_cli (flags);
 	oldoffset = offsets[USED(page)];
 	CLEAR_USED(page, offset);
-	ofsp = PAGE_PTR(spage, oldoffset);
-	cfsp = PAGE_PTR(spage, offset);
+	ofsp = SM_PAGE_PTR(spage, oldoffset);
+	cfsp = SM_PAGE_PTR(spage, offset);
 
 	if (oldoffset == NR_BLOCKS) { /* going from totally used to mostly used */
 		cfsp->prev = 0;
@@ -197,4 +213,13 @@
 	} else
 		*cfsp = *ofsp;
 	restore_flags(flags);
+	return;
+
+non_small:
+	printk ("Trying to free non-small page from %p\n", __builtin_return_address(0));
+	return;
+free:
+	printk ("Trying to free free small page from %p\n", __builtin_return_address(0));
+none:
+	return;
 }
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v2.2.7/linux/arch/i386/kernel/entry.S	Wed Jan 20 23:14:04 1999
+++ linux/arch/i386/kernel/entry.S	Fri Apr 30 08:13:37 1999
@@ -154,7 +154,9 @@
 	.globl	ret_from_fork
 ret_from_fork:
 #ifdef __SMP__
+	pushl %ebx
 	call SYMBOL_NAME(schedule_tail)
+	addl $4, %esp
 #endif /* __SMP__ */
 	GET_CURRENT(%ebx)
 	jmp	ret_from_sys_call
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- v2.2.7/linux/arch/i386/kernel/i386_ksyms.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/i386/kernel/i386_ksyms.c	Mon May 10 10:32:45 1999
@@ -39,6 +39,7 @@
 EXPORT_SYMBOL(local_irq_count);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(disable_irq_nosync);
 EXPORT_SYMBOL(kernel_thread);
 
 EXPORT_SYMBOL_NOVERS(__down_failed);
@@ -91,7 +92,7 @@
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
-EXPORT_SYMBOL(mtrr_hook);
+EXPORT_SYMBOL(smp_call_function);
 #endif
 
 #ifdef CONFIG_MCA
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c
--- v2.2.7/linux/arch/i386/kernel/io_apic.c	Fri Apr 16 14:47:30 1999
+++ linux/arch/i386/kernel/io_apic.c	Thu May  6 16:07:03 1999
@@ -1049,7 +1049,7 @@
 	 * and do not need to be masked.
 	 */
 	ack_APIC_irq();
-	status = desc->status & ~IRQ_REPLAY;
+	status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
 	status |= IRQ_PENDING;
 
 	/*
@@ -1060,8 +1060,9 @@
 	if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
 		action = desc->action;
 		status &= ~IRQ_PENDING;
+		status |= IRQ_INPROGRESS;
 	}
-	desc->status = status | IRQ_INPROGRESS;
+	desc->status = status;
 	spin_unlock(&irq_controller_lock);
 
 	/*
@@ -1103,7 +1104,7 @@
 	 * So this all has to be within the spinlock.
 	 */
 	mask_IO_APIC_irq(irq);
-	status = desc->status & ~IRQ_REPLAY;
+	status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
 
 	/*
 	 * If the IRQ is disabled for whatever reason, we must
@@ -1112,8 +1113,9 @@
 	action = NULL;
 	if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
 		action = desc->action;
+		status |= IRQ_INPROGRESS;
 	}
-	desc->status = status | IRQ_INPROGRESS;
+	desc->status = status;
 
 	ack_APIC_irq();
 	spin_unlock(&irq_controller_lock);
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.2.7/linux/arch/i386/kernel/irq.c	Fri Apr 16 14:47:30 1999
+++ linux/arch/i386/kernel/irq.c	Mon May 10 10:32:45 1999
@@ -203,7 +203,7 @@
 
 void make_8259A_irq(unsigned int irq)
 {
-	disable_irq(irq);
+	disable_irq_nosync(irq);
 	io_apic_irqs &= ~(1<<irq);
 	irq_desc[irq].handler = &i8259A_irq_type;
 	enable_irq(irq);
@@ -239,11 +239,13 @@
 	{
 		unsigned int status;
 		mask_and_ack_8259A(irq);
-		status = desc->status & ~IRQ_REPLAY;
+		status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
 		action = NULL;
-		if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
 			action = desc->action;
-		desc->status = status | IRQ_INPROGRESS;
+			status |= IRQ_INPROGRESS;
+		}
+		desc->status = status;
 	}
 	spin_unlock(&irq_controller_lock);
 
@@ -320,7 +322,7 @@
 BUILD_SMP_INTERRUPT(reschedule_interrupt)
 BUILD_SMP_INTERRUPT(invalidate_interrupt)
 BUILD_SMP_INTERRUPT(stop_cpu_interrupt)
-BUILD_SMP_INTERRUPT(mtrr_interrupt)
+BUILD_SMP_INTERRUPT(call_function_interrupt)
 BUILD_SMP_INTERRUPT(spurious_interrupt)
 
 /*
@@ -747,7 +749,7 @@
  * hardware disable after having gotten the irq
  * controller lock. 
  */
-void disable_irq(unsigned int irq)
+void disable_irq_nosync(unsigned int irq)
 {
 	unsigned long flags;
 
@@ -757,9 +759,21 @@
 		irq_desc[irq].handler->disable(irq);
 	}
 	spin_unlock_irqrestore(&irq_controller_lock, flags);
+}
+
+/*
+ * Synchronous version of the above, making sure the IRQ is
+ * no longer running on any other IRQ..
+ */
+void disable_irq(unsigned int irq)
+{
+	disable_irq_nosync(irq);
 
-	if (irq_desc[irq].status & IRQ_INPROGRESS)
-		synchronize_irq();
+	if (!local_irq_count[smp_processor_id()]) {
+		do {
+			barrier();
+		} while (irq_desc[irq].status & IRQ_INPROGRESS);
+	}
 }
 
 void enable_irq(unsigned int irq)
@@ -769,7 +783,7 @@
 	spin_lock_irqsave(&irq_controller_lock, flags);
 	switch (irq_desc[irq].depth) {
 	case 1:
-		irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_INPROGRESS);
+		irq_desc[irq].status &= ~IRQ_DISABLED;
 		irq_desc[irq].handler->enable(irq);
 		/* fall throught */
 	default:
@@ -864,7 +878,7 @@
 
 	if (!shared) {
 		irq_desc[irq].depth = 0;
-		irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_INPROGRESS);
+		irq_desc[irq].status &= ~IRQ_DISABLED;
 		irq_desc[irq].handler->startup(irq);
 	}
 	spin_unlock_irqrestore(&irq_controller_lock,flags);
@@ -936,7 +950,7 @@
  *
  * This depends on the fact that any interrupt that
  * comes in on to an unassigned handler will get stuck
- * with "IRQ_INPROGRESS" asserted and the interrupt
+ * with "IRQ_WAITING" cleared and the interrupt
  * disabled.
  */
 unsigned long probe_irq_on(void)
@@ -950,8 +964,7 @@
 	spin_lock_irq(&irq_controller_lock);
 	for (i = NR_IRQS-1; i > 0; i--) {
 		if (!irq_desc[i].action) {
-			unsigned int status = irq_desc[i].status | IRQ_AUTODETECT;
-			irq_desc[i].status = status & ~IRQ_INPROGRESS;
+			irq_desc[i].status |= IRQ_AUTODETECT | IRQ_WAITING;
 			irq_desc[i].handler->startup(i);
 		}
 	}
@@ -974,7 +987,7 @@
 			continue;
 		
 		/* It triggered already - consider it spurious. */
-		if (status & IRQ_INPROGRESS) {
+		if (!(status & IRQ_WAITING)) {
 			irq_desc[i].status = status & ~IRQ_AUTODETECT;
 			irq_desc[i].handler->shutdown(i);
 		}
@@ -1000,7 +1013,7 @@
 		if (!(status & IRQ_AUTODETECT))
 			continue;
 
-		if (status & IRQ_INPROGRESS) {
+		if (!(status & IRQ_WAITING)) {
 			if (!nr_irqs)
 				irq_found = i;
 			nr_irqs++;
@@ -1081,8 +1094,8 @@
 	/* self generated IPI for local APIC timer */
 	set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
 
-	/* IPI for MTRR control */
-	set_intr_gate(MTRR_CHANGE_VECTOR, mtrr_interrupt);
+	/* IPI for generic function call */
+	set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
 
 	/* IPI vector for APIC spurious interrupts */
 	set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/irq.h linux/arch/i386/kernel/irq.h
--- v2.2.7/linux/arch/i386/kernel/irq.h	Fri Apr 16 14:47:30 1999
+++ linux/arch/i386/kernel/irq.h	Mon May 10 11:16:39 1999
@@ -26,6 +26,7 @@
 #define IRQ_PENDING	4	/* IRQ pending - replay on enable */
 #define IRQ_REPLAY	8	/* IRQ has been replayed but not acked yet */
 #define IRQ_AUTODETECT	16	/* IRQ is being autodetected */
+#define IRQ_WAITING	32	/* IRQ not yet seen - for autodetection */
 
 /*
  * This is the "IRQ descriptor", which contains various information
@@ -64,7 +65,7 @@
 #define INVALIDATE_TLB_VECTOR	0x31
 #define STOP_CPU_VECTOR		0x40
 #define LOCAL_TIMER_VECTOR	0x41
-#define MTRR_CHANGE_VECTOR	0x50
+#define CALL_FUNCTION_VECTOR	0x50
 
 /*
  * First APIC vector available to drivers: (vectors 0x51-0xfe)
@@ -98,7 +99,6 @@
 extern int i8259A_irq_pending(unsigned int irq);
 extern void ack_APIC_irq(void);
 extern void FASTCALL(send_IPI_self(int vector));
-extern void smp_send_mtrr(void);
 extern void init_VISWS_APIC_irqs(void);
 extern void setup_IO_APIC(void);
 extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c
--- v2.2.7/linux/arch/i386/kernel/mtrr.c	Mon Dec 28 15:00:52 1998
+++ linux/arch/i386/kernel/mtrr.c	Mon May 10 10:32:45 1999
@@ -132,6 +132,70 @@
 	       Fixed harmless compiler warning in include/asm-i386/mtrr.h
 	       Fixed version numbering and history for v1.23 -> v1.24.
   v1.26
+    19990118   Richard Gooch <rgooch@atnf.csiro.au>
+	       PLACEHOLDER.
+  v1.27
+    19990123   Richard Gooch <rgooch@atnf.csiro.au>
+	       Changed locking to spin with reschedule.
+	       Made use of new <smp_call_function>.
+  v1.28
+    19990201   Zoltan Boszormenyi <zboszor@mol.hu>
+	       Extended the driver to be able to use Cyrix style ARRs.
+    19990204   Richard Gooch <rgooch@atnf.csiro.au>
+	       Restructured Cyrix support.
+  v1.29
+    19990204   Zoltan Boszormenyi <zboszor@mol.hu>
+	       Refined ARR support: enable MAPEN in set_mtrr_prepare()
+	       and disable MAPEN in set_mtrr_done().
+    19990205   Richard Gooch <rgooch@atnf.csiro.au>
+	       Minor cleanups.
+  v1.30
+    19990208   Zoltan Boszormenyi <zboszor@mol.hu>
+               Protect plain 6x86s (and other processors without the
+               Page Global Enable feature) against accessing CR4 in
+               set_mtrr_prepare() and set_mtrr_done().
+    19990210   Richard Gooch <rgooch@atnf.csiro.au>
+	       Turned <set_mtrr_up> and <get_mtrr> into function pointers.
+  v1.31
+    19990212   Zoltan Boszormenyi <zboszor@mol.hu>
+               Major rewrite of cyrix_arr_init(): do not touch ARRs,
+               leave them as the BIOS have set them up.
+               Enable usage of all 8 ARRs.
+               Avoid multiplications by 3 everywhere and other
+               code clean ups/speed ups.
+    19990213   Zoltan Boszormenyi <zboszor@mol.hu>
+               Set up other Cyrix processors identical to the boot cpu.
+               Since Cyrix don't support Intel APIC, this is l'art pour l'art.
+               Weigh ARRs by size:
+               If size <= 32M is given, set up ARR# we were given.
+               If size >  32M is given, set up ARR7 only if it is free,
+               fail otherwise.
+    19990214   Zoltan Boszormenyi <zboszor@mol.hu>
+               Also check for size >= 256K if we are to set up ARR7,
+               mtrr_add() returns the value it gets from set_mtrr()
+    19990218   Zoltan Boszormenyi <zboszor@mol.hu>
+               Remove Cyrix "coma bug" workaround from here.
+               Moved to linux/arch/i386/kernel/setup.c and
+               linux/include/asm-i386/bugs.h
+    19990228   Richard Gooch <rgooch@atnf.csiro.au>
+	       Added #ifdef CONFIG_DEVFS_FS
+	       Added MTRRIOC_KILL_ENTRY ioctl(2)
+	       Trap for counter underflow in <mtrr_file_del>.
+	       Trap for 4 MiB aligned regions for PPro, stepping <= 7.
+    19990301   Richard Gooch <rgooch@atnf.csiro.au>
+	       Created <get_free_region> hook.
+    19990305   Richard Gooch <rgooch@atnf.csiro.au>
+	       Temporarily disable AMD support now MTRR capability flag is set.
+  v1.32
+    19990308   Zoltan Boszormenyi <zboszor@mol.hu>
+	       Adjust my changes (19990212-19990218) to Richard Gooch's
+	       latest changes. (19990228-19990305)
+  v1.33
+    19990309   Richard Gooch <rgooch@atnf.csiro.au>
+	       Fixed typo in <printk> message.
+    19990310   Richard Gooch <rgooch@atnf.csiro.au>
+	       Support K6-II/III based on Alan Cox's <alan@redhat.com> patches.
+  v1.34
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -163,11 +227,12 @@
 #include <asm/segment.h>
 #include <asm/bitops.h>
 #include <asm/atomic.h>
+#include <asm/msr.h>
 
 #include <asm/hardirq.h>
 #include "irq.h"
 
-#define MTRR_VERSION            "1.26 (19981001)"
+#define MTRR_VERSION            "1.34 (19990310)"
 
 #define TRUE  1
 #define FALSE 0
@@ -197,7 +262,7 @@
 #  define MTRR_CHANGE_MASK_DEFTYPE   0x04
 #endif
 
-/* In the processor's MTRR interface, the MTRR type is always held in
+/* In the Intel processor's MTRR interface, the MTRR type is always held in
    an 8 bit field: */
 typedef u8 mtrr_type;
 
@@ -207,9 +272,12 @@
 #ifdef __SMP__
 #  define set_mtrr(reg,base,size,type) set_mtrr_smp (reg, base, size, type)
 #else
-#  define set_mtrr(reg,base,size,type) set_mtrr_up (reg, base, size, type,TRUE)
+#  define set_mtrr(reg,base,size,type) (*set_mtrr_up) (reg, base, size, type, \
+						       TRUE)
 #endif
 
+#define spin_lock_reschedule(lock) while (!spin_trylock(lock)) schedule ();
+
 #ifndef CONFIG_PROC_FS
 #  define compute_ascii() while (0)
 #endif
@@ -233,49 +301,30 @@
     unsigned long deftype_lo;
     unsigned long deftype_hi;
     unsigned long cr4val;
+    unsigned long ccr3;
 };
 
-/*
- * Access to machine-specific registers (available on 586 and better only)
- * Note: the rd* operations modify the parameters directly (without using
- * pointer indirection), this allows gcc to optimize better
- */
-#define rdmsr(msr,val1,val2) \
-       __asm__ __volatile__("rdmsr" \
-			    : "=a" (val1), "=d" (val2) \
-			    : "c" (msr))
-
-#define wrmsr(msr,val1,val2) \
-     __asm__ __volatile__("wrmsr" \
-			  : /* no outputs */ \
-			  : "c" (msr), "a" (val1), "d" (val2))
-
-#define rdtsc(low,high) \
-     __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
-
-#define rdpmc(counter,low,high) \
-     __asm__ __volatile__("rdpmc" \
-			  : "=a" (low), "=d" (high) \
-			  : "c" (counter))
-
 
-/* Put the processor into a state where MTRRs can be safely set. */
-static void set_mtrr_prepare(struct set_mtrr_context *ctxt)
+/*  Put the processor into a state where MTRRs can be safely set  */
+static void set_mtrr_prepare (struct set_mtrr_context *ctxt)
 {
     unsigned long tmp;
 
-    /* disable interrupts locally */
+    /*  Disable interrupts locally  */
     __save_flags (ctxt->flags); __cli ();
 
-    /* save value of CR4 and clear Page Global Enable (bit 7) */
-    asm volatile ("movl  %%cr4, %0\n\t"
-		  "movl  %0, %1\n\t"
-		  "andb  $0x7f, %b1\n\t"
-		  "movl  %1, %%cr4\n\t"
-                  : "=r" (ctxt->cr4val), "=q" (tmp) : : "memory");
+    if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) return;
 
-    /* disable and flush caches. Note that wbinvd flushes the TLBs as
-       a side-effect. */
+    /*  Save value of CR4 and clear Page Global Enable (bit 7)  */
+    if (boot_cpu_data.x86_capability & X86_FEATURE_PGE)
+	asm volatile ("movl  %%cr4, %0\n\t"
+		      "movl  %0, %1\n\t"
+		      "andb  $0x7f, %b1\n\t"
+		      "movl  %1, %%cr4\n\t"
+		      : "=r" (ctxt->cr4val), "=q" (tmp) : : "memory");
+
+    /*  Disable and flush caches. Note that wbinvd flushes the TLBs as
+	a side-effect  */
     asm volatile ("movl  %%cr0, %0\n\t"
 		  "orl   $0x40000000, %0\n\t"
 		  "wbinvd\n\t"
@@ -283,64 +332,108 @@
 		  "wbinvd\n\t"
 		  : "=r" (tmp) : : "memory");
 
-    /* disable MTRRs, and set the default type to uncached. */
-    rdmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
-    wrmsr(MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	/*  Disable MTRRs, and set the default type to uncached  */
+	rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+	wrmsr (MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);
+	break;
+      case X86_VENDOR_CYRIX:
+	tmp = getCx86 (CX86_CCR3);
+	setCx86 (CX86_CCR3, (tmp & 0x0f) | 0x10);
+	ctxt->ccr3 = tmp;
+	break;
+    }
 }   /*  End Function set_mtrr_prepare  */
 
-
-/* Restore the processor after a set_mtrr_prepare */
-static void set_mtrr_done(struct set_mtrr_context *ctxt)
+/*  Restore the processor after a set_mtrr_prepare  */
+static void set_mtrr_done (struct set_mtrr_context *ctxt)
 {
     unsigned long tmp;
 
-    /* flush caches and TLBs */
+    if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
+    {
+	__restore_flags (ctxt->flags);
+	return;
+    }
+
+    /*  Flush caches and TLBs  */
     asm volatile ("wbinvd" : : : "memory" );
 
-    /* restore MTRRdefType */
-    wrmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+    /*  Restore MTRRdefType  */
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	wrmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
+	break;
+      case X86_VENDOR_CYRIX:
+	setCx86 (CX86_CCR3, ctxt->ccr3);
+	break;
+    }
 
-    /* enable caches */
+    /*  Enable caches  */
     asm volatile ("movl  %%cr0, %0\n\t"
 		  "andl  $0xbfffffff, %0\n\t"
 		  "movl  %0, %%cr0\n\t"
 		  : "=r" (tmp) : : "memory");
 
-    /* restore value of CR4 */
-    asm volatile ("movl  %0, %%cr4"
-                  : : "r" (ctxt->cr4val) : "memory");
+    /*  Restore value of CR4  */
+    if (boot_cpu_data.x86_capability & X86_FEATURE_PGE)
+	asm volatile ("movl  %0, %%cr4"
+		      : : "r" (ctxt->cr4val) : "memory");
 
-    /* re-enable interrupts locally (if enabled previously) */
+    /*  Re-enable interrupts locally (if enabled previously)  */
     __restore_flags (ctxt->flags);
 }   /*  End Function set_mtrr_done  */
 
-
-/* this function returns the number of variable MTRRs */
+/*  This function returns the number of variable MTRRs  */
 static unsigned int get_num_var_ranges (void)
 {
     unsigned long config, dummy;
 
-    rdmsr(MTRRcap_MSR, config, dummy);
-    return (config & 0xff);
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	rdmsr (MTRRcap_MSR, config, dummy);
+	return (config & 0xff);
+	/*break;*/
+      case X86_VENDOR_CYRIX:
+	/*  Cyrix have 8 ARRs */
+	return 8;
+	/*break;*/
+      case X86_VENDOR_AMD:
+	return 2;
+	/*break;*/
+    }
+    return 0;
 }   /*  End Function get_num_var_ranges  */
 
-
-/* non-zero if we have the write-combining memory type. */
+/*  Returns non-zero if we have the write-combining memory type  */
 static int have_wrcomb (void)
 {
     unsigned long config, dummy;
 
-    rdmsr(MTRRcap_MSR, config, dummy);
-    return (config & (1<<10));
-}
-
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	rdmsr (MTRRcap_MSR, config, dummy);
+	return (config & (1<<10));
+	/*break;*/
+      case X86_VENDOR_CYRIX:
+      case X86_VENDOR_AMD:
+	return 1;
+	/*break;*/
+    }
+    return 0;
+}   /*  End Function have_wrcomb  */
 
-static void get_mtrr (unsigned int reg, unsigned long *base,
-		      unsigned long *size, mtrr_type *type)
+static void intel_get_mtrr (unsigned int reg, unsigned long *base,
+			    unsigned long *size, mtrr_type *type)
 {
     unsigned long dummy, mask_lo, base_lo;
 
-    rdmsr(MTRRphysMask_MSR(reg), mask_lo, dummy);
+    rdmsr (MTRRphysMask_MSR(reg), mask_lo, dummy);
     if ((mask_lo & 0x800) == 0) {
 	/* Invalid (i.e. free) range. */
 	*base = 0;
@@ -364,11 +457,104 @@
 
     *base = (base_lo & 0xfffff000UL);
     *type = (base_lo & 0xff);
-}   /*  End Function get_mtrr  */
+}   /*  End Function intel_get_mtrr  */
+
+static void cyrix_get_arr (unsigned int reg, unsigned long *base,
+			   unsigned long *size, mtrr_type *type)
+{
+    unsigned long flags;
+    unsigned char arr, ccr3, rcr, shift;
+
+    arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
 
+    /* Save flags and disable interrupts */
+    __save_flags (flags); __cli ();
 
-static void set_mtrr_up (unsigned int reg, unsigned long base,
-			 unsigned long size, mtrr_type type, int do_safe)
+    ccr3 = getCx86 (CX86_CCR3);
+    setCx86 (CX86_CCR3, (ccr3 & 0x0f) | 0x10);		/* enable MAPEN */
+    ((unsigned char *) base)[3]  = getCx86 (arr);
+    ((unsigned char *) base)[2]  = getCx86 (arr+1);
+    ((unsigned char *) base)[1]  = getCx86 (arr+2);
+    rcr = getCx86(CX86_RCR_BASE + reg);
+    setCx86 (CX86_CCR3, ccr3);				/* disable MAPEN */
+
+    /* Enable interrupts if it was enabled previously */
+    __restore_flags (flags);
+    
+    shift = ((unsigned char *) base)[1] & 0x0f;
+    *base &= 0xfffff000UL;
+
+    /* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7
+     * Note: shift==0xf means 4G, this is unsupported.
+     */
+    if (shift)
+      *size = (reg < 7 ? 0x800UL : 0x20000UL) << shift;
+    else
+      *size = 0;
+
+    /* Bit 0 is Cache Enable on ARR7, Cache Disable on ARR0-ARR6 */
+    if (reg < 7) {
+      switch (rcr) {
+	case  1: *type = MTRR_TYPE_UNCACHABLE; break;
+	case  8: *type = MTRR_TYPE_WRBACK;     break;
+	case  9: *type = MTRR_TYPE_WRCOMB;     break;
+	case 24:
+	default: *type = MTRR_TYPE_WRTHROUGH;  break;
+      }
+    } else {
+      switch (rcr) {
+	case  0: *type = MTRR_TYPE_UNCACHABLE; break;
+	case  8: *type = MTRR_TYPE_WRCOMB;     break;
+	case  9: *type = MTRR_TYPE_WRBACK;     break;
+	case 25:
+	default: *type = MTRR_TYPE_WRTHROUGH;  break;
+      }
+    }
+}   /*  End Function cyrix_get_arr  */
+
+static void amd_get_mtrr (unsigned int reg, unsigned long *base,
+			  unsigned long *size, mtrr_type *type)
+{
+    unsigned long low, high;
+
+    rdmsr (0xC0000085, low, high);
+    /*  Upper dword is region 1, lower is region 0  */
+    if (reg == 1) low = high;
+    /*  The base masks off on the right alignment  */
+    *base = low & 0xFFFE0000;
+    *type = 0;
+    if (low & 1) *type = MTRR_TYPE_UNCACHABLE;
+    if (low & 2) *type = MTRR_TYPE_WRCOMB;
+    if ( !(low & 3) )
+    {
+	*size = 0;
+	return;
+    }
+    /*
+     *	This needs a little explaining. The size is stored as an
+     *	inverted mask of bits of 128K granularity 15 bits long offset
+     *	2 bits
+     *
+     *	So to get a size we do invert the mask and add 1 to the lowest
+     *	mask bit (4 as its 2 bits in). This gives us a size we then shift
+     *	to turn into 128K blocks
+     *
+     *	eg		111 1111 1111 1100      is 512K
+     *
+     *	invert		000 0000 0000 0011
+     *	+1		000 0000 0000 0100
+     *	*128K	...
+     */
+    low = (~low) & 0x1FFFC;
+    *size = (low + 4) << 15;
+    return;
+}   /*  End Function amd_get_mtrr  */
+
+static void (*get_mtrr) (unsigned int reg, unsigned long *base,
+			 unsigned long *size, mtrr_type *type) = NULL;
+
+static void intel_set_mtrr_up (unsigned int reg, unsigned long base,
+			       unsigned long size, mtrr_type type, int do_safe)
 /*  [SUMMARY] Set variable MTRR register on the local CPU.
     <reg> The register to set.
     <base> The base address of the region.
@@ -376,6 +562,7 @@
     <type> The type of the region.
     <do_safe> If TRUE, do the change safely. If FALSE, safety measures should
     be done externally.
+    [RETURNS] Nothing.
 */
 {
     struct set_mtrr_context ctxt;
@@ -393,8 +580,92 @@
 	wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0);
     }
     if (do_safe) set_mtrr_done (&ctxt);
-}   /*  End Function set_mtrr_up  */
+}   /*  End Function intel_set_mtrr_up  */
+
+static void cyrix_set_arr_up (unsigned int reg, unsigned long base,
+			      unsigned long size, mtrr_type type, int do_safe)
+{
+    struct set_mtrr_context ctxt;
+    unsigned char arr, arr_type, arr_size;
+
+    arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
+
+    /* count down from 32M (ARR0-ARR6) or from 2G (ARR7) */
+    size >>= (reg < 7 ? 12 : 18);
+    size &= 0x7fff; /* make sure arr_size <= 14 */
+    for(arr_size = 0; size; arr_size++, size >>= 1);
+
+    if (reg<7) {
+      switch (type) {
+	case MTRR_TYPE_UNCACHABLE:	arr_type =  1; break;
+	case MTRR_TYPE_WRCOMB:		arr_type =  9; break;
+	case MTRR_TYPE_WRTHROUGH:	arr_type = 24; break;
+	default:			arr_type =  8; break;
+      }
+    } else {
+      switch (type) {
+	case MTRR_TYPE_UNCACHABLE:	arr_type =  0; break;
+	case MTRR_TYPE_WRCOMB:		arr_type =  8; break;
+	case MTRR_TYPE_WRTHROUGH:	arr_type = 25; break;
+	default:			arr_type =  9; break;
+      }
+    }
+
+    if (do_safe) set_mtrr_prepare (&ctxt);
+    setCx86(arr,    ((unsigned char *) &base)[3]);
+    setCx86(arr+1,  ((unsigned char *) &base)[2]);
+    setCx86(arr+2, (((unsigned char *) &base)[1]) | arr_size);
+    setCx86(CX86_RCR_BASE + reg, arr_type);
+    if (do_safe) set_mtrr_done (&ctxt);
+}   /*  End Function cyrix_set_arr_up  */
+
+static void amd_set_mtrr_up (unsigned int reg, unsigned long base,
+			     unsigned long size, mtrr_type type, int do_safe)
+/*  [SUMMARY] Set variable MTRR register on the local CPU.
+    <reg> The register to set.
+    <base> The base address of the region.
+    <size> The size of the region. If this is 0 the region is disabled.
+    <type> The type of the region.
+    <do_safe> If TRUE, do the change safely. If FALSE, safety measures should
+    be done externally.
+    [RETURNS] Nothing.
+*/
+{
+    u32 low, high;
+    struct set_mtrr_context ctxt;
+
+    if (do_safe) set_mtrr_prepare (&ctxt);
+    /*
+     *	Low is MTRR0 , High MTRR 1
+     */
+    rdmsr (0xC0000085, low, high);
+    /*
+     *	Blank to disable
+     */
+    if (size == 0)
+	*(reg ? &high : &low) = 0;
+    else
+	/* Set the register to the base (already shifted for us), the
+	   type (off by one) and an inverted bitmask of the size
+        	   
+	   The size is the only odd bit. We are fed say 512K
+	   We invert this and we get 111 1111 1111 1011 but
+	   if you subtract one and invert you get the desired
+	   111 1111 1111 1100 mask 
+	   */
+	*(reg ? &high : &low)=(((~(size-1))>>15)&0x0001FFFC)|base|(type+1);
+    /*
+     *	The writeback rule is quite specific. See the manual. Its
+     *	disable local interrupts, write back the cache, set the mtrr
+     */
+    __asm__ __volatile__ ("wbinvd" : : : "memory");
+    wrmsr (0xC0000085, low, high);
+    if (do_safe) set_mtrr_done (&ctxt);
+}   /*  End Function amd_set_mtrr_up  */
 
+static void (*set_mtrr_up) (unsigned int reg, unsigned long base,
+			    unsigned long size, mtrr_type type,
+			    int do_safe) = NULL;
      
 #ifdef __SMP__
 
@@ -407,7 +678,7 @@
 };
 
 
-/* Get the MSR pair relating to a var range. */
+/*  Get the MSR pair relating to a var range  */
 __initfunc(static void get_mtrr_var_range (unsigned int index,
 					   struct mtrr_var_range *vr))
 {
@@ -416,8 +687,8 @@
 }   /*  End Function get_mtrr_var_range  */
 
 
-/* Set the MSR pair relating to a var range. Returns TRUE if
-   changes are made. */
+/*  Set the MSR pair relating to a var range. Returns TRUE if
+    changes are made  */
 __initfunc(static int set_mtrr_var_range_testing (unsigned int index,
 						  struct mtrr_var_range *vr))
 {
@@ -441,8 +712,7 @@
     }
     
     return changed;
-}
-
+}   /*  End Function set_mtrr_var_range_testing  */
 
 __initfunc(static void get_fixed_ranges(mtrr_type *frs))
 {
@@ -456,8 +726,7 @@
  
     for (i = 0; i < 8; i++)
 	rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]);
-}
-
+}   /*  End Function get_fixed_ranges  */
 
 __initfunc(static int set_fixed_ranges_testing(mtrr_type *frs))
 {
@@ -487,10 +756,8 @@
 	    changed = TRUE;
 	}
     }
-
     return changed;
-}
-
+}   /*  End Function set_fixed_ranges_testing  */
 
 struct mtrr_state
 {
@@ -502,7 +769,7 @@
 };
 
 
-/* Grab all of the MTRR state for this CPU into *state. */
+/*  Grab all of the MTRR state for this CPU into *state  */
 __initfunc(static void get_mtrr_state(struct mtrr_state *state))
 {
     unsigned int nvrs, i;
@@ -511,22 +778,22 @@
 
     nvrs = state->num_var_ranges = get_num_var_ranges();
     vrs = state->var_ranges 
-              = kmalloc(nvrs * sizeof(struct mtrr_var_range), GFP_KERNEL);
+              = kmalloc (nvrs * sizeof (struct mtrr_var_range), GFP_KERNEL);
     if (vrs == NULL)
 	nvrs = state->num_var_ranges = 0;
 
     for (i = 0; i < nvrs; i++)
-	get_mtrr_var_range(i, &vrs[i]);
+	get_mtrr_var_range (i, &vrs[i]);
     
-    get_fixed_ranges(state->fixed_ranges);
+    get_fixed_ranges (state->fixed_ranges);
 
-    rdmsr(MTRRdefType_MSR, lo, dummy);
+    rdmsr (MTRRdefType_MSR, lo, dummy);
     state->def_type = (lo & 0xff);
     state->enabled = (lo & 0xc00) >> 10;
 }   /*  End Function get_mtrr_state  */
 
 
-/* Free resources associated with a struct mtrr_state */
+/*  Free resources associated with a struct mtrr_state  */
 __initfunc(static void finalize_mtrr_state(struct mtrr_state *state))
 {
     if (state->var_ranges) kfree (state->var_ranges);
@@ -546,14 +813,14 @@
     unsigned long change_mask = 0;
 
     for (i = 0; i < state->num_var_ranges; i++)
-	if (set_mtrr_var_range_testing(i, &state->var_ranges[i]))
+	if ( set_mtrr_var_range_testing (i, &state->var_ranges[i]) )
 	    change_mask |= MTRR_CHANGE_MASK_VARIABLE;
 
-    if (set_fixed_ranges_testing(state->fixed_ranges))
+    if ( set_fixed_ranges_testing(state->fixed_ranges) )
 	change_mask |= MTRR_CHANGE_MASK_FIXED;
     
-    /* set_mtrr_restore restores the old value of MTRRdefType,
-       so to set it we fiddle with the saved value. */
+    /*  Set_mtrr_restore restores the old value of MTRRdefType,
+	so to set it we fiddle with the saved value  */
     if ((ctxt->deftype_lo & 0xff) != state->def_type
 	|| ((ctxt->deftype_lo & 0xc00) >> 10) != state->enabled)
     {
@@ -566,76 +833,63 @@
 
  
 static atomic_t undone_count;
-static void (*handler_func) (struct set_mtrr_context *ctxt, void *info);
-static void *handler_info;
 static volatile int wait_barrier_execute = FALSE;
 static volatile int wait_barrier_cache_enable = FALSE;
 
-static void sync_handler (void)
+struct set_mtrr_data
+{
+    unsigned long smp_base;
+    unsigned long smp_size;
+    unsigned int smp_reg;
+    mtrr_type smp_type;
+};
+
+static void ipi_handler (void *info)
 /*  [SUMMARY] Synchronisation handler. Executed by "other" CPUs.
     [RETURNS] Nothing.
 */
 {
+    struct set_mtrr_data *data = info;
     struct set_mtrr_context ctxt;
 
     set_mtrr_prepare (&ctxt);
-    /*  Notify master CPU that I'm at the barrier and then wait  */
+    /*  Notify master that I've flushed and disabled my cache  */
     atomic_dec (&undone_count);
     while (wait_barrier_execute) barrier ();
     /*  The master has cleared me to execute  */
-    (*handler_func) (&ctxt, handler_info);
+    (*set_mtrr_up) (data->smp_reg, data->smp_base, data->smp_size,
+		    data->smp_type, FALSE);
     /*  Notify master CPU that I've executed the function  */
     atomic_dec (&undone_count);
     /*  Wait for master to clear me to enable cache and return  */
     while (wait_barrier_cache_enable) barrier ();
     set_mtrr_done (&ctxt);
-}   /*  End Function sync_handler  */
+}   /*  End Function ipi_handler  */
 
-static void do_all_cpus (void (*handler) (struct set_mtrr_context *ctxt,
-					  void *info),
-			 void *info, int local)
-/*  [SUMMARY] Execute a function on all CPUs, with caches flushed and disabled.
-    [PURPOSE] This function will synchronise all CPUs, flush and disable caches
-    on all CPUs, then call a specified function. When the specified function
-    finishes on all CPUs, caches are enabled on all CPUs.
-    <handler> The function to execute.
-    <info> An arbitrary information pointer which is passed to <<handler>>.
-    <local> If TRUE <<handler>> is executed locally.
-    [RETURNS] Nothing.
-*/
+static void set_mtrr_smp (unsigned int reg, unsigned long base,
+			  unsigned long size, mtrr_type type)
 {
-    unsigned long timeout;
+    struct set_mtrr_data data;
     struct set_mtrr_context ctxt;
 
-    mtrr_hook = sync_handler;
-    handler_func = handler;
-    handler_info = info;
+    data.smp_reg = reg;
+    data.smp_base = base;
+    data.smp_size = size;
+    data.smp_type = type;
     wait_barrier_execute = TRUE;
     wait_barrier_cache_enable = TRUE;
-    /*  Send a message to all other CPUs and wait for them to enter the
-	barrier  */
     atomic_set (&undone_count, smp_num_cpus - 1);
-    smp_send_mtrr();
-    /*  Wait for it to be done  */
-    timeout = jiffies + JIFFIE_TIMEOUT;
-    while ( (atomic_read (&undone_count) > 0) &&
-	    time_before(jiffies, timeout) )
-	barrier ();
-    if (atomic_read (&undone_count) > 0)
-    {
+    /*  Flush and disable the local CPU's cache	and start the ball rolling on
+	other CPUs  */
+    set_mtrr_prepare (&ctxt);
+    if (smp_call_function (ipi_handler, &data, 1, 0) != 0)
 	panic ("mtrr: timed out waiting for other CPUs\n");
-    }
-    mtrr_hook = NULL;
-    /*  All other CPUs should be waiting for the barrier, with their caches
-	already flushed and disabled. Prepare for function completion
-	notification  */
+    /*  Wait for all other CPUs to flush and disable their caches  */
+    while (atomic_read (&undone_count) > 0) barrier ();
+    /* Set up for completion wait and then release other CPUs to change MTRRs*/
     atomic_set (&undone_count, smp_num_cpus - 1);
-    /*  Flush and disable the local CPU's cache	and release the barier, which
-	should cause the other CPUs to execute the function. Also execute it
-	locally if required  */
-    set_mtrr_prepare (&ctxt);
     wait_barrier_execute = FALSE;
-    if (local) (*handler) (&ctxt, info);
+    (*set_mtrr_up) (reg, base, size, type, FALSE);
     /*  Now wait for other CPUs to complete the function  */
     while (atomic_read (&undone_count) > 0) barrier ();
     /*  Now all CPUs should have finished the function. Release the barrier to
@@ -643,41 +897,10 @@
 	then enable the local cache and return  */
     wait_barrier_cache_enable = FALSE;
     set_mtrr_done (&ctxt);
-    handler_func = NULL;
-    handler_info = NULL;
-}   /*  End Function do_all_cpus  */
-
-
-struct set_mtrr_data
-{
-    unsigned long smp_base;
-    unsigned long smp_size;
-    unsigned int smp_reg;
-    mtrr_type smp_type;
-};
-
-static void set_mtrr_handler (struct set_mtrr_context *ctxt, void *info)
-{
-    struct set_mtrr_data *data = info;
-
-    set_mtrr_up (data->smp_reg, data->smp_base, data->smp_size, data->smp_type,
-		 FALSE);
-}   /*  End Function set_mtrr_handler  */
-
-static void set_mtrr_smp (unsigned int reg, unsigned long base,
-			  unsigned long size, mtrr_type type)
-{
-    struct set_mtrr_data data;
-
-    data.smp_reg = reg;
-    data.smp_base = base;
-    data.smp_size = size;
-    data.smp_type = type;
-    do_all_cpus (set_mtrr_handler, &data, TRUE);
 }   /*  End Function set_mtrr_smp  */
 
 
-/* Some BIOS's are fucked and don't set all MTRRs the same! */
+/*  Some BIOS's are fucked and don't set all MTRRs the same!  */
 __initfunc(static void mtrr_state_warn (unsigned long mask))
 {
     if (!mask) return;
@@ -720,6 +943,58 @@
 #endif
 }   /*  End Function init_table  */
 
+static int generic_get_free_region (unsigned long base, unsigned long size)
+/*  [SUMMARY] Get a free MTRR.
+    <base> The starting (base) address of the region.
+    <size> The size (in bytes) of the region.
+    [RETURNS] The index of the region on success, else -1 on error.
+*/
+{
+    int i, max;
+    mtrr_type ltype;
+    unsigned long lbase, lsize;
+
+    max = get_num_var_ranges ();
+    for (i = 0; i < max; ++i)
+    {
+	(*get_mtrr) (i, &lbase, &lsize, &ltype);
+	if (lsize < 1) return i;
+    }
+    return -ENOSPC;
+}   /*  End Function generic_get_free_region  */
+
+static int cyrix_get_free_region (unsigned long base, unsigned long size)
+/*  [SUMMARY] Get a free ARR.
+    <base> The starting (base) address of the region.
+    <size> The size (in bytes) of the region.
+    [RETURNS] The index of the region on success, else -1 on error.
+*/
+{
+    int i;
+    mtrr_type ltype;
+    unsigned long lbase, lsize;
+
+    /* If we are to set up a region >32M then look at ARR7 immediately */
+    if (size > 0x2000000UL) {
+	cyrix_get_arr (7, &lbase, &lsize, &ltype);
+	if (lsize < 1) return 7;
+    /* else try ARR0-ARR6 first */
+    } else {
+	for (i = 0; i < 7; i++)
+	{
+	    cyrix_get_arr (i, &lbase, &lsize, &ltype);
+	    if (lsize < 1) return i;
+	}
+	/* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */
+	cyrix_get_arr (i, &lbase, &lsize, &ltype);
+	if ((lsize < 1) && (size >= 0x40000)) return i;
+    }
+    return -ENOSPC;
+}   /*  End Function cyrix_get_free_region  */
+
+static int (*get_free_region) (unsigned long base,
+			       unsigned long size) = generic_get_free_region;
+
 int mtrr_add (unsigned long base, unsigned long size, unsigned int type,
 	      char increment)
 /*  [SUMMARY] Add an MTRR entry.
@@ -738,28 +1013,57 @@
     unsigned long lbase, lsize, last;
 
     if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
-    if ( (base & 0xfff) || (size & 0xfff) )
-    {
-	printk ("mtrr: size and base must be multiples of 4kB\n");
-	printk ("mtrr: size: %lx  base: %lx\n", size, base);
-	return -EINVAL;
-    }
-    if (base + size < 0x100000)
-    {
-	printk ("mtrr: cannot set region below 1 MByte (0x%lx,0x%lx)\n",
-		base, size);
-	return -EINVAL;
-    }
-    /*  Check upper bits of base and last are equal and lower bits are 0 for
-	base and 1 for last  */
-    last = base + size - 1;
-    for (lbase = base; !(lbase & 1) && (last & 1);
-	 lbase = lbase >> 1, last = last >> 1);
-    if (lbase != last)
+    switch (boot_cpu_data.x86_vendor)
     {
-	printk ("mtrr: base(0x%lx) is not aligned on a size(0x%lx) boundary\n",
-		base, size);
+      case X86_VENDOR_INTEL:
+	/*  For Intel PPro stepping <= 7, must be 4 MiB aligned  */
+	if ( (boot_cpu_data.x86 == 6) && (boot_cpu_data.x86_model == 1) &&
+	     (boot_cpu_data.x86_mask <= 7) && ( base & ( (1 << 22) - 1 ) ) )
+	{
+	    printk ("mtrr: base(0x%lx) is not 4 MiB aligned\n", base);
+	    return -EINVAL;
+	}
+	/*  Fall through  */
+      case X86_VENDOR_CYRIX:
+	if ( (base & 0xfff) || (size & 0xfff) )
+	{
+	    printk ("mtrr: size and base must be multiples of 4 kiB\n");
+	    printk ("mtrr: size: %lx  base: %lx\n", size, base);
+	    return -EINVAL;
+	}
+	if (base + size < 0x100000)
+	{
+	    printk ("mtrr: cannot set region below 1 MiB (0x%lx,0x%lx)\n",
+		    base, size);
+	    return -EINVAL;
+	}
+	/*  Check upper bits of base and last are equal and lower bits are 0
+	    for base and 1 for last  */
+	last = base + size - 1;
+	for (lbase = base; !(lbase & 1) && (last & 1);
+	     lbase = lbase >> 1, last = last >> 1);
+	if (lbase != last)
+	{
+	    printk ("mtrr: base(0x%lx) is not aligned on a size(0x%lx) boundary\n",
+		    base, size);
+	    return -EINVAL;
+	}
+	break;
+      case X86_VENDOR_AMD:
+    	/* Apply the K6 block alignment and size rules 
+    	   In order
+    	      o Uncached or gathering only
+    	      o 128K or bigger block
+    	      o Power of 2 block
+    	      o base suitably aligned to the power
+    	  */
+    	if (type > MTRR_TYPE_WRCOMB || size < (1 << 17) ||
+	    (size & ~(size-1))-size || (base & (size-1)))
+	    return -EINVAL;
+	break;
+      default:
 	return -EINVAL;
+	/*break;*/
     }
     if (type >= MTRR_NUM_TYPES)
     {
@@ -775,10 +1079,10 @@
     increment = increment ? 1 : 0;
     max = get_num_var_ranges ();
     /*  Search for existing MTRR  */
-    spin_lock (&main_lock);
+    spin_lock_reschedule (&main_lock);
     for (i = 0; i < max; ++i)
     {
-	get_mtrr (i, &lbase, &lsize, &ltype);
+	(*get_mtrr) (i, &lbase, &lsize, &ltype);
 	if (base >= lbase + lsize) continue;
 	if ( (base < lbase) && (base + size <= lbase) ) continue;
 	/*  At this point we know there is some kind of overlap/enclosure  */
@@ -804,19 +1108,18 @@
 	return i;
     }
     /*  Search for an empty MTRR  */
-    for (i = 0; i < max; ++i)
+    i = (*get_free_region) (base, size);
+    if (i < 0)
     {
-	get_mtrr (i, &lbase, &lsize, &ltype);
-	if (lsize > 0) continue;
-	set_mtrr (i, base, size, type);
-	usage_table[i] = 1;
-	compute_ascii ();
 	spin_unlock (&main_lock);
+	printk ("mtrr: no more MTRRs available\n");
 	return i;
     }
+    set_mtrr (i, base, size, type);
+    usage_table[i] = 1;
+    compute_ascii ();
     spin_unlock (&main_lock);
-    printk ("mtrr: no more MTRRs available\n");
-    return -ENOSPC;
+    return i;
 }   /*  End Function mtrr_add  */
 
 int mtrr_del (int reg, unsigned long base, unsigned long size)
@@ -836,13 +1139,13 @@
 
     if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
     max = get_num_var_ranges ();
-    spin_lock (&main_lock);
+    spin_lock_reschedule (&main_lock);
     if (reg < 0)
     {
 	/*  Search for existing MTRR  */
 	for (i = 0; i < max; ++i)
 	{
-	    get_mtrr (i, &lbase, &lsize, &ltype);
+	    (*get_mtrr) (i, &lbase, &lsize, &ltype);
 	    if ( (lbase == base) && (lsize == size) )
 	    {
 		reg = i;
@@ -862,7 +1165,7 @@
 	printk ("mtrr: register: %d too big\n", reg);
 	return -EINVAL;
     }
-    get_mtrr (reg, &lbase, &lsize, &ltype);
+    (*get_mtrr) (reg, &lbase, &lsize, &ltype);
     if (lsize < 1)
     {
 	spin_unlock (&main_lock);
@@ -913,7 +1216,9 @@
 
     reg = mtrr_del (-1, base, size);
     if (reg < 0) return reg;
-    if (fcount != NULL) --fcount[reg];
+    if (fcount == NULL) return reg;
+    if (fcount[reg] < 1) return -EINVAL;
+    --fcount[reg];
     return reg;
 }   /*  End Function mtrr_file_del  */
 
@@ -1019,11 +1324,18 @@
 	err = mtrr_file_del (sentry.base, sentry.size, file);
 	if (err < 0) return err;
 	break;
+      case MTRRIOC_KILL_ENTRY:
+	if ( !suser () ) return -EPERM;
+	if ( copy_from_user (&sentry, (void *) arg, sizeof sentry) )
+	    return -EFAULT;
+	err = mtrr_del (-1, sentry.base, sentry.size);
+	if (err < 0) return err;
+	break;
       case MTRRIOC_GET_ENTRY:
 	if ( copy_from_user (&gentry, (void *) arg, sizeof gentry) )
 	    return -EFAULT;
 	if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL;
-	get_mtrr (gentry.regnum, &gentry.base, &gentry.size, &type);
+	(*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type);
 	gentry.type = type;
 	if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) )
 	     return -EFAULT;
@@ -1115,7 +1427,7 @@
     max = get_num_var_ranges ();
     for (i = 0; i < max; i++)
     {
-	get_mtrr (i, &base, &size, &type);
+	(*get_mtrr) (i, &base, &size, &type);
 	if (size < 1) usage_table[i] = 0;
 	else
 	{
@@ -1148,23 +1460,165 @@
 
 #ifdef __SMP__
 
+typedef struct {
+  unsigned long base;
+  unsigned long size;
+  mtrr_type type;
+} arr_state_t;
+
+arr_state_t arr_state[8] __initdata = {
+  {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL},
+  {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}, {0UL,0UL,0UL}
+};
+
+unsigned char ccr_state[7] __initdata = { 0, 0, 0, 0, 0, 0, 0 };
+
+__initfunc(static void cyrix_arr_init_secondary(void))
+{
+    struct set_mtrr_context ctxt;
+    int i;
+
+    set_mtrr_prepare (&ctxt); /* flush cache and enable MAPEN */
+
+     /* the CCRs are not contiguous */
+    for(i=0; i<4; i++) setCx86(CX86_CCR0 + i, ccr_state[i]);
+    for(   ; i<7; i++) setCx86(CX86_CCR4 + i, ccr_state[i]);
+    for(i=0; i<8; i++)
+      cyrix_set_arr_up(i,
+        arr_state[i].base, arr_state[i].size, arr_state[i].type, FALSE);
+
+    set_mtrr_done (&ctxt); /* flush cache and disable MAPEN */
+}   /*  End Function cyrix_arr_init_secondary  */
+
+#endif
+
+/*
+ * On Cyrix 6x86(MX) and M II the ARR3 is special: it has connection
+ * with the SMM (System Management Mode) mode. So we need the following:
+ * Check whether SMI_LOCK (CCR3 bit 0) is set
+ *   if it is set, write a warning message: ARR3 cannot be changed!
+ *     (it cannot be changed until the next processor reset)
+ *   if it is reset, then we can change it, set all the needed bits:
+ *   - disable access to SMM memory through ARR3 range (CCR1 bit 7 reset)
+ *   - disable access to SMM memory (CCR1 bit 2 reset)
+ *   - disable SMM mode (CCR1 bit 1 reset)
+ *   - disable write protection of ARR3 (CCR6 bit 1 reset)
+ *   - (maybe) disable ARR3
+ * Just to be sure, we enable ARR usage by the processor (CCR5 bit 5 set)
+ */
+__initfunc(static void cyrix_arr_init(void))
+{
+    struct set_mtrr_context ctxt;
+    unsigned char ccr[7];
+    int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 };
+#ifdef __SMP__
+    int i;
+#endif
+
+    set_mtrr_prepare (&ctxt); /* flush cache and enable MAPEN */
+
+    /* Save all CCRs locally */
+    ccr[0] = getCx86 (CX86_CCR0);
+    ccr[1] = getCx86 (CX86_CCR1);
+    ccr[2] = getCx86 (CX86_CCR2);
+    ccr[3] = ctxt.ccr3;
+    ccr[4] = getCx86 (CX86_CCR4);
+    ccr[5] = getCx86 (CX86_CCR5);
+    ccr[6] = getCx86 (CX86_CCR6);
+
+    if (ccr[3] & 1)
+      ccrc[3] = 1;
+    else {
+      /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and
+       * access to SMM memory through ARR3 (bit 7).
+       */
+/*
+      if (ccr[1] & 0x80) { ccr[1] &= 0x7f; ccrc[1] |= 0x80; }
+      if (ccr[1] & 0x04) { ccr[1] &= 0xfb; ccrc[1] |= 0x04; }
+      if (ccr[1] & 0x02) { ccr[1] &= 0xfd; ccrc[1] |= 0x02; }
+*/
+      if (ccr[6] & 0x02) {
+        ccr[6] &= 0xfd; ccrc[6] = 1; /* Disable write protection of ARR3. */
+        setCx86 (CX86_CCR6, ccr[6]);
+      }
+      /* Disable ARR3. */
+      /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */
+    }
+    /* If we changed CCR1 in memory, change it in the processor, too. */
+    if (ccrc[1]) setCx86 (CX86_CCR1, ccr[1]);
+
+    /* Enable ARR usage by the processor */
+    if (!(ccr[5] & 0x20)) {
+      ccr[5] |= 0x20; ccrc[5] = 1;
+      setCx86 (CX86_CCR5, ccr[5]);
+    }
+
+#ifdef __SMP__
+    for(i=0; i<7; i++) ccr_state[i] = ccr[i];
+    for(i=0; i<8; i++)
+      cyrix_get_arr(i,
+        &arr_state[i].base, &arr_state[i].size, &arr_state[i].type);
+#endif
+
+    set_mtrr_done (&ctxt); /* flush cache and disable MAPEN */
+
+    if ( ccrc[5] ) printk ("mtrr: ARR usage was not enabled, enabled manually\n");
+    if ( ccrc[3] ) printk ("mtrr: ARR3 cannot be changed\n");
+/*
+    if ( ccrc[1] & 0x80) printk ("mtrr: SMM memory access through ARR3 disabled\n");
+    if ( ccrc[1] & 0x04) printk ("mtrr: SMM memory access disabled\n");
+    if ( ccrc[1] & 0x02) printk ("mtrr: SMM mode disabled\n");
+*/
+    if ( ccrc[6] ) printk ("mtrr: ARR3 was write protected, unprotected\n");
+}   /*  End Function cyrix_arr_init  */
+
+__initfunc(static void mtrr_setup (void))
+{
+    printk ("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION);
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	get_mtrr = intel_get_mtrr;
+	set_mtrr_up = intel_set_mtrr_up;
+	break;
+      case X86_VENDOR_CYRIX:
+	printk ("mtrr: Using Cyrix style ARRs\n");
+	get_mtrr = cyrix_get_arr;
+	set_mtrr_up = cyrix_set_arr_up;
+	get_free_region = cyrix_get_free_region;
+	break;
+      case X86_VENDOR_AMD:
+	get_mtrr = amd_get_mtrr;
+	set_mtrr_up = amd_set_mtrr_up;
+	break;
+    }
+}   /*  End Function mtrr_setup  */
+
+#ifdef __SMP__
+
 static volatile unsigned long smp_changes_mask __initdata = 0;
 static struct mtrr_state smp_mtrr_state __initdata = {0, 0};
 
 __initfunc(void mtrr_init_boot_cpu (void))
 {
     if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
-    printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION);
-
-    get_mtrr_state (&smp_mtrr_state);
+    mtrr_setup ();
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	get_mtrr_state (&smp_mtrr_state);
+	break;
+      case X86_VENDOR_CYRIX:
+	cyrix_arr_init ();
+	break;
+    }
 }   /*  End Function mtrr_init_boot_cpu  */
 
-__initfunc(void mtrr_init_secondary_cpu (void))
+__initfunc(static void intel_mtrr_init_secondary_cpu (void))
 {
     unsigned long mask, count;
     struct set_mtrr_context ctxt;
 
-    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
     /*  Note that this is not ideal, since the cache is only flushed/disabled
 	for this CPU while the MTRRs are changed, but changing this requires
 	more invasive changes to the way the kernel boots  */
@@ -1177,21 +1631,52 @@
 	if (mask & 0x01) set_bit (count, &smp_changes_mask);
 	mask >>= 1;
     }
-}   /*  End Function mtrr_init_secondary_cpu  */
+}   /*  End Function intel_mtrr_init_secondary_cpu  */
 
+__initfunc(void mtrr_init_secondary_cpu (void))
+{
+    if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return;
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	intel_mtrr_init_secondary_cpu ();
+	break;
+      case X86_VENDOR_CYRIX:
+	/* This is _completely theoretical_!
+	 * I assume here that one day Cyrix will support Intel APIC.
+	 * In reality on non-Intel CPUs we won't even get to this routine.
+	 * Hopefully no one will plug two Cyrix processors in a dual P5 board.
+	 *  :-)
+	 */
+	cyrix_arr_init_secondary ();
+	break;
+      default:
+	printk ("mtrr: SMP support incomplete for this vendor\n");
+	break;
+    }
+}   /*  End Function mtrr_init_secondary_cpu  */
 #endif  /*  __SMP__  */
 
 __initfunc(int mtrr_init(void))
 {
     if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return 0;
-#  ifndef __SMP__
-    printk("mtrr: v%s Richard Gooch (rgooch@atnf.csiro.au)\n", MTRR_VERSION);
-#  endif
-
 #  ifdef __SMP__
-    finalize_mtrr_state (&smp_mtrr_state);
-    mtrr_state_warn (smp_changes_mask);
-#  endif /* __SMP__ */
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_INTEL:
+	finalize_mtrr_state (&smp_mtrr_state);
+	mtrr_state_warn (smp_changes_mask);
+	break;
+    }
+#  else /* __SMP__ */
+    mtrr_setup ();
+    switch (boot_cpu_data.x86_vendor)
+    {
+      case X86_VENDOR_CYRIX:
+	cyrix_arr_init ();
+	break;
+    }
+#  endif  /*  !__SMP__  */
 
 #  ifdef CONFIG_PROC_FS
     proc_register (&proc_root, &proc_root_mtrr);
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.2.7/linux/arch/i386/kernel/process.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/i386/kernel/process.c	Fri Apr 30 08:13:37 1999
@@ -111,6 +111,8 @@
 	/* endless idle loop with no priority at all */
 	current->priority = 0;
 	current->counter = -100;
+	init_idle();
+
 	for (;;) {
 		if (work)
 			start_idle = jiffies;
@@ -139,6 +141,8 @@
 	/* endless idle loop with no priority at all */
 	current->priority = 0;
 	current->counter = -100;
+	init_idle();
+
 	while(1) {
 		if (current_cpu_data.hlt_works_ok && !hlt_counter &&
 				 !current->need_resched)
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- v2.2.7/linux/arch/i386/kernel/setup.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/i386/kernel/setup.c	Mon May 10 10:32:45 1999
@@ -5,6 +5,10 @@
  *
  *  Enhanced CPU type detection by Mike Jagdis, Patrick St. Jean
  *  and Martin Mares, November 1997.
+ *
+ *  Force Cyrix 6x86(MX) and M II processors to report MTRR capability
+ *  and fix against Cyrix "coma bug" by
+ *      Zoltan Boszormenyi <zboszor@mol.hu> February 1999.
  */
 
 /*
@@ -39,6 +43,7 @@
 #include <asm/io.h>
 #include <asm/smp.h>
 #include <asm/cobalt.h>
+#include <asm/msr.h>
 
 /*
  * Machine setup..
@@ -57,6 +62,7 @@
 unsigned int machine_id = 0;
 unsigned int machine_submodel_id = 0;
 unsigned int BIOS_revision = 0;
+unsigned int mca_pentium_flag = 0;
 
 /*
  * Setup options
@@ -244,11 +250,6 @@
 	unsigned long memory_start, memory_end;
 	char c = ' ', *to = command_line, *from = COMMAND_LINE;
 	int len = 0;
-	static unsigned char smptrap=0;
-
-	if (smptrap)
-		return;
-	smptrap=1;
 
 #ifdef CONFIG_VISWS
 	visws_get_board_type_and_rev();
@@ -381,16 +382,6 @@
 
 }
 
-#define rdmsr(msr,val1,val2) \
-       __asm__ __volatile__("rdmsr" \
-			    : "=a" (val1), "=d" (val2) \
-			    : "c" (msr))
-
-#define wrmsr(msr,val1,val2) \
-     __asm__ __volatile__("wrmsr" \
-			  : /* no outputs */ \
-			  : "c" (msr), "a" (val1), "d" (val2))
-
 __initfunc(static int get_model_name(struct cpuinfo_x86 *c))
 {
 	unsigned int n, dummy, *v;
@@ -408,6 +399,14 @@
 	cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
 	cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
 	c->x86_model_id[48] = 0;
+	/*  Set MTRR capability flag if appropriate  */
+	if(boot_cpu_data.x86 !=5)
+		return 1;
+	if((boot_cpu_data.x86_model == 9) ||
+	   ((boot_cpu_data.x86_model == 8) && 
+	    (boot_cpu_data.x86_mask >= 8)))
+		c->x86_capability |= X86_FEATURE_MTRR;
+
 	return 1;
 }
 
@@ -587,6 +586,10 @@
 			(c->x86_model)++;
 		} else             /* 686 */
 			p = Cx86_cb+1;
+		/* Emulate MTRRs using Cyrix's ARRs. */
+		c->x86_capability |= X86_FEATURE_MTRR;
+		/* 6x86's contain this bug */
+		c->coma_bug = 1;
 		break;
 
 	case 4: /* MediaGX/GXm */
@@ -611,11 +614,14 @@
 
         case 5: /* 6x86MX/M II */
 		if (dir1 > 7) dir0_msn++;  /* M II */
+		else c->coma_bug = 1;      /* 6x86MX, it has the bug. */
 		tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0;
 		Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7];
 		p = Cx86_cb+tmp;
         	if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
 			(c->x86_model)++;
+		/* Emulate MTRRs using Cyrix's ARRs. */
+		c->x86_capability |= X86_FEATURE_MTRR;
 		break;
 
 	case 0xf:  /* Cyrix 486 without DEVID registers */
@@ -869,7 +875,7 @@
 	int sep_bug;
 	static char *x86_cap_flags[] = {
 	        "fpu", "vme", "de", "pse", "tsc", "msr", "6", "mce",
-	        "cx8", "9", "10", "sep", "12", "pge", "14", "cmov",
+	        "cx8", "9", "10", "sep", "mtrr", "pge", "14", "cmov",
 	        "16", "17", "psn", "19", "20", "21", "22", "mmx",
 	        "24", "kni", "26", "27", "28", "29", "30", "31"
 	};
@@ -917,7 +923,6 @@
 		} else if (c->x86_vendor == X86_VENDOR_INTEL) {
 			x86_cap_flags[6] = "pae";
 			x86_cap_flags[9] = "apic";
-			x86_cap_flags[12] = "mtrr";
 			x86_cap_flags[14] = "mca";
 			x86_cap_flags[16] = "pat";
 			x86_cap_flags[17] = "pse36";
@@ -936,6 +941,7 @@
 			        "hlt_bug\t\t: %s\n"
 			        "sep_bug\t\t: %s\n"
 			        "f00f_bug\t: %s\n"
+			        "coma_bug\t: %s\n"
 			        "fpu\t\t: %s\n"
 			        "fpu_exception\t: %s\n"
 			        "cpuid level\t: %d\n"
@@ -945,6 +951,7 @@
 			     c->hlt_works_ok ? "no" : "yes",
 			     sep_bug ? "yes" : "no",
 			     c->f00f_bug ? "yes" : "no",
+			     c->coma_bug ? "yes" : "no",
 			     c->hard_math ? "yes" : "no",
 			     (c->hard_math && ignore_irq13) ? "yes" : "no",
 			     c->cpuid_level,
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.2.7/linux/arch/i386/kernel/smp.c	Wed Apr 28 11:37:29 1999
+++ linux/arch/i386/kernel/smp.c	Mon May 10 10:32:45 1999
@@ -40,10 +40,12 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <asm/mtrr.h>
+#include <asm/msr.h>
 
 #include "irq.h"
 
-extern unsigned long start_kernel;
+#define JIFFIE_TIMEOUT 100
+
 extern void update_one_process( struct task_struct *p,
 				unsigned long ticks, unsigned long user,
 				unsigned long system, int cpu);
@@ -147,16 +149,7 @@
  */
 #define APIC_DEFAULT_PHYS_BASE 0xfee00000
 
-/*
- * Reads and clears the Pentium Timestamp-Counter
- */
-#define READ_TSC(x)	__asm__ __volatile__ (  "rdtsc" \
-				:"=a" (((unsigned long*)&(x))[0]),  \
-				 "=d" (((unsigned long*)&(x))[1]))
-
-#define CLEAR_TSC \
-	__asm__ __volatile__ ("\t.byte 0x0f, 0x30;\n"::\
-		"a"(0x00001000), "d"(0x00001000), "c"(0x10):"memory")
+#define CLEAR_TSC wrmsr(0x10, 0x00001000, 0x00001000)
 
 /*
  *	Setup routine for controlling SMP activation
@@ -899,6 +892,7 @@
  * Everything has been set up for the secondary
  * CPUs - they just need to reload everything
  * from the task structure
+ * This function must not return.
  */
 void __init initialize_secondary(void)
 {
@@ -940,7 +934,6 @@
 	/*
 	 *	We need an idle process for each processor.
 	 */
-
 	kernel_thread(start_secondary, NULL, CLONE_PID);
 	cpucount++;
 
@@ -951,6 +944,8 @@
 	idle->processor = i;
 	__cpu_logical_map[cpucount] = i;
 	cpu_number_map[i] = cpucount;
+	idle->has_cpu = 1; /* we schedule the first task manually */
+	idle->tss.eip = (unsigned long) start_secondary;
 
 	/* start_eip had better be page-aligned! */
 	start_eip = setup_trampoline();
@@ -1183,6 +1178,7 @@
 	/*  Must be done before other processors booted  */
 	mtrr_init_boot_cpu ();
 #endif
+	init_idle();
 	/*
 	 *	Initialize the logical to physical CPU number mapping
 	 *	and the per-CPU profiling counter/multiplier
@@ -1657,15 +1653,84 @@
 	send_IPI_allbutself(STOP_CPU_VECTOR);
 }
 
-/*
- * this function sends an 'reload MTRR state' IPI to all other CPUs
- * in the system. it goes straight through, completion processing
- * is done on the mttr.c level.
+/* Structure and data for smp_call_function(). This is designed to minimise
+ * static memory requirements. It also looks cleaner.
  */
-
-void smp_send_mtrr(void)
+struct smp_call_function_struct {
+	void (*func) (void *info);
+	void *info;
+	atomic_t unstarted_count;
+	atomic_t unfinished_count;
+	int wait;
+};
+static volatile struct smp_call_function_struct *smp_call_function_data = NULL;
+
+/*
+ * this function sends a 'generic call function' IPI to all other CPUs
+ * in the system.
+ */
+
+int smp_call_function (void (*func) (void *info), void *info, int retry,
+		       int wait)
+/*  [SUMMARY] Run a function on all other CPUs.
+    <func> The function to run. This must be fast and non-blocking.
+    <info> An arbitrary pointer to pass to the function.
+    <retry> If true, keep retrying until ready.
+    <wait> If true, wait until function has completed on other CPUs.
+    [RETURNS] 0 on success, else a negative status code. Does not return until
+    remote CPUs are nearly ready to execute <<func>> or are or have executed.
+*/
 {
-	send_IPI_allbutself(MTRR_CHANGE_VECTOR);
+	unsigned long timeout;
+	struct smp_call_function_struct data;
+	static spinlock_t lock = SPIN_LOCK_UNLOCKED;
+
+	if (retry) {
+		while (1) {
+			if (smp_call_function_data) {
+				schedule ();  /*  Give a mate a go  */
+				continue;
+			}
+			spin_lock (&lock);
+			if (smp_call_function_data) {
+				spin_unlock (&lock);  /*  Bad luck  */
+				continue;
+			}
+			/*  Mine, all mine!  */
+			break;
+		}
+	}
+	else {
+		if (smp_call_function_data) return -EBUSY;
+		spin_lock (&lock);
+		if (smp_call_function_data) {
+			spin_unlock (&lock);
+			return -EBUSY;
+		}
+	}
+	smp_call_function_data = &data;
+	spin_unlock (&lock);
+	data.func = func;
+	data.info = info;
+	atomic_set (&data.unstarted_count, smp_num_cpus - 1);
+	data.wait = wait;
+	if (wait) atomic_set (&data.unfinished_count, smp_num_cpus - 1);
+	/*  Send a message to all other CPUs and wait for them to respond  */
+	send_IPI_allbutself (CALL_FUNCTION_VECTOR);
+	/*  Wait for response  */
+	timeout = jiffies + JIFFIE_TIMEOUT;
+	while ( (atomic_read (&data.unstarted_count) > 0) &&
+		time_before (jiffies, timeout) )
+		barrier ();
+	if (atomic_read (&data.unstarted_count) > 0) {
+		smp_call_function_data = NULL;
+		return -ETIMEDOUT;
+	}
+	if (wait)
+		while (atomic_read (&data.unfinished_count) > 0)
+			barrier ();
+	smp_call_function_data = NULL;
+	return 0;
 }
 
 /*
@@ -1781,6 +1846,7 @@
 		local_flush_tlb();
 
 	ack_APIC_irq();
+
 }
 
 static void stop_this_cpu (void)
@@ -1803,12 +1869,19 @@
 	stop_this_cpu();
 }
 
-void (*mtrr_hook) (void) = NULL;
-
-asmlinkage void smp_mtrr_interrupt(void)
+asmlinkage void smp_call_function_interrupt(void)
 {
-	ack_APIC_irq();
-	if (mtrr_hook) (*mtrr_hook)();
+	void (*func) (void *info) = smp_call_function_data->func;
+	void *info = smp_call_function_data->info;
+	int wait = smp_call_function_data->wait;
+
+	ack_APIC_irq ();
+	/*  Notify initiating CPU that I've grabbed the data and am about to
+	    execute the function  */
+	atomic_dec (&smp_call_function_data->unstarted_count);
+	/*  At this point the structure may be out of scope unless wait==1  */
+	(*func) (info);
+	if (wait) atomic_dec (&smp_call_function_data->unfinished_count);
 }
 
 /*
@@ -1949,7 +2022,7 @@
 	/*
 	 * We wrapped around just now. Let's start:
 	 */
-	READ_TSC(t1);
+	rdtscll(t1);
 	tt1=apic_read(APIC_TMCCT);
 
 #define LOOPS (HZ/10)
@@ -1960,7 +2033,7 @@
 		wait_8254_wraparound ();
 
 	tt2=apic_read(APIC_TMCCT);
-	READ_TSC(t2);
+	rdtscll(t2);
 
 	/*
 	 * The APIC bus clock counter is 32 bits only, it
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
--- v2.2.7/linux/arch/i386/kernel/time.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/i386/kernel/time.c	Thu Apr 29 11:53:41 1999
@@ -47,6 +47,7 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/delay.h>
+#include <asm/msr.h>
 
 #include <linux/mc146818rtc.h>
 #include <linux/timex.h>
@@ -83,8 +84,8 @@
 	register unsigned long edx asm("dx");
 
 	/* Read the Time Stamp Counter */
-	__asm__("rdtsc"
-		:"=a" (eax), "=d" (edx));
+
+	rdtsc(eax,edx);
 
 	/* .. relative to previous jiffy (32 bits is enough) */
 	eax -= last_tsc_low;	/* tsc_low delta */
@@ -443,7 +444,8 @@
 		 */
 	
 		/* read Pentium cycle counter */
-		__asm__("rdtsc" : "=a" (last_tsc_low) : : "edx");
+
+		rdtscl(last_tsc_low);
 
 		outb_p(0x00, 0x43);     /* latch the count ASAP */
 
@@ -566,12 +568,12 @@
 		unsigned long endlow, endhigh;
 		unsigned long count;
 
-		__asm__ __volatile__("rdtsc":"=a" (startlow),"=d" (starthigh));
+		rdtsc(startlow,starthigh);
 		count = 0;
 		do {
 			count++;
 		} while ((inb(0x61) & 0x20) == 0);
-		__asm__ __volatile__("rdtsc":"=a" (endlow),"=d" (endhigh));
+		rdtsc(endlow,endhigh);
 
 		last_tsc_low = endlow;
 
diff -u --recursive --new-file v2.2.7/linux/arch/i386/kernel/visws_apic.c linux/arch/i386/kernel/visws_apic.c
--- v2.2.7/linux/arch/i386/kernel/visws_apic.c	Wed Jan 20 23:14:04 1999
+++ linux/arch/i386/kernel/visws_apic.c	Thu May  6 16:12:23 1999
@@ -201,11 +201,13 @@
 	{
 		unsigned int status;
 		/* XXX APIC EOI? */
-		status = desc->status & ~IRQ_REPLAY;
+		status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
 		action = NULL;
-		if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+		if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
 			action = desc->action;
-		desc->status = status | IRQ_INPROGRESS;
+			status |= IRQ_INPROGRESS;
+		}
+		desc->status = status;
 	}
 	spin_unlock(&irq_controller_lock);
 
diff -u --recursive --new-file v2.2.7/linux/arch/mips/kernel/irixioctl.c linux/arch/mips/kernel/irixioctl.c
--- v2.2.7/linux/arch/mips/kernel/irixioctl.c	Fri Oct 23 22:01:19 1998
+++ linux/arch/mips/kernel/irixioctl.c	Sat May  8 11:14:01 1999
@@ -33,13 +33,15 @@
 {
 	struct file *filp;
 
-	if(fd >= NR_OPEN || !(filp = current->files->fd[fd]))
+	file = fcheck(fd);
+	if(!file)
 		return ((struct tty_struct *) 0);
 	if(filp->private_data) {
 		struct tty_struct *ttyp = (struct tty_struct *) filp->private_data;
 
-		if(ttyp->magic == TTY_MAGIC)
+		if(ttyp->magic == TTY_MAGIC) {
 			return ttyp;
+		}
 	}
 	return ((struct tty_struct *) 0);
 }
diff -u --recursive --new-file v2.2.7/linux/arch/mips/kernel/sysirix.c linux/arch/mips/kernel/sysirix.c
--- v2.2.7/linux/arch/mips/kernel/sysirix.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/mips/kernel/sysirix.c	Sat May  8 11:14:01 1999
@@ -23,6 +23,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/utsname.h>
+#include <linux/file.h>
 
 #include <asm/ptrace.h>
 #include <asm/page.h>
@@ -734,6 +735,7 @@
 	int error, i;
 
 	/* We don't support this feature yet. */
+	lock_kernel();
 	if(fs_type) {
 		error = -EINVAL;
 		goto out;
@@ -776,7 +778,6 @@
 
 asmlinkage int irix_fstatfs(unsigned int fd, struct irix_statfs *buf)
 {
-	struct dentry *dentry;
 	struct inode *inode;
 	struct statfs kbuf;
 	mm_segment_t old_fs;
@@ -787,25 +788,22 @@
 	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statfs));
 	if (error)
 		goto out;
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd])) {
+	if (!(file = fget(fd))) {
 		error = -EBADF;
 		goto out;
 	}
-	if (!(dentry = file->f_dentry)) {
+
+	if (!(inode = file->f_dentry->d_inode)) {
 		error = -ENOENT;
-		goto out;
-	}
-	if (!(inode = dentry->d_inode)) {
-		error = -ENOENT;
-		goto out;
+		goto out_f;
 	}
 	if (!inode->i_sb) {
 		error = -ENODEV;
-		goto out;
+		goto out_f;
 	}
 	if (!inode->i_sb->s_op->statfs) {
 		error = -ENOSYS;
-		goto out;
+		goto out_f;
 	}
 
 	old_fs = get_fs(); set_fs(get_ds());
@@ -813,7 +811,7 @@
 	                                  sizeof(struct statfs));
 	set_fs(old_fs);
 	if (error)
-		goto out;
+		goto out_f;
 
 	__put_user(kbuf.f_type, &buf->f_type);
 	__put_user(kbuf.f_bsize, &buf->f_bsize);
@@ -826,9 +824,9 @@
 		__put_user(0, &buf->f_fname[i]);
 		__put_user(0, &buf->f_fpack[i]);
 	}
-	error = 0;
 
-	dput(dentry);
+out_f:
+	fput(file);
 out:
 	unlock_kernel();
 	return error;
@@ -1110,7 +1108,7 @@
 
 	lock_kernel();
 	if(!(flags & MAP_ANONYMOUS)) {
-		if(fd >= NR_OPEN || !(file = current->files->fd[fd])) {
+		if(!(file = fget(fd))) {
 			retval = -EBADF;
 			goto out;
 		}
@@ -1130,6 +1128,8 @@
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
 	retval = do_mmap(file, addr, len, prot, flags, offset);
+	if (file)
+		fput(file);
 
 out:
 	unlock_kernel();
@@ -1568,7 +1568,6 @@
 
 asmlinkage int irix_fstatvfs(int fd, struct irix_statvfs *buf)
 {
-	struct dentry *dentry;
 	struct inode *inode;
 	mm_segment_t old_fs;
 	struct statfs kbuf;
@@ -1582,21 +1581,21 @@
 	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
 	if (error)
 		goto out;
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd])) {
+	if (!(file = fget(fd))) {
 		error = -EBADF;
 		goto out;
 	}
-	if (!(dentry = file->f_dentry)) {
+	if (!(inode = file->f_dentry->d_inode)) {
 		error = -ENOENT;
-		goto out;
+		goto out_f;
 	}
-	if (!(inode = dentry->d_inode)) {
-		error = -ENOENT;
-		goto out;
+	if (!inode->i_sb) {
+		error = -ENODEV;
+		goto out_f;
 	}
 	if (!inode->i_sb->s_op->statfs) {
 		error = -ENOSYS;
-		goto out;
+		goto out_f;
 	}
 
 	old_fs = get_fs(); set_fs(get_ds());
@@ -1604,7 +1603,7 @@
 	                                  sizeof(struct statfs));
 	set_fs(old_fs);
 	if (error)
-		goto out;
+		goto out_f;
 
 	__put_user(kbuf.f_bsize, &buf->f_bsize);
 	__put_user(kbuf.f_frsize, &buf->f_frsize);
@@ -1626,9 +1625,8 @@
 	for(i = 0; i < 32; i++)
 		__put_user(0, &buf->f_fstr[i]);
 
-	error = 0;
-
-	dput(dentry);
+out_f:
+	fput(file);
 out:
 	unlock_kernel();
 	return error;
@@ -1726,7 +1724,7 @@
 	}
 
 	if(!(flags & MAP_ANONYMOUS)) {
-		if(fd >= NR_OPEN || !(file = current->files->fd[fd])) {
+		if(!(file = fcheck(fd))) {
 			error = -EBADF;
 			goto out;
 		}
@@ -1812,6 +1810,7 @@
 	struct statfs kbuf;
 	int error, i;
 
+	lock_kernel();
 	printk("[%s:%ld] Wheee.. irix_statvfs(%s,%p)\n",
 	       current->comm, current->pid, fname, buf);
 	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
@@ -1864,7 +1863,6 @@
 
 asmlinkage int irix_fstatvfs64(int fd, struct irix_statvfs *buf)
 {
-	struct dentry *dentry;
 	struct inode *inode;
 	mm_segment_t old_fs;
 	struct statfs kbuf;
@@ -1878,21 +1876,21 @@
 	error = verify_area(VERIFY_WRITE, buf, sizeof(struct irix_statvfs));
 	if (error)
 		goto out;
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd])) {
+	if (!(file = fget(fd))) {
 		error = -EBADF;
 		goto out;
 	}
-	if (!(dentry = file->f_dentry)) {
+	if (!(inode = file->f_dentry->d_inode)) {
 		error = -ENOENT;
-		goto out;
+		goto out_f;
 	}
-	if (!(inode = dentry->d_inode)) {
-		error = -ENOENT;
-		goto out;
+	if (!inode->i_sb) {
+		error = -ENODEV;
+		goto out_f;
 	}
 	if (!inode->i_sb->s_op->statfs) {
 		error = -ENOSYS;
-		goto out;
+		goto out_f;
 	}
 
 	old_fs = get_fs(); set_fs(get_ds());
@@ -1900,7 +1898,7 @@
 	                                  sizeof(struct statfs));
 	set_fs(old_fs);
 	if (error)
-		goto out;
+		goto out_f;
 
 	__put_user(kbuf.f_bsize, &buf->f_bsize);
 	__put_user(kbuf.f_frsize, &buf->f_frsize);
@@ -1921,10 +1919,8 @@
 	__put_user(kbuf.f_namelen, &buf->f_namemax);
 	for(i = 0; i < 32; i++)
 		__put_user(0, &buf->f_fstr[i]);
-
-	error = 0;
-
-	dput(dentry);
+out_f:
+	fput(file);
 out:
 	unlock_kernel();
 	return error;
@@ -1994,7 +1990,6 @@
 	unsigned short reclen = ROUND_UP32(NAME_OFFSET32(dirent) + namlen + 1);
 	int retval;
 
-	lock_kernel();
 #ifdef DEBUG_GETDENTS
 	printk("\nirix_filldir32[reclen<%d>namlen<%d>count<%d>]",
 	       reclen, namlen, buf->count);
@@ -2020,14 +2015,12 @@
 	retval = 0;
 
 out:
-	unlock_kernel();
 	return retval;
 }
 
 asmlinkage int irix_ngetdents(unsigned int fd, void * dirent, unsigned int count, int *eob)
 {
 	struct file *file;
-	struct dentry *dentry;
 	struct inode *inode;
 	struct irix_dirent32 *lastdirent;
 	struct irix_dirent32_callback buf;
@@ -2039,46 +2032,56 @@
 	       current->pid, fd, dirent, count, eob);
 #endif
 	error = -EBADF;
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+	file = fget(fd);
+	if (!file)
 		goto out;
 
-	dentry = file->f_dentry;
-	if (!dentry)
-		goto out;
+	inode = file->f_dentry->d_inode;
+	if (!inode)
+		goto out_putf;
 
 	inode = dentry->d_inode;
 	if (!inode)
-		goto out;
+		goto out_putf;
 
-	error = -ENOTDIR;
-	if (!file->f_op || !file->f_op->readdir)
-		goto out;
-
-	error = -EFAULT;
-	if(!access_ok(VERIFY_WRITE, dirent, count) ||
-	   !access_ok(VERIFY_WRITE, eob, sizeof(*eob)))
-		goto out;
-
-	__put_user(0, eob);
 	buf.current_dir = (struct irix_dirent32 *) dirent;
 	buf.previous = NULL;
 	buf.count = count;
 	buf.error = 0;
 
+	error = -ENOTDIR;
+	if (!file->f_op || !file->f_op->readdir)
+		goto out_putf;
+
+	/*
+	 * Get the inode's semaphore to prevent changes
+	 * to the directory while we read it.
+	 */
+	down(&inode->i_sem);
 	error = file->f_op->readdir(file, &buf, irix_filldir32);
+	up(&inode->i_sem);
 	if (error < 0)
-		goto out;
+		goto out_putf;
+	error = buf.error;
 	lastdirent = buf.previous;
-	if (!lastdirent) {
-		error = buf.error;
-		goto out;
+	if (lastdirent) {
+		put_user(file->f_pos, &lastdirent->d_off);
+		error = count - buf.count;
 	}
-	lastdirent->d_off = (u32) file->f_pos;
+
+	if (put_user(0, eob) < 0) {
+		error = EFAULT;
+		goto out_putf;
+	}
+
+
 #ifdef DEBUG_GETDENTS
 	printk("eob=%d returning %d\n", *eob, count - buf.count);
 #endif
 	error = count - buf.count;
 
+out_putf:
+	fput(file);
 out:
 	unlock_kernel();
 	return error;
@@ -2110,7 +2113,6 @@
 	unsigned short reclen = ROUND_UP64(NAME_OFFSET64(dirent) + namlen + 1);
 	int retval;
 
-	lock_kernel();
 	buf->error = -EINVAL;	/* only used if we fail.. */
 	if (reclen > buf->count) {
 		retval = -EINVAL;
@@ -2131,14 +2133,12 @@
 
 	retval = 0;
 out:
-	unlock_kernel();
 	return retval;
 }
 
 asmlinkage int irix_getdents64(int fd, void *dirent, int cnt)
 {
 	struct file *file;
-	struct dentry *dentry;
 	struct inode *inode;
 	struct irix_dirent64 *lastdirent;
 	struct irix_dirent64_callback buf;
@@ -2150,40 +2150,38 @@
 	       current->pid, fd, dirent, cnt);
 #endif
 	error = -EBADF;
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-		goto out;
-
-	dentry = file->f_dentry;
-	if (!dentry)
+	if (!(file = fget(fd)))
 		goto out;
 
-	inode = dentry->d_inode;
+	inode = file->f_dentry->d_inode;
 	if (!inode)
-		goto out;
+		goto out_f;
 
 	error = -ENOTDIR;
 	if (!file->f_op || !file->f_op->readdir)
-		goto out;
+		goto out_f;
 
 	error = -EFAULT;
 	if(!access_ok(VERIFY_WRITE, dirent, cnt))
-		goto out;
+		goto out_f;
 
 	error = -EINVAL;
 	if(cnt < (sizeof(struct irix_dirent64) + 255))
-		goto out;
+		goto out_f;
 
 	buf.curr = (struct irix_dirent64 *) dirent;
 	buf.previous = NULL;
 	buf.count = cnt;
 	buf.error = 0;
+	down(&inode->i_sem);
 	error = file->f_op->readdir(file, &buf, irix_filldir64);
+	up(&inode->i_sem);
 	if (error < 0)
-		goto out;
+		goto out_f;
 	lastdirent = buf.previous;
 	if (!lastdirent) {
 		error = buf.error;
-		goto out;
+		goto out_f;
 	}
 	lastdirent->d_off = (u64) file->f_pos;
 #ifdef DEBUG_GETDENTS
@@ -2191,6 +2189,8 @@
 #endif
 	error = cnt - buf.count;
 
+out_f:
+	fput(file);
 out:
 	unlock_kernel();
 	return error;
@@ -2199,7 +2199,6 @@
 asmlinkage int irix_ngetdents64(int fd, void *dirent, int cnt, int *eob)
 {
 	struct file *file;
-	struct dentry *dentry;
 	struct inode *inode;
 	struct irix_dirent64 *lastdirent;
 	struct irix_dirent64_callback buf;
@@ -2211,42 +2210,40 @@
 	       current->pid, fd, dirent, cnt);
 #endif
 	error = -EBADF;
-	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
-		goto out;
-
-	dentry = file->f_dentry;
-	if (!dentry)
+	if (!(file = fget(fd)))
 		goto out;
 
-	inode = dentry->d_inode;
+	inode = file->f_dentry->d_inode;
 	if (!inode)
-		goto out;
+		goto out_f;
 
 	error = -ENOTDIR;
 	if (!file->f_op || !file->f_op->readdir)
-		goto out;
+		goto out_f;
 
 	error = -EFAULT;
 	if(!access_ok(VERIFY_WRITE, dirent, cnt) ||
 	   !access_ok(VERIFY_WRITE, eob, sizeof(*eob)))
-		goto out;
+		goto out_f;
 
 	error = -EINVAL;
 	if(cnt < (sizeof(struct irix_dirent64) + 255))
-		goto out;
+		goto out_f;
 
 	*eob = 0;
 	buf.curr = (struct irix_dirent64 *) dirent;
 	buf.previous = NULL;
 	buf.count = cnt;
 	buf.error = 0;
+	down(&inode->i_sem);
 	error = file->f_op->readdir(file, &buf, irix_filldir64);
+	up(&inode->i_sem);
 	if (error < 0)
-		goto out;
+		goto out_f;
 	lastdirent = buf.previous;
 	if (!lastdirent) {
 		error = buf.error;
-		goto out;
+		goto out_f;
 	}
 	lastdirent->d_off = (u64) file->f_pos;
 #ifdef DEBUG_GETDENTS
@@ -2254,6 +2251,8 @@
 #endif
 	error = cnt - buf.count;
 
+out_f:
+	fput(file);
 out:
 	unlock_kernel();
 	return error;
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile
--- v2.2.7/linux/arch/ppc/boot/Makefile	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/boot/Makefile	Thu Apr 29 12:39:01 1999
@@ -14,7 +14,7 @@
 .s.o:
 	$(AS) -o $*.o $<
 .c.o:
-	$(CC) $(CFLAGS)  -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $<
+	$(CC) $(CFLAGS)  -DINITRD_OFFSET=$(IOFF) -DINITRD_SIZE=$(ISZ) -DZIMAGE_OFFSET=$(ZOFF) -DZIMAGE_SIZE=$(ZSZ) -c -o $*.o $<
 .S.s:
 	$(CC) -D__ASSEMBLY__ -traditional -E -o $*.o $<
 .S.o:
@@ -57,7 +57,7 @@
 		-DINITRD_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd initrd` \
 		-DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux.initrd image` \
 		-DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux.initrd image` \
-		-DKERNELBASE=$(KERNELBASE) -c -o misc.o misc.c
+		-c -o misc.o misc.c
 	$(LD) $(ZLINKFLAGS) -o zvmlinux.initrd.tmp $(OBJECTS)
 	$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
 		--add-section=initrd=ramdisk.image.gz \
@@ -84,7 +84,7 @@
 #
 	$(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 \
 		-DZIMAGE_OFFSET=`sh offset $(OBJDUMP) zvmlinux image` \
-		-DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` -DKERNELBASE=$(KERNELBASE) \
+		-DZIMAGE_SIZE=`sh size $(OBJDUMP) zvmlinux image` \
 		-c -o misc.o misc.c
 	$(LD) $(ZLINKFLAGS) -o zvmlinux.tmp $(OBJECTS)
 	$(OBJCOPY) $(OBJCOPY_ARGS) -R .comment --add-section=image=../coffboot/vmlinux.gz \
@@ -95,7 +95,7 @@
 	dd if=zImage of=/dev/fd0H1440 bs=64b
 
 mkprep : mkprep.c
-	$(HOSTCC) -DKERNELBASE=$(KERNELBASE) -o mkprep mkprep.c
+	$(HOSTCC) -o mkprep mkprep.c
 
 znetboot : zImage
 	cp zImage $(TFTPIMAGE)
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/boot/head.S linux/arch/ppc/boot/head.S
--- v2.2.7/linux/arch/ppc/boot/head.S	Fri Apr 16 14:47:30 1999
+++ linux/arch/ppc/boot/head.S	Thu Apr 29 12:39:01 1999
@@ -6,7 +6,7 @@
 	.text
 
 /*
- * $Id: head.S,v 1.29 1999/03/08 23:41:17 cort Exp $
+ * $Id: head.S,v 1.31 1999/04/22 06:32:00 davem Exp $
  *	
  * Boot loader philosophy:
  *      ROM loads us to some arbitrary location
@@ -23,11 +23,7 @@
 start_:
 	mr	r11,r3		/* Save pointer to residual/board data */
 	mr      r25,r5          /* Save OFW pointer */
-
-	mfmsr	r3		/* Turn off interrupts  */
-	li	r4,0
-	ori	r4,r4,MSR_EE
-	andc	r3,r3,r4
+	li	r3,MSR_IP	/* Establish default MSR value */
 	mtmsr	r3
 
 /* check if we need to relocate ourselves to the link addr or were we
@@ -136,6 +132,20 @@
 	lis	r10,0xdeadc0de@h
 	ori	r10,r10,0xdeadc0de@l
 	stw	r10,0(r9)
+/*
+ * The Radstone firmware maps PCI memory at 0xc0000000 using BAT2
+ * so disable BATs before setting this to avoid a clash
+ */
+	li      r8,0
+	mtspr   DBAT0U,r8
+	mtspr   DBAT1U,r8
+	mtspr   DBAT2U,r8
+	mtspr   DBAT3U,r8
+	mtspr   IBAT0U,r8
+	mtspr   IBAT1U,r8
+	mtspr   IBAT2U,r8
+	mtspr   IBAT3U,r8
+
 	blr
 hang:
 	b	hang	
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/boot/kbd.c linux/arch/ppc/boot/kbd.c
--- v2.2.7/linux/arch/ppc/boot/kbd.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/boot/kbd.c	Thu Apr 29 12:39:01 1999
@@ -127,6 +127,11 @@
 	unsigned char c;
 	int i;
 
+	/* flush input queue */
+	while ((inb(KBSTATP) & KBINRDY))
+	{
+		(void)inb(KBDATAP);
+	}
 	/* Send self-test */
 	while (inb(KBSTATP) & KBOUTRDY) ;
 	outb(KBSTATP,0xAA);
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/boot/misc.c linux/arch/ppc/boot/misc.c
--- v2.2.7/linux/arch/ppc/boot/misc.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/boot/misc.c	Thu Apr 29 12:39:01 1999
@@ -1,7 +1,7 @@
 /*
  * misc.c
  *
- * $Id: misc.c,v 1.61 1999/03/08 23:51:02 cort Exp $
+ * $Id: misc.c,v 1.63 1999/04/05 21:48:20 cort Exp $
  * 
  * Adapted for PowerPC by Gary Thomas
  *
@@ -33,14 +33,16 @@
 char *end_avail;
 extern char _end[];
 
-#if defined(CONFIG_SERIAL_CONSOLE)
-char cmd_preset[] = "console=ttyS0,9600n8";
+#ifdef CONFIG_CMDLINE
+#define CMDLINE CONFIG_CMDLINE
 #else
-char cmd_preset[] = "";
+#define CMDLINE "";
 #endif
-char	cmd_buf[256];
-char	*cmd_line = cmd_buf;
+char cmd_preset[] = CMDLINE;
+char cmd_buf[256];
+char *cmd_line = cmd_buf;
 
+int keyb_present = 1;	/* keyboard controller is present by default */
 RESIDUAL hold_resid_buf;
 RESIDUAL *hold_residual = &hold_resid_buf;
 unsigned long initrd_start = 0, initrd_end = 0;
@@ -58,7 +60,8 @@
 void * memcpy(void * __dest, __const void * __src,
 			    int __n);
 void gunzip(void *, int, unsigned char *, int *);
-int _cvt(unsigned long val, char *buf, long radix, char *digits);
+static int _cvt(unsigned long val, char *buf, long radix, char *digits);
+unsigned char inb(int);
 
 void pause()
 {
@@ -93,11 +96,14 @@
 
 tstc(void)
 {
-	return (
 #if defined(CONFIG_SERIAL_CONSOLE)
-		NS16550_tstc(com_port) ||
+	if (keyb_present)
+		return (CRT_tstc() || NS16550_tstc(com_port));
+	else
+		NS16550_tstc(com_port);
+#else
+	return (CRT_tstc() );
 #endif /* CONFIG_SERIAL_CONSOLE */
-		CRT_tstc());
 }
 
 getc(void)
@@ -106,7 +112,8 @@
 #if defined(CONFIG_SERIAL_CONSOLE)
 		if (NS16550_tstc(com_port)) return (NS16550_getc(com_port));
 #endif /* CONFIG_SERIAL_CONSOLE */
-		if (CRT_tstc()) return (CRT_getc());
+		if (keyb_present)
+			if (CRT_tstc()) return (CRT_getc());
 	}
 }
 
@@ -188,6 +195,8 @@
 		}
 	}
 
+	cursor(x, y);
+
 	orig_x = x;
 	orig_y = y;
 }
@@ -317,6 +326,8 @@
 	int dev_handle;
 	int mem_info[2];
 	int res, size;
+	unsigned char board_type;
+	unsigned char base_mod;
 
 	lines = 25;
 	cols = 80;
@@ -333,14 +344,30 @@
 	flush_instruction_cache();
 	_put_HID0(_get_HID0() & ~0x0000C000);
 	_put_MSR((orig_MSR = _get_MSR()) & ~0x0030);
-	vga_init(0xC0000000);
 
 #if defined(CONFIG_SERIAL_CONSOLE)
-	com_port = (struct NS16550 *)NS16550_init(1);
+	com_port = (struct NS16550 *)NS16550_init(0);
 #endif /* CONFIG_SERIAL_CONSOLE */
+	vga_init(0xC0000000);
 
 	if (residual)
 	{
+		/* Is this Motorola PPCBug? */
+		if ((1 & residual->VitalProductData.FirmwareSupports) &&
+		    (1 == residual->VitalProductData.FirmwareSupplier)) {
+			board_type = inb(0x800) & 0xF0;
+
+			/* If this is genesis 2 board then check for no
+			 * keyboard controller and more than one processor.
+			 */
+			if (board_type == 0xe0) {	
+				base_mod = inb(0x803);
+				/* if a MVME2300 or a MCME2400 then no keyboard */
+				if((base_mod == 0x9) || (base_mod == 0xF9)) {
+					keyb_present = 0;	/* no keyboard */
+				}
+			}
+		}
 		memcpy(hold_residual,residual,sizeof(RESIDUAL));
 	} else {
 		/* Assume 32M in the absence of more info... */
@@ -429,7 +456,7 @@
 	avail_ram = (char *)PAGE_ALIGN((unsigned long)_end);
 	puts("zimage at:     "); puthex((unsigned long)zimage_start);
 	puts(" "); puthex((unsigned long)(zimage_size+zimage_start)); puts("\n");
-	if ( (unsigned long)zimage_start <= 0x008000000 )
+	if ( (unsigned long)zimage_start <= 0x00800000 )
 	{
 		memcpy( (void *)avail_ram, (void *)zimage_start, zimage_size );
 		zimage_start = (char *)avail_ram;
@@ -458,9 +485,8 @@
 	puts("avail ram:     "); puthex((unsigned long)avail_ram); puts(" ");
 	puthex((unsigned long)end_avail); puts("\n");
 
-#if !defined(CONFIG_SERIAL_CONSOLE)
-	CRT_tstc();  /* Forces keyboard to be initialized */
-#endif
+	if (keyb_present)
+		CRT_tstc();  /* Forces keyboard to be initialized */
 
 	puts("\nLinux/PPC load: ");
 	timer = 0;
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/boot/mkprep.c linux/arch/ppc/boot/mkprep.c
--- v2.2.7/linux/arch/ppc/boot/mkprep.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/boot/mkprep.c	Thu Apr 29 12:39:01 1999
@@ -14,15 +14,8 @@
  * Modified for x86 hosted builds by Matt Porter <porter@neta.com>
  */
 
-#ifdef linux
-#include <linux/types.h>
-/*#include <asm/stat.h>*/
-/*#include <asm/byteorder.h>*/ /* the byte swap funcs don't work here -- Cort */
-#else
 #include <unistd.h>
-#endif
 #include <sys/stat.h>
-
 #include <stdio.h>
 #include <errno.h>
 
@@ -168,10 +161,10 @@
   /* set entry point and boot image size skipping over elf header */
 #ifdef __i386__
   *entry = 0x400/*+65536*/;
-  *length = info.st_size+0x400;
+  *length = info.st_size-elfhdr_size+0x400;
 #else
   *entry = cpu_to_le32(0x400/*+65536*/);
-  *length = cpu_to_le32(info.st_size+0x400);
+  *length = cpu_to_le32(info.st_size-elfhdr_size+0x400);
 #endif /* __i386__ */
 
   /* sets magic number for msdos partition (used by linux) */
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/common_defconfig linux/arch/ppc/common_defconfig
--- v2.2.7/linux/arch/ppc/common_defconfig	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/common_defconfig	Thu Apr 29 12:39:01 1999
@@ -1,5 +1,5 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
 #
 
 #
@@ -14,7 +14,7 @@
 CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
-# CONFIG_SMP is not set
+CONFIG_SMP=y
 
 #
 # General setup
@@ -43,12 +43,11 @@
 CONFIG_MAC_FLOPPY=y
 CONFIG_MAC_SERIAL=y
 CONFIG_ADBMOUSE=y
-CONFIG_BLK_DEV_IDE_PMAC=y
 CONFIG_PROC_DEVICETREE=y
-# CONFIG_KGDB is not set
-# CONFIG_XMON is not set
 # CONFIG_TOTALMP is not set
 CONFIG_BOOTX_TEXT=y
+# CONFIG_MOTOROLA_HOTSWAP is not set
+# CONFIG_CMDLINE_BOOL is not set
 
 #
 # Plug and Play support
@@ -60,6 +59,10 @@
 #
 # 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
@@ -70,8 +73,14 @@
 # CONFIG_BLK_DEV_RZ1000 is not set
 # CONFIG_BLK_DEV_IDEPCI is not set
 # CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDE_PMAC=y
+# CONFIG_BLK_DEV_IDEDMA_PMAC is not set
 # CONFIG_IDE_CHIPSETS is not set
-# CONFIG_BLK_DEV_LOOP is not set
+
+#
+# Additional Block Devices
+#
+CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
@@ -101,10 +110,17 @@
 # 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_RARP=y
-CONFIG_IP_NOSR=y
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
+
+#
+#  
+#
 # CONFIG_IPX is not set
 CONFIG_ATALK=m
 # CONFIG_X25 is not set
@@ -126,12 +142,20 @@
 # SCSI support
 #
 CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-# CONFIG_CHR_DEV_SG is not set
-# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
 
@@ -159,10 +183,15 @@
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_G_NCR5380_PORT is not set
+# CONFIG_SCSI_G_NCR5380_MEM is not set
 # CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
 # CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C416 is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 CONFIG_SCSI_NCR53C8XX=y
+# CONFIG_SCSI_SYM53C8XX is not set
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
 CONFIG_SCSI_NCR53C8XX_SYNC=20
@@ -175,6 +204,7 @@
 # CONFIG_SCSI_PSI240I is not set
 # CONFIG_SCSI_QLOGIC_FAS is not set
 # CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
 # CONFIG_SCSI_SEAGATE is not set
 # CONFIG_SCSI_DC390T is not set
 # CONFIG_SCSI_T128 is not set
@@ -205,7 +235,7 @@
 # CONFIG_ACENIC is not set
 # CONFIG_NET_ISA is not set
 CONFIG_NET_EISA=y
-# CONFIG_PCNET32 is not set
+CONFIG_PCNET32=y
 # CONFIG_AC3200 is not set
 # CONFIG_APRICOT is not set
 # CONFIG_CS89x0 is not set
@@ -229,6 +259,10 @@
 # CONFIG_COPS is not set
 # CONFIG_IPDDP is not set
 CONFIG_PPP=y
+
+#
+# CCP compressors for PPP are only built as modules.
+#
 # CONFIG_SLIP is not set
 # CONFIG_NET_RADIO is not set
 # CONFIG_TR is not set
@@ -256,22 +290,37 @@
 # Console drivers
 #
 CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_PM2 is not set
 CONFIG_FB_OF=y
 CONFIG_FB_CONTROL=y
 CONFIG_FB_PLATINUM=y
 CONFIG_FB_VALKYRIE=y
-CONFIG_FB_ATY=y
+# CONFIG_FB_ATY is not set
 CONFIG_FB_IMSTT=y
 CONFIG_FB_CT65550=y
 # CONFIG_FB_S3TRIO is not set
-# CONFIG_FB_MATROX is not set
-CONFIG_FB_ATY=y
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G100=y
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+# CONFIG_FB_ATY is not set
 # CONFIG_FB_VIRTUAL is not set
-# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
 CONFIG_FBCON_CFB8=y
 CONFIG_FBCON_CFB16=y
 CONFIG_FBCON_CFB24=y
 CONFIG_FBCON_CFB32=y
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA is not set
 # CONFIG_FBCON_FONTWIDTH8_ONLY is not set
 CONFIG_FBCON_FONTS=y
 # CONFIG_FONT_8x8 is not set
@@ -292,7 +341,17 @@
 # CONFIG_SERIAL_NONSTANDARD is not set
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
-# CONFIG_MOUSE is not set
+CONFIG_MOUSE=y
+
+#
+# Mice
+#
+# CONFIG_ATIXL_BUSMOUSE is not set
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MS_BUSMOUSE is not set
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
@@ -307,11 +366,20 @@
 # Joystick support
 #
 # CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
 
 #
 # Ftape, the floppy tape device driver
 #
 # CONFIG_FTAPE is not set
+# CONFIG_FT_NORMAL_DEBUG is not set
+# CONFIG_FT_FULL_DEBUG is not set
+# CONFIG_FT_NO_TRACE is not set
+# CONFIG_FT_NO_TRACE_AT_ALL is not set
+# CONFIG_FT_STD_FDC is not set
+# CONFIG_FT_MACH2 is not set
+# CONFIG_FT_PROBE_FC10 is not set
+# CONFIG_FT_ALT_FDC is not set
 
 #
 # Filesystems
@@ -402,3 +470,10 @@
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
 # CONFIG_SOUND_OSS is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.2.7/linux/arch/ppc/config.in	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/config.in	Thu Apr 29 12:39:01 1999
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.84 1999/02/23 08:08:38 davem Exp $
+# $Id: config.in,v 1.91 1999/04/09 07:07:47 cort Exp $
 # For a description of the syntax of this configuration file,
 # see the Configure script.
 #
@@ -19,12 +19,10 @@
   	 APUS           CONFIG_APUS \
 	 MBX		CONFIG_MBX" PowerMac
 
+bool 'Symmetric multi-processing support' CONFIG_SMP
 if [ "$CONFIG_ALL_PPC" != "y" ];then
   define_bool CONFIG_MACH_SPECIFIC y
 fi
-
-bool 'Symmetric multi-processing support' CONFIG_SMP
-
 endmenu
 
 if [ "$CONFIG_MBX" = "y" ];then
@@ -82,13 +80,20 @@
 bool 'Support for PowerMac keyboard' CONFIG_MAC_KEYBOARD
 bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY
 bool 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL
+if [ "$CONFIG_MAC_SERIAL" = "y" ]; then
+   bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
+fi
 bool 'Support for PowerMac ADB mouse' CONFIG_ADBMOUSE
-bool 'Support for PowerMac IDE devices (must also enable IDE)' CONFIG_BLK_DEV_IDE_PMAC
 bool 'Support for Open Firmware device tree in /proc' CONFIG_PROC_DEVICETREE
-bool 'Include kgdb kernel debugger' CONFIG_KGDB
-bool 'Include xmon kernel debugger' CONFIG_XMON
 bool 'Support for TotalImpact TotalMP' CONFIG_TOTALMP
 bool 'Support for early boot text console (BootX only)' CONFIG_BOOTX_TEXT
+bool 'Support for Motorola Hot Swap' CONFIG_MOTOROLA_HOTSWAP
+if [ "$CONFIG_PREP" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then
+  bool 'PReP bootloader ernel arguments' CONFIG_CMDLINE_BOOL n
+  if [ "$CONFIG_CMDLINE_BOOL" = "y" ] ; then
+    string 'Initial kernel command string' CONFIG_CMDLINE ""
+  fi
+fi
 
 if [ "$CONFIG_APUS" = "y" ]; then
   define_bool CONFIG_FB_CONSOLE y
@@ -176,4 +181,12 @@
   source drivers/sound/Config.in
 fi
 
+endmenu
+
+mainmenu_option next_comment
+comment 'Kernel hacking'
+
+bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+bool 'Include kgdb kernel debugger' CONFIG_KGDB
+bool 'Include xmon kernel debugger' CONFIG_XMON
 endmenu
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- v2.2.7/linux/arch/ppc/kernel/Makefile	Mon Dec 28 15:00:52 1998
+++ linux/arch/ppc/kernel/Makefile	Thu Apr 29 12:39:01 1999
@@ -27,7 +27,7 @@
 endif
 
 ifeq ($(CONFIG_MBX),y)
-O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o
+O_OBJS += mbx_setup.o mbx_pci.o softemu8xx.o i8259.o ppc8xx_pic.o
 else
 ifeq ($(CONFIG_APUS),y)
 O_OBJS += apus_setup.o prom.o openpic.o
@@ -36,7 +36,8 @@
 O_OBJS += prep_time.o pmac_time.o chrp_time.o \
 	  pmac_setup.o pmac_support.o \
 	  prep_pci.o pmac_pci.o chrp_pci.o \
-	  residual.o prom.o openpic.o feature.o
+	  residual.o prom.o openpic.o feature.o \
+	  prep_nvram.o open_pic.o i8259.o pmac_pic.o indirect_pci.o
 OX_OBJS += chrp_setup.o prep_setup.o
 endif
 endif
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/align.c linux/arch/ppc/kernel/align.c
--- v2.2.7/linux/arch/ppc/kernel/align.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/align.c	Thu Apr 29 12:39:01 1999
@@ -194,13 +194,8 @@
 			return -EFAULT;	/* bad address */
 	}
 
-#ifdef __SMP__
-	if ((flags & F) && (regs->msr & MSR_FP) )
-		smp_giveup_fpu(current);
-#else	
-	if ((flags & F) && last_task_used_math == current)
-		giveup_fpu();
-#endif
+	if ((flags & F) && (regs->msr & MSR_FP))
+		giveup_fpu(current);
 	if (flags & M)
 		return 0;		/* too hard for now */
 
@@ -254,27 +249,16 @@
 		data.d = current->tss.fpr[reg];
 		break;
 	/* these require some floating point conversions... */
-	/* note that giveup_fpu enables the FPU for the kernel */
 	/* we'd like to use the assignment, but we have to compile
 	 * the kernel with -msoft-float so it doesn't use the
 	 * fp regs for copying 8-byte objects. */
 	case LD+F+S:
-#ifdef __SMP__
-		if (regs->msr & MSR_FP )
-			smp_giveup_fpu(current);
-#else	
-		giveup_fpu();
-#endif		
+		enable_kernel_fp();
 		cvt_fd(&data.f, &current->tss.fpr[reg], &current->tss.fpscr);
 		/* current->tss.fpr[reg] = data.f; */
 		break;
 	case ST+F+S:
-#ifdef __SMP__
-		if (regs->msr & MSR_FP )
-			smp_giveup_fpu(current);
-#else	
-		giveup_fpu();
-#endif		
+		enable_kernel_fp();
 		cvt_df(&current->tss.fpr[reg], &data.f, &current->tss.fpscr);
 		/* data.f = current->tss.fpr[reg]; */
 		break;
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c
--- v2.2.7/linux/arch/ppc/kernel/apus_setup.c	Tue Dec 22 14:16:54 1998
+++ linux/arch/ppc/kernel/apus_setup.c	Thu Apr 29 12:39:01 1999
@@ -14,12 +14,50 @@
 #include <linux/sched.h>
 #include <linux/kd.h>
 #include <linux/init.h>
+#include <linux/hdreg.h>
+
+/* Get the IDE stuff from the 68k file */
+#define ide_init_hwif_ports m68k_ide_init_hwif_ports
+#define ide_default_irq m68k_ide_default_irq
+#define ide_default_io_base m68k_ide_default_io_base
+#define ide_check_region m68k_ide_check_region
+#define ide_request_region m68k_ide_request_region
+#define ide_release_region m68k_ide_release_region
+#define ide_fix_driveid m68k_ide_fix_driveid
+#include <asm-m68k/ide.h>
+#undef ide_init_hwif_ports
+#define ide_default_irq
+#define ide_default_io_base
+#define ide_check_region
+#define ide_request_region
+#define ide_release_region
+#define ide_fix_driveid
+
 
 #include <asm/setup.h>
 #include <asm/amigahw.h>
 #include <asm/amigappc.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ide.h>
+
+#include "time.h"
+#include "local_irq.h"
+
+unsigned long apus_get_rtc_time(void);
+int apus_set_rtc_time(unsigned long nowtime);
+
+/* APUS defs */
+extern int parse_bootinfo(const struct bi_record *);
+extern char _end[];
+#ifdef CONFIG_APUS
+struct mem_info ramdisk;
+unsigned long isa_io_base;
+unsigned long isa_mem_base;
+unsigned long pci_dram_offset;
+#endif
+/* END APUS defs */
 
 unsigned long m68k_machtype;
 char debug_device[6] = "";
@@ -72,6 +110,8 @@
 	int i;
 	char *p, *q;
 
+	m68k_machtype = MACH_AMIGA;
+
 	/* Parse the command line for arch-specific options.
 	 * For the m68k, this is currently only "debug=xxx" to enable printing
 	 * certain kernel messages to some machine-specific device.  */
@@ -408,4 +448,195 @@
 	       "icbi 0,%0 \n\t"
 	       "isync \n\t"
 	       : : "r" (addr));
+}
+
+void
+apus_restart(char *cmd)
+{
+	cli();
+
+	APUS_WRITE(APUS_REG_LOCK, 
+		   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK2);
+	APUS_WRITE(APUS_REG_LOCK, 
+		   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK3);
+	APUS_WRITE(APUS_REG_LOCK, 
+		   REGLOCK_BLACKMAGICK2|REGLOCK_BLACKMAGICK3);
+	APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET);
+	APUS_WRITE(APUS_REG_RESET, REGRESET_AMIGARESET);
+	for(;;);
+}
+
+void
+apus_power_off(void)
+{
+	for (;;);
+}
+
+void
+apus_halt(void)
+{
+   apus_restart(NULL);
+}
+
+void
+apus_do_IRQ(struct pt_regs *regs,
+	    int            cpu,
+            int            isfake)
+{
+        int old_level, new_level;
+
+	/* I don't think we need SMP code here - Corey */
+
+        old_level = ~(regs->mq) & IPLEMU_IPLMASK;
+        new_level = (~(regs->mq) >> 3) & IPLEMU_IPLMASK;
+        if (new_level != 0)
+        {
+                APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
+                APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
+                                          | (~(new_level) & IPLEMU_IPLMASK)));
+                APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
+
+                process_int (VEC_SPUR+new_level, regs);
+                APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
+                APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
+                APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
+                                          | (~(old_level) & IPLEMU_IPLMASK)));
+        }
+        APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+void
+apus_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+	ide_insw(port, buf, ns);
+}
+
+void
+apus_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+	ide_outsw(port, buf, ns);
+}
+
+int
+apus_ide_default_irq(ide_ioreg_t base)
+{
+        m68k_ide_default_irq(base);
+}
+
+ide_ioreg_t
+apus_ide_default_io_base(int index)
+{
+        m68k_ide_default_io_base(index);
+}
+
+int
+apus_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+        return m68k_ide_check_region(from, extent);
+}
+
+void
+apus_ide_request_region(ide_ioreg_t from,
+			unsigned int extent,
+			const char *name)
+{
+        m68k_ide_request_region(from, extent, name);
+}
+
+void
+apus_ide_release_region(ide_ioreg_t from,
+			unsigned int extent)
+{
+        m68k_ide_release_region(from, extent);
+}
+
+void
+apus_ide_fix_driveid(struct hd_driveid *id)
+{
+        m68k_ide_fix_driveid(id);
+}
+
+__initfunc(void
+apus_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq))
+{
+        m68k_ide_init_hwif_ports(p, base, irq);
+}
+#endif
+
+__initfunc(void
+apus_local_init_IRQ(void))
+{
+	ppc_md.mask_irq = amiga_disable_irq;
+	ppc_md.unmask_irq = amiga_enable_irq;
+	apus_init_IRQ();
+}
+
+__initfunc(void
+apus_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	  unsigned long r6, unsigned long r7))
+{
+	/* Parse bootinfo. The bootinfo is located right after
+           the kernel bss */
+	parse_bootinfo((const struct bi_record *)&_end);
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* Take care of initrd if we have one. Use data from
+	   bootinfo to avoid the need to initialize PPC
+	   registers when kernel is booted via a PPC reset. */
+	if ( ramdisk.addr ) {
+		initrd_start = (unsigned long) __va(ramdisk.addr);
+		initrd_end = (unsigned long) 
+			__va(ramdisk.size + ramdisk.addr);
+	}
+	/* Make sure code below is not executed. */
+	r4 = 0;
+	r6 = 0;
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+	ISA_DMA_THRESHOLD = 0x00ffffff;
+
+	ppc_md.setup_arch     = apus_setup_arch;
+	ppc_md.setup_residual = NULL;
+	ppc_md.get_cpuinfo    = apus_get_cpuinfo;
+	ppc_md.irq_cannonicalize = NULL;
+	ppc_md.init_IRQ       = apus_init_IRQ;
+	ppc_md.do_IRQ         = apus_do_IRQ;
+	ppc_md.get_irq_source = NULL;
+	ppc_md.init           = NULL;
+
+	ppc_md.restart        = apus_restart;
+	ppc_md.power_off      = apus_power_off;
+	ppc_md.halt           = apus_halt;
+
+	ppc_md.time_init      = NULL;
+	ppc_md.set_rtc_time   = apus_set_rtc_time;
+	ppc_md.get_rtc_time   = apus_get_rtc_time;
+	ppc_md.calibrate_decr = apus_calibrate_decr;
+
+	/* These should not be used for the APUS yet, since it uses
+	   the M68K keyboard now. */
+	ppc_md.kbd_setkeycode    = NULL;
+	ppc_md.kbd_getkeycode    = NULL;
+	ppc_md.kbd_translate     = NULL;
+	ppc_md.kbd_unexpected_up = NULL;
+	ppc_md.kbd_leds          = NULL;
+	ppc_md.kbd_init_hw       = NULL;
+	ppc_md.kbd_sysrq_xlate	 = NULL;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+        ppc_ide_md.insw = apus_ide_insw;
+        ppc_ide_md.outsw = apus_ide_outsw;
+        ppc_ide_md.default_irq = apus_ide_default_irq;
+        ppc_ide_md.default_io_base = apus_ide_default_io_base;
+        ppc_ide_md.check_region = apus_ide_check_region;
+        ppc_ide_md.request_region = apus_ide_request_region;
+        ppc_ide_md.release_region = apus_ide_release_region;
+        ppc_ide_md.fix_driveid = apus_ide_fix_driveid;
+        ppc_ide_md.ide_init_hwif = apus_ide_init_hwif_ports;
+
+        ppc_ide_md.io_base = _IO_BASE;
+#endif		
 }
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/chrp_pci.c linux/arch/ppc/kernel/chrp_pci.c
--- v2.2.7/linux/arch/ppc/kernel/chrp_pci.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/chrp_pci.c	Thu Apr 29 12:39:01 1999
@@ -15,10 +15,14 @@
 #include <asm/hydra.h>
 #include <asm/prom.h>
 #include <asm/gg2.h>
+#include <asm/ide.h>
+#include <asm/machdep.h>
+
+#include "pci.h"
 
 /* LongTrail */
 #define pci_config_addr(bus, dev, offset) \
-	(GG2_PCI_CONFIG_BASE | ((bus)<<16) | ((dev)<<8) | (offset))
+(GG2_PCI_CONFIG_BASE | ((bus)<<16) | ((dev)<<8) | (offset))
 
 volatile struct Hydra *Hydra = NULL;
 
@@ -30,149 +34,67 @@
 int gg2_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
 				 unsigned char offset, unsigned char *val)
 {
-    if (bus > 7) {
-	*val = 0xff;
-	return PCIBIOS_DEVICE_NOT_FOUND;
-    }
-    *val = in_8((unsigned char *)pci_config_addr(bus, dev_fn, offset));
-    return PCIBIOS_SUCCESSFUL;
+	if (bus > 7) {
+		*val = 0xff;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+	*val = in_8((unsigned char *)pci_config_addr(bus, dev_fn, offset));
+	return PCIBIOS_SUCCESSFUL;
 }
 
 int gg2_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
 				 unsigned char offset, unsigned short *val)
 {
-    if (bus > 7) {
-	*val = 0xffff;
-	return PCIBIOS_DEVICE_NOT_FOUND;
-    }
-    *val = in_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset));
-    return PCIBIOS_SUCCESSFUL;
+	if (bus > 7) {
+		*val = 0xffff;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+	*val = in_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset));
+	return PCIBIOS_SUCCESSFUL;
 }
 
 
 int gg2_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
 				  unsigned char offset, unsigned int *val)
 {
-    if (bus > 7) {
-	*val = 0xffffffff;
-	return PCIBIOS_DEVICE_NOT_FOUND;
-    }
-    *val = in_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset));
-    return PCIBIOS_SUCCESSFUL;
+	if (bus > 7) {
+		*val = 0xffffffff;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+	*val = in_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset));
+	return PCIBIOS_SUCCESSFUL;
 }
 
 int gg2_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
 				  unsigned char offset, unsigned char val)
 {
-    if (bus > 7)
-	return PCIBIOS_DEVICE_NOT_FOUND;
-    out_8((unsigned char *)pci_config_addr(bus, dev_fn, offset), val);
-    return PCIBIOS_SUCCESSFUL;
+	if (bus > 7)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	out_8((unsigned char *)pci_config_addr(bus, dev_fn, offset), val);
+	return PCIBIOS_SUCCESSFUL;
 }
 
 int gg2_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
 				  unsigned char offset, unsigned short val)
 {
-    if (bus > 7)
-	return PCIBIOS_DEVICE_NOT_FOUND;
-    out_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset), val);
-    return PCIBIOS_SUCCESSFUL;
+	if (bus > 7)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	out_le16((unsigned short *)pci_config_addr(bus, dev_fn, offset), val);
+	return PCIBIOS_SUCCESSFUL;
 }
 
 int gg2_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
 				   unsigned char offset, unsigned int val)
 {
-   if (bus > 7)
-	return PCIBIOS_DEVICE_NOT_FOUND;
-    out_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset), val);
-    return PCIBIOS_SUCCESSFUL;
-}
-
-extern volatile unsigned int *pci_config_address;
-extern volatile unsigned char *pci_config_data;
-
-#define DEV_FN_MAX (31<<3)
-
-int raven_pcibios_read_config_byte(unsigned char bus, 
-                                      unsigned char dev_fn,
-                                      unsigned char offset, 
-                                      unsigned char *val)
-{
-        if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
-        out_be32(pci_config_address,
-                 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
-        *val = in_8(pci_config_data+(offset&3));
-        return PCIBIOS_SUCCESSFUL;
-}
-
-int raven_pcibios_read_config_word(unsigned char bus, 
-                                      unsigned char dev_fn,
-                                      unsigned char offset, 
-                                      unsigned short *val)
-{
-        if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
-        if (offset&1)return PCIBIOS_BAD_REGISTER_NUMBER;
-        out_be32(pci_config_address,
-                 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
-        *val = in_le16((volatile unsigned short *)
-                       (pci_config_data+(offset&3)));
-        return PCIBIOS_SUCCESSFUL;
-}
-
-int raven_pcibios_read_config_dword(unsigned char bus, 
-                                       unsigned char dev_fn,
-                                       unsigned char offset, 
-                                       unsigned int *val)
-{
-        if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
-        if (offset&3)return PCIBIOS_BAD_REGISTER_NUMBER;
-        out_be32(pci_config_address,
-                 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24));
-        *val = in_le32((volatile unsigned int *)(pci_config_data));
-        return PCIBIOS_SUCCESSFUL;
-}
-
-int raven_pcibios_write_config_byte(unsigned char bus, 
-                                       unsigned char dev_fn,
-                                       unsigned char offset, 
-                                       unsigned char val) 
-{
-        if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
-        out_be32(pci_config_address,
-                 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
-        out_8(pci_config_data+(offset&3),val);
-        return PCIBIOS_SUCCESSFUL;
-}
-
-int raven_pcibios_write_config_word(unsigned char bus, 
-                                       unsigned char dev_fn,
-                                       unsigned char offset, 
-                                       unsigned short val) 
-{
-        if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
-        if (offset&1)return PCIBIOS_BAD_REGISTER_NUMBER;
-        out_be32(pci_config_address,
-                 0x80|(bus<<8)|(dev_fn<<16)|((offset&~3)<<24));
-        out_le16((volatile unsigned short *)(pci_config_data+(offset&3)),val);
-        return PCIBIOS_SUCCESSFUL;
-}
-
-int raven_pcibios_write_config_dword(unsigned char bus, 
-                                        unsigned char dev_fn,
-                                        unsigned char offset, 
-                                        unsigned int val) 
-{
-        if (dev_fn >= DEV_FN_MAX) return PCIBIOS_DEVICE_NOT_FOUND;
-        if (offset&3)return PCIBIOS_BAD_REGISTER_NUMBER;
-        out_be32(pci_config_address,
-                 0x80|(bus<<8)|(dev_fn<<16)|(offset<<24));
-        out_le32((volatile unsigned int *)pci_config_data,val);
-        return PCIBIOS_SUCCESSFUL;
+	if (bus > 7)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	out_le32((unsigned int *)pci_config_addr(bus, dev_fn, offset), val);
+	return PCIBIOS_SUCCESSFUL;
 }
 
 #define python_config_address(bus) (unsigned *)((0xfef00000+0xf8000)-(bus*0x100000))
 #define python_config_data(bus) ((0xfef00000+0xf8010)-(bus*0x100000))
-#define PYTHON_CFA(b, d, o)	(0x80 | ((b) << 8) | ((d) << 16) \
+#define PYTHON_CFA(b, d, o)	(0x80 | ((b<<6) << 8) | ((d) << 16) \
 				 | (((o) & ~3) << 24))
      
 int python_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
@@ -182,7 +104,7 @@
 		*val = 0xff;
 		return PCIBIOS_DEVICE_NOT_FOUND;
 	}
-	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset) );
+	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
 	*val = in_8((unsigned char *)python_config_data(bus) + (offset&3));
 	return PCIBIOS_SUCCESSFUL;
 }
@@ -194,7 +116,7 @@
 		*val = 0xffff;
 		return PCIBIOS_DEVICE_NOT_FOUND;
 	}
-	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset) );
+	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
 	*val = in_le16((unsigned short *)(python_config_data(bus) + (offset&3)));
 	return PCIBIOS_SUCCESSFUL;
 }
@@ -207,7 +129,7 @@
 		*val = 0xffffffff;
 		return PCIBIOS_DEVICE_NOT_FOUND;
 	}
-	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset) );
+	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
 	*val = in_le32((unsigned *)python_config_data(bus));
 	return PCIBIOS_SUCCESSFUL;
 }
@@ -217,7 +139,7 @@
 {
 	if (bus > 2)
 		return PCIBIOS_DEVICE_NOT_FOUND;
-	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset) );
+	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
 	out_8((volatile unsigned char *)python_config_data(bus) + (offset&3), val);
 	return PCIBIOS_SUCCESSFUL;
 }
@@ -227,7 +149,7 @@
 {
 	if (bus > 2)
 		return PCIBIOS_DEVICE_NOT_FOUND;
-	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset) );
+	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
 	out_le16((volatile unsigned short *)python_config_data(bus) + (offset&3),
 		 val);
 	return PCIBIOS_SUCCESSFUL;
@@ -238,7 +160,7 @@
 {
 	if (bus > 2)
 		return PCIBIOS_DEVICE_NOT_FOUND;
-	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset) );
+	out_be32( python_config_address( bus ), PYTHON_CFA(bus,dev_fn,offset));
 	out_le32((unsigned *)python_config_data(bus) + (offset&3), val);
 	return PCIBIOS_SUCCESSFUL;
 }
@@ -264,7 +186,8 @@
     	/* all others are 1 (= default) */
 };
 
-__initfunc(int hydra_init(void))
+int __init
+hydra_init(void)
 {
 	struct device_node *np;
 
@@ -287,4 +210,83 @@
 	OpenPIC_InitSenses = hydra_openpic_initsenses;
 	OpenPIC_NumInitSenses = sizeof(hydra_openpic_initsenses);
 	return 1;
+}
+
+void __init
+chrp_pcibios_fixup(void)
+{
+	struct pci_dev *dev;
+	
+	/* get the other 2 busses on the F50 */
+	if ( !strncmp("F5", get_property(find_path_device("/"),
+					 "ibm,model-class", NULL),2) )
+	{
+		pci_scan_peer_bridge(1);
+		pci_scan_peer_bridge(2);
+	}
+	
+	/* PCI interrupts are controlled by the OpenPIC */
+	for( dev=pci_devices ; dev; dev=dev->next )
+	{
+		if ( dev->irq )
+			dev->irq = openpic_to_irq( dev->irq );
+		/* adjust the io_port for the NCR cards for busses other than 0 -- Cort */
+		if ( (dev->bus->number > 0) && (dev->vendor == PCI_VENDOR_ID_NCR) )
+			dev->base_address[0] += (dev->bus->number*0x08000000);
+		/* these need to be absolute addrs for OF and Matrox FB -- Cort */
+		if ( dev->vendor == PCI_VENDOR_ID_MATROX )
+		{
+			if ( dev->base_address[0] < isa_mem_base )
+				dev->base_address[0] += isa_mem_base;
+			if ( dev->base_address[1] < isa_mem_base )
+				dev->base_address[1] += isa_mem_base;
+		}
+		/* the F50 identifies the amd as a trident */
+		if ( (dev->vendor == PCI_VENDOR_ID_TRIDENT) &&
+		      (dev->class == PCI_CLASS_NETWORK_ETHERNET) )
+		{
+			dev->vendor = PCI_VENDOR_ID_AMD;
+			pcibios_write_config_word(dev->bus->number, dev->devfn,
+						   PCI_VENDOR_ID, PCI_VENDOR_ID_AMD);
+		}
+	}
+}
+
+decl_config_access_method(grackle);
+decl_config_access_method(indirect);
+
+void __init
+chrp_setup_pci_ptrs(void)
+{
+        if ( !strncmp("MOT",
+                      get_property(find_path_device("/"), "model", NULL),3) )
+        {
+                pci_dram_offset = 0;
+                isa_mem_base = 0xf7000000;
+                isa_io_base = 0xfe000000;
+                set_config_access_method(grackle);
+        }
+        else
+        {
+		if ( find_compatible_devices( "pci", "IBM,python" ) )
+		{
+			/*
+			 * We assume these values but should someday get them
+			 * from the device tree or python itself instead -- Cort
+			 */
+			pci_dram_offset = 0x80000000;
+			isa_mem_base = 0xa0000000;
+			isa_io_base = 0x88000000;
+                        set_config_access_method(python);
+                }
+                else
+                {
+			pci_dram_offset = 0;
+			isa_mem_base = 0xf7000000;
+			isa_io_base = 0xf8000000;
+			set_config_access_method(gg2);
+                }
+        }
+	
+	ppc_md.pcibios_fixup = chrp_pcibios_fixup;
 }
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c
--- v2.2.7/linux/arch/ppc/kernel/chrp_setup.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/chrp_setup.c	Thu Apr 29 12:39:01 1999
@@ -41,8 +41,50 @@
 #include <asm/prom.h>
 #include <asm/gg2.h>
 #include <asm/pci-bridge.h>
-
-extern void hydra_init(void);
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/adb.h>
+#include <asm/hydra.h>
+
+#include "time.h"
+#include "local_irq.h"
+#include "i8259.h"
+#include "open_pic.h"
+
+/* Fixme - need to move these into their own .c and .h file */
+extern void i8259_mask_and_ack_irq(unsigned int irq_nr);
+extern void i8259_set_irq_mask(unsigned int irq_nr);
+extern void i8259_mask_irq(unsigned int irq_nr);
+extern void i8259_unmask_irq(unsigned int irq_nr);
+extern void i8259_init(void);
+
+/* Fixme - remove this when it is fixed. - Corey */
+extern volatile unsigned char *chrp_int_ack_special;
+
+unsigned long chrp_get_rtc_time(void);
+int chrp_set_rtc_time(unsigned long nowtime);
+void chrp_calibrate_decr(void);
+void chrp_time_init(void);
+
+void chrp_setup_pci_ptrs(void);
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+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];
+extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
+			    char raw_mode);
+extern char mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void mackbd_init_hw(void);
+extern unsigned char mackbd_sysrq_xlate[128];
 
 /* for the mac fs */
 kdev_t boot_dev;
@@ -61,17 +103,17 @@
 #endif
 
 static const char *gg2_memtypes[4] = {
-    "FPM", "SDRAM", "EDO", "BEDO"
+	"FPM", "SDRAM", "EDO", "BEDO"
 };
 static const char *gg2_cachesizes[4] = {
-    "256 KB", "512 KB", "1 MB", "Reserved"
+	"256 KB", "512 KB", "1 MB", "Reserved"
 };
 static const char *gg2_cachetypes[4] = {
-    "Asynchronous", "Reserved", "Flow-Through Synchronous",
-    "Pipelined Synchronous"
+	"Asynchronous", "Reserved", "Flow-Through Synchronous",
+	"Pipelined Synchronous"
 };
 static const char *gg2_cachemodes[4] = {
-    "Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
+	"Disabled", "Write-Through", "Copy-Back", "Transparent Mode"
 };
 
 int
@@ -84,7 +126,7 @@
 
 	root = find_path_device("/");
 	if (root)
-	    model = get_property(root, "model", NULL);
+		model = get_property(root, "model", NULL);
 	len = sprintf(buffer,"machine\t\t: CHRP %s\n", model);
 
 	/* longtrail (goldengate) stuff */
@@ -137,7 +179,7 @@
 	return len;
 }
 
-    /*
+/*
      *  Fixes for the National Semiconductor PC78308VUL SuperI/O
      *
      *  Some versions of Open Firmware incorrectly initialize the IRQ settings
@@ -146,56 +188,56 @@
 
 __initfunc(static inline void sio_write(u8 val, u8 index))
 {
-    outb(index, 0x15c);
-    outb(val, 0x15d);
+	outb(index, 0x15c);
+	outb(val, 0x15d);
 }
 
 __initfunc(static inline u8 sio_read(u8 index))
 {
-    outb(index, 0x15c);
-    return inb(0x15d);
+	outb(index, 0x15c);
+	return inb(0x15d);
 }
 
 __initfunc(static void sio_fixup_irq(const char *name, u8 device, u8 level,
 				     u8 type))
 {
-    u8 level0, type0, active;
+	u8 level0, type0, active;
 
-    /* select logical device */
-    sio_write(device, 0x07);
-    active = sio_read(0x30);
-    level0 = sio_read(0x70);
-    type0 = sio_read(0x71);
-    printk("sio: %s irq level %d, type %d, %sactive: ", name, level0, type0,
-	   !active ? "in" : "");
-    if (level0 == level && type0 == type && active)
-	printk("OK\n");
-    else {
-	printk("remapping to level %d, type %d, active\n", level, type);
-	sio_write(0x01, 0x30);
-	sio_write(level, 0x70);
-	sio_write(type, 0x71);
-    }
+	/* select logical device */
+	sio_write(device, 0x07);
+	active = sio_read(0x30);
+	level0 = sio_read(0x70);
+	type0 = sio_read(0x71);
+	printk("sio: %s irq level %d, type %d, %sactive: ", name, level0, type0,
+	       !active ? "in" : "");
+	if (level0 == level && type0 == type && active)
+		printk("OK\n");
+	else {
+		printk("remapping to level %d, type %d, active\n", level, type);
+		sio_write(0x01, 0x30);
+		sio_write(level, 0x70);
+		sio_write(type, 0x71);
+	}
 
 }
 
 __initfunc(static void sio_init(void))
 {
-    /* logical device 0 (KBC/Keyboard) */
-    sio_fixup_irq("keyboard", 0, 1, 2);
-    /* select logical device 1 (KBC/Mouse) */
-    sio_fixup_irq("mouse", 1, 12, 2);
+	/* logical device 0 (KBC/Keyboard) */
+	sio_fixup_irq("keyboard", 0, 1, 2);
+	/* select logical device 1 (KBC/Mouse) */
+	sio_fixup_irq("mouse", 1, 12, 2);
 }
 
 
 __initfunc(void
-chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
+	   chrp_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
 	extern char cmd_line[];
 
 	/* init to some ~sane value until calibrate_delay() runs */
 	loops_per_sec = 50000000;
-	
+
 #ifdef CONFIG_BLK_DEV_INITRD
 	/* this is fine for chrp */
 	initrd_below_start_ok = 1;
@@ -243,27 +285,207 @@
 	if ( !strncmp("MOT", get_property(find_path_device("/"),
 					  "model", NULL),3) )
 		*memory_start_p = pmac_find_bridges(*memory_start_p, *memory_end_p);
+	/*
+	 * The f50 has a lot of IO space - we need to map some in that
+	 * isn't covered by the BAT mappings in MMU_init() -- Cort
+	 */
+	if ( !strncmp("F5", get_property(find_path_device("/"),
+					 "ibm,model-class", NULL),2) )
+	{
+#if 0		
+		/*
+		 * This ugly hack allows us to force ioremap() to
+		 * create a 1-to-1 mapping for us, even though
+		 * the address is < ioremap_base.  This is necessary
+		 * since we want our PCI IO space to have contiguous
+		 * virtual addresses and I think it's worse to have
+		 * calls to map_page() here.
+		 * -- Cort
+		 */
+		unsigned long hold = ioremap_base;
+		ioremap_base = 0;
+		__ioremap(0x90000000, 0x10000000, _PAGE_NO_CACHE);
+		ioremap_base = hold;
+#endif		
+	}
 }
 
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+void
+chrp_restart(char *cmd)
+{
+#if 0
+	extern unsigned int rtas_entry, rtas_data, rtas_size;
+	printk("RTAS system-reboot returned %d\n",
+	       call_rtas("system-reboot", 0, 1, NULL));
+	printk("rtas_entry: %08lx rtas_data: %08lx rtas_size: %08lx\n",
+	       rtas_entry,rtas_data,rtas_size);
+	for (;;);
+#else
+	printk("System Halted\n");
+	while(1);
+#endif
+}
 
-unsigned int chrp_ide_irq = 0;
-int chrp_ide_ports_known = 0;
-ide_ioreg_t chrp_ide_regbase[MAX_HWIFS];
-ide_ioreg_t chrp_idedma_regbase;
+void
+chrp_power_off(void)
+{
+	/* RTAS doesn't seem to work on Longtrail.
+	   For now, do it the same way as the PReP. */
+#if 0
+	extern unsigned int rtas_entry, rtas_data, rtas_size;
+	printk("RTAS power-off returned %d\n",
+	       call_rtas("power-off", 2, 1, NULL, 0, 0));
+	printk("rtas_entry: %08lx rtas_data: %08lx rtas_size: %08lx\n",
+	       rtas_entry,rtas_data,rtas_size);
+	for (;;);
+#else
+	chrp_restart(NULL);
+#endif
+}
 
-void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+void
+chrp_halt(void)
 {
-        ide_ioreg_t port = base;
-        int i = 8;
+	chrp_restart(NULL);
+}
 
-        while (i--)
-                *p++ = port++;
-        *p++ = port;
-        if (irq != NULL)
-                *irq = chrp_ide_irq;
+u_int
+chrp_irq_cannonicalize(u_int irq)
+{
+	if (irq == 2)
+	{
+		return 9;
+	}
+	else
+	{
+		return irq;
+	}
+}
+
+void
+chrp_do_IRQ(struct pt_regs *regs,
+	    int            cpu,
+            int            isfake)
+{
+        int irq;
+        unsigned long bits = 0;
+        int openpic_eoi_done = 0;
+
+#ifdef __SMP__
+        {
+                unsigned int loops = 1000000;
+                while (test_bit(0, &global_irq_lock)) {
+                        if (smp_processor_id() == global_irq_holder) {
+                                printk("uh oh, interrupt while we hold global irq lock!\n");
+#ifdef CONFIG_XMON
+                                xmon(0);
+#endif
+                                break;
+                        }
+                        if (loops-- == 0) {
+                                printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
+#ifdef CONFIG_XMON
+                                xmon(0);
+#endif
+                        }
+                }
+        }
+#endif /* __SMP__ */
+
+        irq = openpic_irq(0);
+        if (irq == IRQ_8259_CASCADE)
+        {
+                /*
+                 * This magic address generates a PCI IACK cycle.
+                 *
+                 * This should go in the above mask/ack code soon. -- Cort
+                 */
+                irq = *chrp_int_ack_special;
+                /*
+                 * Acknowledge as soon as possible to allow i8259
+                 * interrupt nesting                         */
+                openpic_eoi(0);
+                openpic_eoi_done = 1;
+        }
+        if (irq == OPENPIC_VEC_SPURIOUS)
+        {
+                /*
+                 * Spurious interrupts should never be
+                 * acknowledged
+                 */
+                ppc_spurious_interrupts++;
+                openpic_eoi_done = 1;
+		goto out;
+        }
+        bits = 1UL << irq;
+
+        if (irq < 0)
+        {
+                printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+                       irq, regs->nip);
+                ppc_spurious_interrupts++;
+        }
+	else
+        {
+		ppc_irq_dispatch_handler( regs, irq );
+	}
+out:
+        if (!openpic_eoi_done)
+                openpic_eoi(0);
 }
 
+__initfunc(void
+	   chrp_init_IRQ(void))
+{
+	struct device_node *np;
+	int i;
+
+	if ( !(np = find_devices("pci") ) )
+		printk("Cannot find pci to get ack address\n");
+	else
+	{
+		chrp_int_ack_special = (volatile unsigned char *)
+			(*(unsigned long *)get_property(np,
+							"8259-interrupt-acknowledge", NULL));
+	}
+	for ( i = 16 ; i < NR_IRQS ; i++ )
+		irq_desc[i].ctl = &open_pic;
+	/* openpic knows that it's at irq 16 offset
+	 * so we don't need to set it in the pic structure
+	 * -- Cort
+	 */
+	openpic_init(1);
+	for ( i = 0 ; i < 16  ; i++ )
+		irq_desc[i].ctl = &i8259_pic;
+	i8259_init();
+#ifdef CONFIG_XMON
+	request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI),
+		    xmon_irq, 0, "NMI", 0);
+#endif	/* CONFIG_XMON */
+#ifdef __SMP__
+	request_irq(openpic_to_irq(OPENPIC_VEC_IPI),
+		    openpic_ipi_action, 0, "IPI0", 0);
+#endif	/* __SMP__ */
+}
+
+__initfunc(void
+	   chrp_init2(void))
+{
+	adb_init();
+
+	/* Should this be here? - Corey */
+	pmac_nvram_init();
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+unsigned int chrp_ide_irq = 0;
+int chrp_ide_ports_known = 0;
+ide_ioreg_t chrp_ide_regbase[MAX_HWIFS];
+ide_ioreg_t chrp_idedma_regbase;
+
 void chrp_ide_probe(void) {
 
         struct pci_dev *pdev = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, NULL);
@@ -281,9 +503,167 @@
         }
 }
 
+void
+chrp_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+	ide_insw(port+_IO_BASE, buf, ns);
+}
+
+void
+chrp_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+	ide_outsw(port+_IO_BASE, buf, ns);
+}
+
+int
+chrp_ide_default_irq(ide_ioreg_t base)
+{
+        if (chrp_ide_ports_known == 0)
+	        chrp_ide_probe();
+	return chrp_ide_irq;
+}
+
+ide_ioreg_t
+chrp_ide_default_io_base(int index)
+{
+        if (chrp_ide_ports_known == 0)
+	        chrp_ide_probe();
+	return chrp_ide_regbase[index];
+}
+
+int
+chrp_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+        return check_region(from, extent);
+}
+
+void
+chrp_ide_request_region(ide_ioreg_t from,
+			unsigned int extent,
+			const char *name)
+{
+        request_region(from, extent, name);
+}
+
+void
+chrp_ide_release_region(ide_ioreg_t from,
+			unsigned int extent)
+{
+        release_region(from, extent);
+}
+
+void
+chrp_ide_fix_driveid(struct hd_driveid *id)
+{
+        ppc_generic_ide_fix_driveid(id);
+}
+
+void chrp_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+        ide_ioreg_t port = base;
+        int i = 8;
+
+        while (i--)
+                *p++ = port++;
+        *p++ = port;
+        if (irq != NULL)
+                *irq = chrp_ide_irq;
+}
+
 EXPORT_SYMBOL(chrp_ide_irq);
 EXPORT_SYMBOL(chrp_ide_ports_known);
 EXPORT_SYMBOL(chrp_ide_regbase);
 EXPORT_SYMBOL(chrp_ide_probe);
 
 #endif
+
+__initfunc(void
+	   chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
+		     unsigned long r6, unsigned long r7))
+{
+	chrp_setup_pci_ptrs();
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* take care of initrd if we have one */
+	if ( r3 )
+	{
+		initrd_start = r3 + KERNELBASE;
+		initrd_end = r3 + r4 + KERNELBASE;
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+        /* pci_dram_offset/isa_io_base/isa_mem_base set by setup_pci_ptrs() */
+	ISA_DMA_THRESHOLD = ~0L;
+	DMA_MODE_READ = 0x44;
+	DMA_MODE_WRITE = 0x48;
+
+	ppc_md.setup_arch     = chrp_setup_arch;
+	ppc_md.setup_residual = NULL;
+	ppc_md.get_cpuinfo    = chrp_get_cpuinfo;
+	ppc_md.irq_cannonicalize = chrp_irq_cannonicalize;
+	ppc_md.init_IRQ       = chrp_init_IRQ;
+	ppc_md.do_IRQ         = chrp_do_IRQ;
+		
+	ppc_md.init           = chrp_init2;
+
+	ppc_md.restart        = chrp_restart;
+	ppc_md.power_off      = chrp_power_off;
+	ppc_md.halt           = chrp_halt;
+
+	ppc_md.time_init      = chrp_time_init;
+	ppc_md.set_rtc_time   = chrp_set_rtc_time;
+	ppc_md.get_rtc_time   = chrp_get_rtc_time;
+	ppc_md.calibrate_decr = chrp_calibrate_decr;
+
+#ifdef CONFIG_VT
+#ifdef CONFIG_MAC_KEYBOAD
+	if ( adb_hardware == ADB_NONE )
+	{
+		ppc_md.kbd_setkeycode    = pckbd_setkeycode;
+		ppc_md.kbd_getkeycode    = pckbd_getkeycode;
+		ppc_md.kbd_translate     = pckbd_translate;
+		ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+		ppc_md.kbd_leds          = pckbd_leds;
+		ppc_md.kbd_init_hw       = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+		ppc_md.kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+#endif		
+	}
+	else
+	{
+		ppc_md.kbd_setkeycode    = mackbd_setkeycode;
+		ppc_md.kbd_getkeycode    = mackbd_getkeycode;
+		ppc_md.kbd_translate     = mackbd_translate;
+		ppc_md.kbd_unexpected_up = mackbd_unexpected_up;
+		ppc_md.kbd_leds          = mackbd_leds;
+		ppc_md.kbd_init_hw       = mackbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+		ppc_md.kbd_sysrq_xlate	 = mackbd_sysrq_xlate;
+#endif		
+	}
+#else
+	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
+	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
+	ppc_md.kbd_translate     = pckbd_translate;
+	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+	ppc_md.kbd_leds          = pckbd_leds;
+	ppc_md.kbd_init_hw       = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+#endif
+#endif
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+        ppc_ide_md.insw = chrp_ide_insw;
+        ppc_ide_md.outsw = chrp_ide_outsw;
+        ppc_ide_md.default_irq = chrp_ide_default_irq;
+        ppc_ide_md.default_io_base = chrp_ide_default_io_base;
+        ppc_ide_md.check_region = chrp_ide_check_region;
+        ppc_ide_md.request_region = chrp_ide_request_region;
+        ppc_ide_md.release_region = chrp_ide_release_region;
+        ppc_ide_md.fix_driveid = chrp_ide_fix_driveid;
+        ppc_ide_md.ide_init_hwif = chrp_ide_init_hwif_ports;
+
+        ppc_ide_md.io_base = _IO_BASE;
+#endif		
+}
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- v2.2.7/linux/arch/ppc/kernel/head.S	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/head.S	Thu Apr 29 12:39:01 1999
@@ -1,7 +1,7 @@
 /*
  *  arch/ppc/kernel/head.S
  *
- *  $Id: head.S,v 1.121 1999/03/16 10:40:29 cort Exp $
+ *  $Id: head.S,v 1.127 1999/04/07 07:26:55 paulus Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -91,7 +91,7 @@
 #define tlbia \
 	li	r4,128; \
 	mtctr	r4; \
-	lis	r4,0xC000; \
+	lis	r4,KERNELBASE@h; \
 0:	tlbie	r4; \
 	addi	r4,r4,0x1000; \
 	bdnz	0b
@@ -415,7 +415,7 @@
  * this, we leave this much untouched space on the stack on exception
  * entry.
  */
-#define STACK_UNDERHEAD	64
+#define STACK_UNDERHEAD	0
 	
 /*
  * Exception entry code.  This code runs with address translation
@@ -1495,27 +1495,25 @@
  * On SMP we know the fpu is free, since we give it up every
  * switch.  -- Cort
  */
+	mfmsr	r5
+	ori	r5,r5,MSR_FP
+	SYNC
+	mtmsr	r5			/* enable use of fpu now */
+	SYNC
+/*
+ * For SMP, we don't do lazy FPU switching because it just gets too
+ * horrendously complex, especially when a task switches from one CPU
+ * to another.  Instead we call giveup_fpu in switch_to.
+ */
+#ifndef __SMP__
 #ifndef CONFIG_APUS
 	lis	r6,-KERNELBASE@h
 #else
 	lis	r6,CYBERBASEp@h
 	lwz	r6,0(r6)
 #endif
-
 	addis	r3,r6,last_task_used_math@ha
 	lwz	r4,last_task_used_math@l(r3)
-	mfmsr	r5
-	ori	r5,r5,MSR_FP
-	SYNC
-	mtmsr	r5			/* enable use of fpu now */
-/*
- * All the saving of last_task_used_math is handled
- * by a switch_to() call to smp_giveup_fpu() in SMP so 
- * last_task_used_math is not used.
- * -- Cort
- */
-#ifndef __SMP__
-	SYNC
 	cmpi	0,r4,0
 	beq	1f
 	add	r4,r4,r6
@@ -1529,15 +1527,17 @@
 	li	r20,MSR_FP|MSR_FE0|MSR_FE1
 	andc	r4,r4,r20		/* disable FP for previous task */
 	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
 #endif /* __SMP__ */
-1:	ori	r23,r23,MSR_FP|MSR_FE0|MSR_FE1	/* enable use of FP after return */
+	/* enable use of FP after return */
+	ori	r23,r23,MSR_FP|MSR_FE0|MSR_FE1
 	mfspr	r5,SPRG3		/* current task's TSS (phys) */
 	lfd	fr0,TSS_FPSCR-4(r5)
 	mtfsf	0xff,fr0
 	REST_32FPRS(0, r5)
+#ifndef __SMP__
 	subi	r4,r5,TSS
 	sub	r4,r4,r6
-#ifndef __SMP__
 	stw	r4,last_task_used_math@l(r3)
 #endif /* __SMP__ */
 	/* restore registers and return */
@@ -1574,48 +1574,44 @@
 	.align	4
 
 /*
- * Disable FP for the task which had the FPU previously,
- * and save its floating-point registers in its thread_struct.
+ * giveup_fpu(tsk)
+ * Disable FP for the task given as the argument,
+ * and save the floating-point registers in its thread_struct.
  * Enables the FPU for use in the kernel on return.
  */
-/* smp_giveup_fpu() takes an arg to tell it where to save the fpu
- * regs since last_task_used_math can't be trusted (many many race
- * conditions). -- Cort
- */
-	.globl	smp_giveup_fpu
-smp_giveup_fpu:	
-	mr	r4,r3
-	b	12f
 	.globl	giveup_fpu
 giveup_fpu:
-	lis	r3,last_task_used_math@ha
-	lwz	r4,last_task_used_math@l(r3)
-12:		
 	mfmsr	r5
 	ori	r5,r5,MSR_FP
 	SYNC
 	mtmsr	r5			/* enable use of fpu now */
 	SYNC
-	cmpi	0,r4,0
+	cmpi	0,r3,0
 	beqlr-				/* if no previous owner, done */
-	addi	r4,r4,TSS	        /* want TSS of last_task_used_math */
+	addi	r3,r3,TSS	        /* want TSS of task */
+	lwz	r5,PT_REGS(r3)
+	cmpi	0,r5,0
+	SAVE_32FPRS(0, r3)
+	mffs	fr0
+	stfd	fr0,TSS_FPSCR-4(r3)
+	beq	1f
+	lwz	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+	li	r3,MSR_FP|MSR_FE0|MSR_FE1
+	andc	r4,r4,r3		/* disable FP for previous task */
+	stw	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
+1:
 #ifndef __SMP__
 	li	r5,0
-	stw	r5,last_task_used_math@l(r3)
+	lis	r4,last_task_used_math@ha
+	stw	r5,last_task_used_math@l(r4)
 #endif /* __SMP__ */
-	SAVE_32FPRS(0, r4)
-	mffs	fr0
-	stfd	fr0,TSS_FPSCR-4(r4)
-	lwz	r5,PT_REGS(r4)
-	lwz	r3,_MSR-STACK_FRAME_OVERHEAD(r5)
-	li	r4,MSR_FP|MSR_FE0|MSR_FE1
-	andc	r3,r3,r4		/* disable FP for previous task */
-	stw	r3,_MSR-STACK_FRAME_OVERHEAD(r5)
+	blr
+
 #else  /* CONFIG_8xx */
 	.globl	giveup_fpu
 giveup_fpu:
-#endif /* CONFIG_8xx */
 	blr
+#endif /* CONFIG_8xx */
 
 /*
  * This code is jumped to from the startup code to copy
@@ -2127,8 +2123,8 @@
 	lwz	r5,_MSR(r1)
 	and.	r5,r5,r4
 	beq	2f
-3:	lis	r4,n_lost_interrupts@ha
-	lwz	r4,n_lost_interrupts@l(r4)
+3:	lis	r4,ppc_n_lost_interrupts@ha
+	lwz	r4,ppc_n_lost_interrupts@l(r4)
 	cmpi	0,r4,0
 	beq+	1f
 	addi	r3,r1,STACK_FRAME_OVERHEAD
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/i8259.c linux/arch/ppc/kernel/i8259.c
--- v2.2.7/linux/arch/ppc/kernel/i8259.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/i8259.c	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,96 @@
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include "i8259.h"
+
+unsigned char cached_8259[2] = { 0xff, 0xff };
+#define cached_A1 (cached_8259[0])
+#define cached_21 (cached_8259[1])
+
+static void i8259_mask_and_ack_irq(unsigned int irq_nr)
+{
+        if ( irq_nr >= i8259_pic.irq_offset )
+                irq_nr -= i8259_pic.irq_offset;
+
+        if (irq_nr > 7) {                                                   
+                cached_A1 |= 1 << (irq_nr-8);                                   
+                inb(0xA1);      /* DUMMY */                                     
+                outb(cached_A1,0xA1);                                           
+                outb(0x20,0xA0);        /* Non-specific EOI */             
+                outb(0x20,0x20);        /* Non-specific EOI to cascade */
+        } else {                                                            
+                cached_21 |= 1 << irq_nr;                                   
+                inb(0x21);      /* DUMMY */                                 
+                outb(cached_21,0x21);
+                outb(0x20,0x20);        /* Non-specific EOI */                 
+        }                                                                
+}
+
+static void i8259_set_irq_mask(int irq_nr)
+{
+        outb(cached_A1,0xA1);
+        outb(cached_21,0x21);
+}
+
+static void i8259_mask_irq(unsigned int irq_nr)
+{
+        if ( irq_nr >= i8259_pic.irq_offset )
+                irq_nr -= i8259_pic.irq_offset;
+        if ( irq_nr < 8 )
+                cached_21 |= 1 << irq_nr;
+        else
+                cached_A1 |= 1 << (irq_nr-8);
+        i8259_set_irq_mask(irq_nr);
+}
+
+static void i8259_unmask_irq(unsigned int irq_nr)
+{
+
+        if ( irq_nr >= i8259_pic.irq_offset )
+                irq_nr -= i8259_pic.irq_offset;
+        if ( irq_nr < 8 )
+                cached_21 &= ~(1 << irq_nr);
+        else
+                cached_A1 &= ~(1 << (irq_nr-8));
+        i8259_set_irq_mask(irq_nr);
+}
+
+struct hw_interrupt_type i8259_pic = {
+        " i8259    ",
+        NULL,
+        NULL,
+        NULL,
+        i8259_unmask_irq,
+        i8259_mask_irq,
+        i8259_mask_and_ack_irq,
+        0
+};
+
+static void
+no_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+}
+
+void __init i8259_init(void)
+{
+        /* init master interrupt controller */
+        outb(0x11, 0x20); /* Start init sequence */
+        outb(0x00, 0x21); /* Vector base */
+        outb(0x04, 0x21); /* edge tiggered, 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(0x08, 0xA1); /* Vector base */
+        outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
+        outb(0x01, 0xA1); /* Select 8086 mode */
+        outb(0xFF, 0xA1); /* Mask all */
+        outb(cached_A1, 0xA1);
+        outb(cached_21, 0x21);
+        request_irq( i8259_pic.irq_offset + 2, no_action, SA_INTERRUPT,
+                     "82c59 secondary cascade", NULL );
+        enable_irq(i8259_pic.irq_offset + 2);  /* Enable cascade interrupt */
+}
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/i8259.h linux/arch/ppc/kernel/i8259.h
--- v2.2.7/linux/arch/ppc/kernel/i8259.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/i8259.h	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,11 @@
+
+#ifndef _PPC_KERNEL_i8259_H
+#define _PPC_KERNEL_i8259_H
+
+#include "local_irq.h"
+
+extern struct hw_interrupt_type i8259_pic;
+
+void i8259_init(void);
+
+#endif /* _PPC_KERNEL_i8259_H */
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c
--- v2.2.7/linux/arch/ppc/kernel/idle.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/idle.c	Thu Apr 29 12:39:01 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: idle.c,v 1.60 1999/02/12 07:06:26 cort Exp $
+ * $Id: idle.c,v 1.61 1999/03/18 04:15:45 cort Exp $
  *
  * Idle daemon for PowerPC.  Idle daemon will handle any action
  * that needs to be taken when the system becomes idle.
@@ -303,7 +303,14 @@
 			hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE);
 			hid0 |= (powersave_nap? HID0_NAP: HID0_DOZE) | HID0_DPM;
 			asm("mtspr 1008,%0" : : "r" (hid0));
-			msr |= MSR_POW;
+		
+			/* set the POW bit in the MSR, and enable interrupts
+			 * so we wake up sometime! */
+			_nmask_and_or_msr(0, MSR_POW | MSR_EE);
+
+			/* Disable interrupts again so restore_flags will
+			 * work. */
+			_nmask_and_or_msr(MSR_EE, 0);
 		}
 		restore_flags(msr);
 	default:
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/indirect_pci.c linux/arch/ppc/kernel/indirect_pci.c
--- v2.2.7/linux/arch/ppc/kernel/indirect_pci.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/indirect_pci.c	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,121 @@
+/*
+ * Support for indirect PCI bridges.
+ *
+ * Copyright (C) 1998 Gabriel Paubert.
+ *
+ * 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/pci.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+unsigned int * pci_config_address;
+unsigned char * pci_config_data;
+
+int indirect_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned char *val)
+{
+	unsigned flags;
+
+	save_flags(flags); cli();
+	
+	out_be32(pci_config_address, 
+		 ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+	*val= in_8(pci_config_data + (offset&3));
+
+	restore_flags(flags);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned short *val)
+{
+	unsigned flags;
+	
+	if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	save_flags(flags); cli();
+	
+	out_be32(pci_config_address, 
+		 ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+	*val= in_le16((unsigned short *)(pci_config_data + (offset&3)));
+
+	restore_flags(flags);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned int *val)
+{
+	unsigned flags;
+	
+	if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	save_flags(flags); cli();
+	
+	out_be32(pci_config_address, 
+		 ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+	*val= in_le32((unsigned *)pci_config_data);
+
+	restore_flags(flags);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned char val)
+{
+	unsigned flags;
+
+	save_flags(flags); cli();
+	
+	out_be32(pci_config_address, 
+		 ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+	out_8(pci_config_data + (offset&3), val);
+
+	restore_flags(flags);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned short val)
+{
+	unsigned flags;
+
+	if (offset&1) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	save_flags(flags); cli();
+	
+	out_be32(pci_config_address, 
+		 ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+	out_le16((unsigned short *)(pci_config_data + (offset&3)), val);
+
+	restore_flags(flags);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int indirect_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+			     unsigned char offset, unsigned short val)
+{
+	unsigned flags;
+
+	if (offset&3) return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	save_flags(flags); cli();
+	
+	out_be32(pci_config_address, 
+		 ((offset&0xfc)<<24) | (dev_fn<<16) | (bus<<8) | 0x80);
+
+	out_le32((unsigned *)pci_config_data, val);
+
+	restore_flags(flags);
+	return PCIBIOS_SUCCESSFUL;
+}
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.2.7/linux/arch/ppc/kernel/irq.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/irq.c	Thu Apr 29 12:39:01 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: irq.c,v 1.102 1999/02/03 01:36:59 paulus Exp $
+ * $Id: irq.c,v 1.105 1999/03/25 19:51:51 cort Exp $
  *
  *  arch/ppc/kernel/irq.c
  *
@@ -58,44 +58,15 @@
 #include <asm/amigahw.h>
 #include <asm/amigappc.h>
 #include <asm/ptrace.h>
-#ifdef CONFIG_8xx
-#include <asm/8xx_immap.h>
-#include <asm/mbx.h>
-#endif
 
-static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
+#include "local_irq.h"
+
 extern volatile unsigned long ipi_count;
-static void dispatch_handler(struct pt_regs *regs, int irq);
 void enable_irq(unsigned int irq_nr);
 void disable_irq(unsigned int irq_nr);
 
-static void i8259_mask_and_ack_irq(unsigned int irq_nr);
-static void i8259_mask_irq(unsigned int irq_nr);
-static void i8259_unmask_irq(unsigned int irq_nr);
-#ifdef CONFIG_8xx
-static void mbx_mask_and_ack(unsigned int irq_nr);
-static void mbx_mask_irq(unsigned int irq_nr);
-static void mbx_unmask_irq(unsigned int irq_nr);
-static void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs);
-#else /* CONFIG_8xx */
-static volatile unsigned char *chrp_int_ack_special;
-extern void process_int(unsigned long vec, struct pt_regs *fp);
-extern void apus_init_IRQ(void);
-extern void amiga_disable_irq(unsigned int irq);
-extern void amiga_enable_irq(unsigned int irq);
-static void pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base);
-static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs);
-static void pmac_mask_irq(unsigned int irq_nr);
-static void pmac_unmask_irq(unsigned int irq_nr);
-static void pmac_mask_and_ack_irq(unsigned int irq_nr);
-static void chrp_mask_and_ack_irq(unsigned int irq_nr);
-static void chrp_unmask_irq(unsigned int irq_nr);
-static void chrp_mask_irq(unsigned int irq_nr);
-#ifdef __SMP__	
-static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
-extern void smp_message_recv(void);
-#endif /* __SMP__ */
-#endif /* CONFIG_8xx */
+/* Fixme - Need to figure out a way to get rid of this - Corey */
+volatile unsigned char *chrp_int_ack_special;
 
 #ifdef CONFIG_APUS
 /* Rename a few functions. Requires the CONFIG_APUS protection. */
@@ -105,39 +76,19 @@
 #define VEC_SPUR    (24)
 #endif
 
+#define MAXCOUNT 10000000
+
 #define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
-unsigned char cached_8259[2] = { 0xff, 0xff };
-#define cached_A1 (cached_8259[0])
-#define cached_21 (cached_8259[1])
-
-unsigned int local_bh_count[NR_CPUS];
-unsigned int local_irq_count[NR_CPUS];
-int max_irqs;
-int max_real_irqs;
-static int spurious_interrupts = 0;
-static unsigned int cached_irq_mask[NR_MASK_WORDS];
-unsigned int lost_interrupts[NR_MASK_WORDS];
-atomic_t n_lost_interrupts;
-
-#ifndef CONFIG_8xx
-#define GATWICK_IRQ_POOL_SIZE	10
-static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
-/* pmac */
-struct pmac_irq_hw {
-	unsigned int	flag;
-	unsigned int	enable;
-	unsigned int	ack;
-	unsigned int	level;
-};
-
-/* these addresses are obtained from the device tree now -- Cort */
-volatile struct pmac_irq_hw *pmac_irq_hw[4] __pmac = {
-	(struct pmac_irq_hw *) 0xf3000020,
-	(struct pmac_irq_hw *) 0xf3000010,
-	(struct pmac_irq_hw *) 0xf4000020,
-	(struct pmac_irq_hw *) 0xf4000010,
-};
-#endif /* CONFIG_8xx */
+
+int ppc_spurious_interrupts = 0;
+
+unsigned int ppc_local_bh_count[NR_CPUS];
+unsigned int ppc_local_irq_count[NR_CPUS];
+struct irqaction *ppc_irq_action[NR_IRQS];
+unsigned int ppc_cached_irq_mask[NR_MASK_WORDS];
+unsigned int ppc_lost_interrupts[NR_MASK_WORDS];
+atomic_t ppc_n_lost_interrupts;
+
 
 /* nasty hack for shared irq's since we need to do kmalloc calls but
  * can't very early in the boot when we need to do a request irq.
@@ -174,82 +125,7 @@
 	kfree(ptr);
 }
 
-struct hw_interrupt_type {
-	const char * typename;
-	void (*startup)(unsigned int irq);
-	void (*shutdown)(unsigned int irq);
-	void (*handle)(unsigned int irq, struct pt_regs * regs);
-	void (*enable)(unsigned int irq);
-	void (*disable)(unsigned int irq);
-	void (*mask_and_ack)(unsigned int irq);
-	int irq_offset;
-};
-
-#define mask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->disable) irq_desc[irq].ctl->disable(irq);})
-#define unmask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->enable) irq_desc[irq].ctl->enable(irq);})
-#define mask_and_ack_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->mask_and_ack) irq_desc[irq].ctl->mask_and_ack(irq);})
-
-struct irqdesc {
-	struct irqaction *action;
-	struct hw_interrupt_type *ctl;
-};
-static struct irqdesc irq_desc[NR_IRQS] = {{0, 0}, };
-
-static struct hw_interrupt_type i8259_pic = {
-	" i8259    ",
-	NULL,
-	NULL,
-	NULL,
-	i8259_unmask_irq,
-	i8259_mask_irq,
-	i8259_mask_and_ack_irq,
-	0
-};
-#ifndef CONFIG_8xx
-static struct hw_interrupt_type pmac_pic = {
-	" PMAC-PIC ",
-	NULL,
-	NULL,
-	NULL,
-	pmac_unmask_irq,
-	pmac_mask_irq,
-	pmac_mask_and_ack_irq,
-	0
-};
-
-static struct hw_interrupt_type gatwick_pic = {
-	" GATWICK  ",
-	NULL,
-	NULL,
-	NULL,
-	pmac_unmask_irq,
-	pmac_mask_irq,
-	pmac_mask_and_ack_irq,
-	0
-};
-
-static struct hw_interrupt_type open_pic = {
-	" OpenPIC  ",
-	NULL,
-	NULL,
-	NULL,
-	chrp_unmask_irq,
-	chrp_mask_irq,
-	chrp_mask_and_ack_irq,
-	0
-};
-#else
-static struct hw_interrupt_type ppc8xx_pic = {
-	" 8xx SIU  ",
-	NULL,
-	NULL,
-	NULL,
-	mbx_unmask_irq,
-	mbx_mask_irq,
-	mbx_mask_and_ack,
-	0
-};
-#endif /* CONFIG_8xx */
+struct irqdesc irq_desc[NR_IRQS] = {{0, 0}, };
 
 int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
 	unsigned long irqflags, const char * devname, void *dev_id)
@@ -357,19 +233,17 @@
 	}
 #ifdef __SMP__
 	/* should this be per processor send/receive? */
-	len += sprintf(buf+len, "IPI: %10lu", ipi_count);
-	for ( i = 0 ; i <= smp_num_cpus-1; i++ )
-		len += sprintf(buf+len,"          ");
-	len += sprintf(buf+len, "     interprocessor messages received\n");
+	len += sprintf(buf+len, "IPI: %10lu\n", ipi_count);
 #endif		
-	len += sprintf(buf+len, "BAD: %10u",spurious_interrupts);
-	for ( i = 0 ; i <= smp_num_cpus-1; i++ )
-		len += sprintf(buf+len,"        ");
-	len += sprintf(buf+len, "         spurious or short\n");
+	len += sprintf(buf+len, "BAD: %10u\n", ppc_spurious_interrupts);
 	return len;
 }
 
-static void dispatch_handler(struct pt_regs *regs, int irq)
+/*
+ * Eventually, this should take an array of interrupts and an array size
+ * so it can dispatch multiple interrupts.
+ */
+void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq)
 {
 	int status;
 	struct irqaction *action;
@@ -390,209 +264,18 @@
 		__cli();
 		unmask_irq(irq);
 	} else {
-		spurious_interrupts++;
+		ppc_spurious_interrupts++;
 		disable_irq( irq );
 	}
 }
 
-#define MAXCOUNT 100000000
 asmlinkage void do_IRQ(struct pt_regs *regs, int isfake)
 {
-	int irq;
-	unsigned long bits = 0;
 	int cpu = smp_processor_id();
-	int openpic_eoi_done = 0;
-
-	hardirq_enter(cpu);
-#ifndef CONFIG_8xx		  
-#ifdef __SMP__
-	/* IPI's are a hack on the powersurge -- Cort */
-	if ( (_machine == _MACH_Pmac) && (cpu != 0) )
-	{
-		if (!isfake)
-		{
-#ifdef CONFIG_XMON
-			static int xmon_2nd;
-			if (xmon_2nd)
-				xmon(regs);
-#endif
-			smp_message_recv();
-			goto out;
-		}
-		/* could be here due to a do_fake_interrupt call but we don't
-		   mess with the controller from the second cpu -- Cort */
-		goto out;
-	}
-
-	{
-		unsigned int loops = MAXCOUNT;
-		while (test_bit(0, &global_irq_lock)) {
-			if (smp_processor_id() == global_irq_holder) {
-				printk("uh oh, interrupt while we hold global irq lock!\n");
-#ifdef CONFIG_XMON
-				xmon(0);
-#endif
-				break;
-			}
-			if (loops-- == 0) {
-				printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
-#ifdef CONFIG_XMON
-				xmon(0);
-#endif
-			}
-		}
-	}
-#endif /* __SMP__ */			
-
-	switch ( _machine )
-	{
-	case _MACH_Pmac:
-		for (irq = max_real_irqs - 1; irq > 0; irq -= 32) {
-			int i = irq >> 5;
-			bits = ld_le32(&pmac_irq_hw[i]->flag)
-				| lost_interrupts[i];
-			if (bits == 0)
-				continue;
-			irq -= cntlzw(bits);
-			break;
-		}
-		break;
-	case _MACH_chrp:
-		irq = openpic_irq(0);
-		if (irq == IRQ_8259_CASCADE)
-		{
-			/*
-			 * This magic address generates a PCI IACK cycle.
-			 * 
-			 * This should go in the above mask/ack code soon. -- Cort
-			 */
-			irq = *chrp_int_ack_special;
-			/*
-			 * Acknowledge as soon as possible to allow i8259
-			 * interrupt nesting
-			 */
-			openpic_eoi(0);
-			openpic_eoi_done = 1;
-		}
-		if (irq == OPENPIC_VEC_SPURIOUS)
-		{
-				/*
-				 * Spurious interrupts should never be
-				 * acknowledged
-				 */
-			spurious_interrupts++;
-			openpic_eoi_done = 1;
-		}
-		bits = 1UL << irq;
-		break;
-	case _MACH_prep:
-		outb(0x0C, 0x20);
-		irq = inb(0x20) & 7;
-		if (irq == 2)
-		{
-			outb(0x0C, 0xA0);
-			irq = (inb(0xA0) & 7) + 8;
-			bits |= 1UL << irq;
-#if 0			
-			/* It's possible to loose intrs here
-			 * if we get 2 intrs in the upper 8
-			 * bits.  We eoi irq 2 and handle one of
-			 * the upper intrs but then ignore it
-			 * since we've already eoi-d 2.  So,
-			 * we must keep track of lost intrs.
-			 * -- Cort
-			 */
-			while (1)
-			{
-				int i;
-				outb(0x0C, 0xA0);
-				i = inb(0xA0);
-				if ( !(i & 128) )
-					break;
-				irq &= 7;
-				irq += 8;
-				bits |= 1UL << irq;
-			}
-#endif			
-		}
-		else
-			bits = 1UL << irq;
-		  
-		break;
-#ifdef CONFIG_APUS
-	case _MACH_apus:
-	{
-		int old_level, new_level;
-
-		old_level = ~(regs->mq) & IPLEMU_IPLMASK;
-		new_level = (~(regs->mq) >> 3) & IPLEMU_IPLMASK;
-		
-		if (new_level == 0)
-		{
-			goto apus_out;
-		}
-		
-		APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
-		APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
-					  | (~(new_level) & IPLEMU_IPLMASK)));
-		APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
-		
-		process_int (VEC_SPUR+new_level, regs);
-		
-		APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_DISABLEINT);
-		APUS_WRITE(APUS_IPL_EMU, IPLEMU_IPLMASK);
-		APUS_WRITE(APUS_IPL_EMU, (IPLEMU_SETRESET
-					  | (~(old_level) & IPLEMU_IPLMASK)));
-apus_out:
-		hardirq_exit(cpu);
-		APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT);
-		goto out2;
-	}
-#endif	
-	}
 
-	if (irq < 0)
-	{
-		printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
-		       irq, regs->nip);
-		spurious_interrupts++;
-		goto out;
-	}					
-	
-#else /* CONFIG_8xx */
-	/* For MPC8xx, read the SIVEC register and shift the bits down
-	 * to get the irq number.
-	 */
-	bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
-	irq = bits >> 26;
-	irq += ppc8xx_pic.irq_offset;
-	bits = 1UL << irq;
-#endif /* CONFIG_8xx */
-#if 0
-	/*
-	 * this allows for > 1 interrupt at a time so we can
-	 * clear out any 'double' interrupts on prep and
-	 * finish up the lost interrupts.
-	 * It doesn't currently work for irqs > 31 so I'm leaving
-	 * it commented out for now.
-	 * -- Cort
-	 */
-	for ( i = 0 ; i < sizeof(bits)*8 ; i++ )
-		if ( bits & (1UL<<i) )
-			dispatch_handler( regs, i );
-#else	
-	dispatch_handler( regs, irq );
-#endif	
-	
-#ifndef CONFIG_8xx
-out:
-	if (_machine == _MACH_chrp && !openpic_eoi_done)
-		openpic_eoi(0);
-#endif /* CONFIG_8xx */
-	hardirq_exit(cpu);
-#ifdef CONFIG_APUS
-out2:
-#endif
+        hardirq_enter(cpu);
+        ppc_md.do_IRQ(regs, cpu, isfake);
+        hardirq_exit(cpu);
 }
 
 unsigned long probe_irq_on (void)
@@ -605,461 +288,16 @@
 	return 0;
 }
 
-static void i8259_mask_and_ack_irq(unsigned int irq_nr)
-{
-	if ( irq_nr >= i8259_pic.irq_offset )	
-		irq_nr -= i8259_pic.irq_offset;
-	if (irq_nr > 7) {
-		cached_A1 |= 1 << (irq_nr-8);
-		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 {
-		cached_21 |= 1 << irq_nr;
-		inb(0x21);	/* DUMMY */
-		outb(cached_21,0x21);
-		/*outb(0x20,0x20);*/
-		outb(0x60|irq_nr,0x20); /* specific eoi */
-	}
-}
-
-static void i8259_set_irq_mask(int irq_nr)
-{
-	outb(cached_A1,0xA1);
-	outb(cached_21,0x21);
-}
-
-static void i8259_mask_irq(unsigned int irq_nr)
-{
-	if ( irq_nr >= i8259_pic.irq_offset )	
-		irq_nr -= i8259_pic.irq_offset;
-	if ( irq_nr < 8 )
-		cached_21 |= 1 << irq_nr;
-	else
-		cached_A1 |= 1 << (irq_nr-8);
-	i8259_set_irq_mask(irq_nr);
-}
-
-static void i8259_unmask_irq(unsigned int irq_nr)
-{
-  
-	if ( irq_nr >= i8259_pic.irq_offset )	
-		irq_nr -= i8259_pic.irq_offset;
-	if ( irq_nr < 8 )
-		cached_21 &= ~(1 << irq_nr);
-	else
-		cached_A1 &= ~(1 << (irq_nr-8));
-	i8259_set_irq_mask(irq_nr);
-}
-
-#ifndef CONFIG_8xx
-static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-	int irq, bits;
-	
-	for (irq = max_irqs - 1; irq > max_real_irqs; irq -= 32) {
-		int i = irq >> 5;
-		bits = ld_le32(&pmac_irq_hw[i]->flag)
-			| lost_interrupts[i];
-		if (bits == 0)
-			continue;
-		irq -= cntlzw(bits);
-		break;
-	}
-	/* The previous version of this code allowed for this case, we
-	 * don't.  Put this here to check for it.
-	 * -- Cort
-	 */
-	if ( irq_desc[irq].ctl != &gatwick_pic )
-		printk("gatwick irq not from gatwick pic\n");
-	else
-		dispatch_handler( regs, irq );
-}
-
-void pmac_mask_and_ack_irq(unsigned int irq_nr)
-{
-        unsigned long bit = 1UL << (irq_nr & 0x1f);
-        int i = irq_nr >> 5;
-
-        if ((unsigned)irq_nr >= max_irqs)
-                return;
-
-        clear_bit(irq_nr, cached_irq_mask);
-        if (test_and_clear_bit(irq_nr, lost_interrupts))
-                atomic_dec(&n_lost_interrupts);
-        out_le32(&pmac_irq_hw[i]->ack, bit);
-        out_le32(&pmac_irq_hw[i]->enable, cached_irq_mask[i]);
-        out_le32(&pmac_irq_hw[i]->ack, bit);
-        do {
-                /* make sure ack gets to controller before we enable interrupts */
-		mb();
-        } while(in_le32(&pmac_irq_hw[i]->flag) & bit);
-
-}
-
-void __openfirmware chrp_mask_and_ack_irq(unsigned int irq_nr)
-{
-	if (is_8259_irq(irq_nr))
-	    i8259_mask_and_ack_irq(irq_nr);
-}
-
-static void pmac_set_irq_mask(int irq_nr)
-{
-	unsigned long bit = 1UL << (irq_nr & 0x1f);
-	int i = irq_nr >> 5;
-
-	if ((unsigned)irq_nr >= max_irqs)
-		return;
-
-	/* enable unmasked interrupts */
-	out_le32(&pmac_irq_hw[i]->enable, cached_irq_mask[i]);
-	
-	do {
-		/* make sure mask gets to controller before we
-		   return to user */
-		mb();
-	} while((in_le32(&pmac_irq_hw[i]->enable) & bit)
-		!= (cached_irq_mask[i] & bit));
-
-	/*
-	 * 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 ((bit & cached_irq_mask[i])
-	    && (ld_le32(&pmac_irq_hw[i]->level) & bit)
-	    && !(ld_le32(&pmac_irq_hw[i]->flag) & bit)) {
-		if (!test_and_set_bit(irq_nr, lost_interrupts))
-			atomic_inc(&n_lost_interrupts);
-	}
-}
-
-static void pmac_mask_irq(unsigned int irq_nr)
-{
-	clear_bit(irq_nr, cached_irq_mask);
-	pmac_set_irq_mask(irq_nr);
-	mb();
-}
-
-static void pmac_unmask_irq(unsigned int irq_nr)
-{
-	set_bit(irq_nr, cached_irq_mask);
-	pmac_set_irq_mask(irq_nr);
-}
-
-static void __openfirmware chrp_mask_irq(unsigned int irq_nr)
-{
-	if (is_8259_irq(irq_nr))
-		i8259_mask_irq(irq_nr);
-	else
-		openpic_disable_irq(irq_to_openpic(irq_nr));
-}
-
-static void __openfirmware chrp_unmask_irq(unsigned int irq_nr)
-{
-	if (is_8259_irq(irq_nr))
-		i8259_unmask_irq(irq_nr);
-	else
-		openpic_enable_irq(irq_to_openpic(irq_nr));
-}
-
-/* This routine will fix some missing interrupt values in the device tree
- * on the gatwick mac-io controller used by some PowerBooks
- */
-static void __init pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
-{
-	struct device_node *node;
-	int count;
-	
-	memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool));
-	node = gw->child;
-	count = 0;
-	while(node)
-	{
-		/* Fix SCC */
-		if (strcasecmp(node->name, "escc") == 0)
-			if (node->child) {
-				if (node->child->n_intrs < 3) {
-					node->child->intrs = &gatwick_int_pool[count];
-					count += 3;
-				}
-				node->child->n_intrs = 3;				
-				node->child->intrs[0].line = 15+irq_base;
-				node->child->intrs[1].line =  4+irq_base;
-				node->child->intrs[2].line =  5+irq_base;
-				printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n",
-					node->child->intrs[0].line,
-					node->child->intrs[1].line,
-					node->child->intrs[2].line);
-			}
-		/* Fix media-bay & left SWIM */
-		if (strcasecmp(node->name, "media-bay") == 0) {
-			struct device_node* ya_node;
-
-			if (node->n_intrs == 0)
-				node->intrs = &gatwick_int_pool[count++];
-			node->n_intrs = 1;
-			node->intrs[0].line = 29+irq_base;
-			printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
-					node->intrs[0].line);
-			
-			ya_node = node->child;
-			while(ya_node)
-			{
-				if (strcasecmp(ya_node->name, "floppy") == 0) {
-					if (ya_node->n_intrs < 2) {
-						ya_node->intrs = &gatwick_int_pool[count];
-						count += 2;
-					}
-					ya_node->n_intrs = 2;
-					ya_node->intrs[0].line = 19+irq_base;
-					ya_node->intrs[1].line =  1+irq_base;
-					printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n",
-						ya_node->intrs[0].line, ya_node->intrs[1].line);
-				} 
-				if (strcasecmp(ya_node->name, "ata4") == 0) {
-					if (ya_node->n_intrs < 2) {
-						ya_node->intrs = &gatwick_int_pool[count];
-						count += 2;
-					}
-					ya_node->n_intrs = 2;
-					ya_node->intrs[0].line = 14+irq_base;
-					ya_node->intrs[1].line =  3+irq_base;
-					printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n",
-						ya_node->intrs[0].line, ya_node->intrs[1].line);
-				} 
-				ya_node = ya_node->sibling;
-			}
-		}
-		node = node->sibling;
-	}
-	if (count > 10) {
-		printk("WARNING !! Gatwick interrupt pool overflow\n");
-		printk("  GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE);
-		printk("              requested = %d\n", count);
-	}
-}
-
-#ifdef __SMP__
-static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-	smp_message_recv();
-}
-#endif /* __SMP__ */
-
-
-#else /* CONFIG_8xx */
-
-static void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-	int bits, irq;
-
-	/* A bug in the QSpan chip causes it to give us 0xff always
-	 * when doing a character read.  So read 32 bits and shift.
-	 * This doesn't seem to return useful values anyway, but
-	 * read it to make sure things are acked.
-	 * -- Cort
-	 */
-	irq = (inl(0x508) >> 24)&0xff;
-	if ( irq != 0xff ) printk("iack %d\n", irq);
-	
-	outb(0x0C, 0x20);
-	irq = inb(0x20) & 7;
-	if (irq == 2)
-	{
-		outb(0x0C, 0xA0);
-		irq = inb(0xA0);
-		irq = (irq&7) + 8;
-	}
-	bits = 1UL << irq;
-	irq += i8259_pic.irq_offset;
-	dispatch_handler( regs, irq );
-}
-
-static void mbx_mask_and_ack(unsigned int irq_nr)
-{
-	/* this shouldn't be masked, we mask the 8259 if we need to -- Cort */
-	if ( irq_nr != ISA_BRIDGE_INT )
-		mbx_mask_irq(irq_nr);
-	if ( irq_nr >= ppc8xx_pic.irq_offset )
-		irq_nr -= ppc8xx_pic.irq_offset;
-	/* clear the pending bits */
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-irq_nr);
-}
-
-static void mbx_mask_irq(unsigned int irq_nr)
-{
-	if ( irq_nr == ISA_BRIDGE_INT ) return;
-	if ( irq_nr >= ppc8xx_pic.irq_offset )
-		irq_nr -= ppc8xx_pic.irq_offset;
-	cached_irq_mask[0] &= ~(1 << (31-irq_nr));
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =	cached_irq_mask[0];
-}
-
-static void mbx_unmask_irq(unsigned int irq_nr)
-{
-	if ( irq_nr >= ppc8xx_pic.irq_offset )
-		irq_nr -= ppc8xx_pic.irq_offset;
-	cached_irq_mask[0] |= (1 << (31-irq_nr));
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =	cached_irq_mask[0];
-}
-#endif /* CONFIG_8xx */
-
-static void __init i8259_init(void)
-{
-	/* init master interrupt controller */
-	outb(0x11, 0x20); /* Start init sequence */
-	outb(0x00, 0x21); /* Vector base */
-	outb(0x04, 0x21); /* edge tiggered, 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(0x08, 0xA1); /* Vector base */
-	outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
-	outb(0x01, 0xA1); /* Select 8086 mode */
-	outb(0xFF, 0xA1); /* Mask all */
-	outb(cached_A1, 0xA1);
-	outb(cached_21, 0x21);
-	request_irq( i8259_pic.irq_offset + 2, no_action, SA_INTERRUPT,
-		     "8259 secondary cascade", NULL );
-	enable_irq(i8259_pic.irq_offset + 2);  /* Enable cascade interrupt */
-}
-
 void __init init_IRQ(void)
 {
-	extern void xmon_irq(int, void *, struct pt_regs *);
-	int i;
 	static int once = 0;
-#ifndef CONFIG_8xx
-	struct device_node *irqctrler;
-	unsigned long addr;
-	struct device_node *np;
-	int second_irq = -999;
-#endif
+
 	if ( once )
 		return;
 	else
 		once++;
 	
-#ifndef CONFIG_8xx
-	switch (_machine)
-	{
-	case _MACH_Pmac:
-		/* G3 powermacs have 64 interrupts, G3 Series PowerBook have 128, 
-		   others have 32 */
-		max_irqs = max_real_irqs = 32;
-		irqctrler = find_devices("mac-io");
-		if (irqctrler)
-		{
-			max_real_irqs = 64;
-			if (irqctrler->next)
-				max_irqs = 128;
-			else
-				max_irqs = 64;
-		}
-		for ( i = 0; i < max_real_irqs ; i++ )
-			irq_desc[i].ctl = &pmac_pic;
-
-		/* get addresses of first controller */
-		if (irqctrler) {
-			if  (irqctrler->n_addrs > 0) {
-				addr = (unsigned long) 
-					ioremap(irqctrler->addrs[0].address, 0x40);
-				for (i = 0; i < 2; ++i)
-					pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-						(addr + (2 - i) * 0x10);
-			}
-			
-			/* get addresses of second controller */
-			irqctrler = (irqctrler->next) ? irqctrler->next : NULL;
-			if (irqctrler && irqctrler->n_addrs > 0) {
-				addr = (unsigned long) 
-					ioremap(irqctrler->addrs[0].address, 0x40);
-				for (i = 2; i < 4; ++i)
-					pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
-						(addr + (4 - i) * 0x10);
-			}
-		}
-
-		/* disable all interrupts in all controllers */
-		for (i = 0; i * 32 < max_irqs; ++i)
-			out_le32(&pmac_irq_hw[i]->enable, 0);
-		
-		/* get interrupt line of secondary interrupt controller */
-		if (irqctrler) {
-			second_irq = irqctrler->intrs[0].line;
-			printk(KERN_INFO "irq: secondary controller on irq %d\n",
-				(int)second_irq);
-			if (device_is_compatible(irqctrler, "gatwick"))
-				pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
-			for ( i = max_real_irqs ; i < max_irqs ; i++ )
-				irq_desc[i].ctl = &gatwick_pic;
-			request_irq( second_irq, gatwick_action, SA_INTERRUPT,
-				     "gatwick cascade", 0 );
-		}
-		printk("System has %d possible interrupts\n", max_irqs);
-		if (max_irqs != max_real_irqs)
-			printk(KERN_DEBUG "%d interrupts on main controller\n",
-				max_real_irqs);
-
-#ifdef CONFIG_XMON
-		request_irq(20, xmon_irq, 0, "NMI - XMON", 0);
-#endif	/* CONFIG_XMON */
-		break;
-	case _MACH_chrp:
-		if ( !(np = find_devices("pci") ) )
-			printk("Cannot find pci to get ack address\n");
-		else
-		{
-			chrp_int_ack_special = (volatile unsigned char *)
-				(*(unsigned long *)get_property(np,
-					"8259-interrupt-acknowledge", NULL));
-		}
-		for ( i = 16 ; i < 36 ; i++ )
-			irq_desc[i].ctl = &open_pic;
-		/* openpic knows that it's at irq 16 offset
-		 * so we don't need to set it in the pic structure
-		 * -- Cort
-		 */
-		openpic_init(1);
-		for ( i = 0 ; i < 16  ; i++ )
-			irq_desc[i].ctl = &i8259_pic;
-		i8259_init();
-#ifdef CONFIG_XMON
-		request_irq(openpic_to_irq(HYDRA_INT_ADB_NMI),
-			    xmon_irq, 0, "NMI", 0);
-#endif	/* CONFIG_XMON */
-#ifdef __SMP__
-		request_irq(openpic_to_irq(OPENPIC_VEC_SPURIOUS),
-			    openpic_ipi_action, 0, "IPI0", 0);
-#endif	/* __SMP__ */
-		break;
-	case _MACH_prep:
-		for ( i = 0 ; i < 16  ; i++ )
-			irq_desc[i].ctl = &i8259_pic;
-		i8259_init();
-		break;
-#ifdef CONFIG_APUS		
-	case _MACH_apus:
-		apus_init_IRQ();
-		break;
-#endif	
-	}
-#else /* CONFIG_8xx */
-	ppc8xx_pic.irq_offset = 16;
-	for ( i = 16 ; i < 32 ; i++ )
-		irq_desc[i].ctl = &ppc8xx_pic;
-	unmask_irq(CPM_INTERRUPT);
-
-	for ( i = 0 ; i < 16 ; i++ )
-		irq_desc[i].ctl = &i8259_pic;
-	i8259_init();
-	request_irq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL);
-	enable_irq(ISA_BRIDGE_INT);
-#endif  /* CONFIG_8xx */
+	ppc_md.init_IRQ();
 }
 
 #ifdef __SMP__
@@ -1078,9 +316,13 @@
 
 	printk("\n%s, CPU %d:\n", str, cpu);
 	printk("irq:  %d [%d %d]\n",
-		atomic_read(&global_irq_count), local_irq_count[0], local_irq_count[1]);
+	       atomic_read(&global_irq_count),
+	       ppc_local_irq_count[0],
+	       ppc_local_irq_count[1]);
 	printk("bh:   %d [%d %d]\n",
-		atomic_read(&global_bh_count), local_bh_count[0], local_bh_count[1]);
+	       atomic_read(&global_bh_count),
+	       ppc_local_bh_count[0],
+	       ppc_local_bh_count[1]);
 	stack = (unsigned long *) &str;
 	for (i = 40; i ; i--) {
 		unsigned long x = *++stack;
@@ -1115,7 +357,8 @@
 		 * already executing in one..
 		 */
 		if (!atomic_read(&global_irq_count)) {
-			if (local_bh_count[cpu] || !atomic_read(&global_bh_count))
+			if (ppc_local_bh_count[cpu]
+			    || !atomic_read(&global_bh_count))
 				break;
 		}
 
@@ -1136,7 +379,8 @@
 				continue;
 			if (global_irq_lock)
 				continue;
-			if (!local_bh_count[cpu] && atomic_read(&global_bh_count))
+			if (!ppc_local_bh_count[cpu]
+			    && atomic_read(&global_bh_count))
 				continue;
 			if (!test_and_set_bit(0,&global_irq_lock))
 				break;
@@ -1226,7 +470,7 @@
 	if (flags & (1 << 15)) {
 		int cpu = smp_processor_id();
 		__cli();
-		if (!local_irq_count[cpu])
+		if (!ppc_local_irq_count[cpu])
 			get_irqlock(cpu);
 	}
 }
@@ -1235,7 +479,7 @@
 {
 	int cpu = smp_processor_id();
 
-	if (!local_irq_count[cpu])
+	if (!ppc_local_irq_count[cpu])
 		release_irqlock(cpu);
 	__sti();
 }
@@ -1259,7 +503,7 @@
 	retval = 2 + local_enabled;
 
 	/* check for global flags if we're not in an interrupt */
-	if (!local_irq_count[smp_processor_id()]) {
+	if (!ppc_local_irq_count[smp_processor_id()]) {
 		if (local_enabled)
 			retval = 1;
 		if (global_irq_holder == (unsigned char) smp_processor_id())
@@ -1268,6 +512,31 @@
 	return retval;
 }
 
+int
+tb(long vals[],
+   int  max_size)
+{
+   register unsigned long *orig_sp __asm__ ("r1");
+   register unsigned long lr __asm__ ("r3");
+   unsigned long *sp;
+   int i;
+
+   asm volatile ("mflr 3");
+   vals[0] = lr;
+   sp = (unsigned long *) *orig_sp;
+   sp = (unsigned long *) *sp;
+   for (i=1; i<max_size; i++) {
+      if (sp == 0) {
+         break;
+      }
+
+      vals[i] = *(sp+1);
+      sp = (unsigned long *) *sp;
+   }
+
+   return i;
+}
+
 void __global_restore_flags(unsigned long flags)
 {
 	switch (flags) {
@@ -1284,8 +553,20 @@
 		__sti();
 		break;
 	default:
+	{
+		unsigned long trace[5];
+                int           count;
+                int           i;
+
 		printk("global_restore_flags: %08lx (%08lx)\n",
 			flags, (&flags)[-1]);
+                count = tb(trace, 5);
+                printk("tb:");
+                for(i=0; i<count; i++) {
+			printk(" %8.8lx", trace[i]);
+		}
+		printk("\n");
+	}
 	}
 }
 #endif /* __SMP__ */
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/local_irq.h linux/arch/ppc/kernel/local_irq.h
--- v2.2.7/linux/arch/ppc/kernel/local_irq.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/local_irq.h	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,45 @@
+
+#ifndef _PPC_KERNEL_LOCAL_IRQ_H
+#define _PPC_KERNEL_LOCAL_IRQ_H
+
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+
+void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq);
+
+/* Structure describing interrupts */
+struct hw_interrupt_type {
+	const char * typename;
+	void (*startup)(unsigned int irq);
+	void (*shutdown)(unsigned int irq);
+	void (*handle)(unsigned int irq, struct pt_regs * regs);
+	void (*enable)(unsigned int irq);
+	void (*disable)(unsigned int irq);
+	void (*mask_and_ack)(unsigned int irq);
+	int irq_offset;
+};
+
+#define mask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->disable) irq_desc[irq].ctl->disable(irq);})
+#define unmask_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->enable) irq_desc[irq].ctl->enable(irq);})
+#define mask_and_ack_irq(irq) ({if (irq_desc[irq].ctl && irq_desc[irq].ctl->mask_and_ack) irq_desc[irq].ctl->mask_and_ack(irq);})
+
+struct irqdesc {
+	struct irqaction *action;
+	struct hw_interrupt_type *ctl;
+};
+
+extern struct irqdesc irq_desc[NR_IRQS];
+
+
+#define NR_MASK_WORDS	((NR_IRQS + 31) / 32)
+
+extern int ppc_spurious_interrupts;
+extern int ppc_second_irq;
+extern struct irqaction *ppc_irq_action[NR_IRQS];
+extern unsigned int ppc_local_bh_count[NR_CPUS];
+extern unsigned int ppc_local_irq_count[NR_CPUS];
+extern unsigned int ppc_cached_irq_mask[NR_MASK_WORDS];
+extern unsigned int ppc_lost_interrupts[NR_MASK_WORDS];
+extern atomic_t ppc_n_lost_interrupts;
+
+#endif /* _PPC_KERNEL_LOCAL_IRQ_H */
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/mbx_pci.c linux/arch/ppc/kernel/mbx_pci.c
--- v2.2.7/linux/arch/ppc/kernel/mbx_pci.c	Thu Apr 23 20:21:29 1998
+++ linux/arch/ppc/kernel/mbx_pci.c	Thu Apr 29 12:39:01 1999
@@ -252,3 +252,20 @@
     }
     return PCIBIOS_DEVICE_NOT_FOUND;
 }
+
+__initfunc(
+void
+mbx_pcibios_fixup(void))
+{
+   /* Nothing to do here? */
+}
+
+__initfunc(
+void
+mbx_setup_pci_ptrs(void))
+{
+	set_config_access_method(mbx);
+
+	ppc_md.pcibios_fixup = mbx_pcibios_fixup;
+}
+
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/mbx_setup.c linux/arch/ppc/kernel/mbx_setup.c
--- v2.2.7/linux/arch/ppc/kernel/mbx_setup.c	Fri Jan  8 22:36:02 1999
+++ linux/arch/ppc/kernel/mbx_setup.c	Thu Apr 29 12:39:01 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: mbx_setup.c,v 1.5 1998/12/29 18:55:07 cort Exp $
+ * $Id: mbx_setup.c,v 1.9 1999/04/28 11:54:09 davem Exp $
  *
  *  linux/arch/ppc/kernel/setup.c
  *
@@ -39,6 +39,22 @@
 #include <asm/pgtable.h>
 #include <asm/ide.h>
 #include <asm/mbx.h>
+#include <asm/machdep.h>
+
+#include "time.h"
+#include "local_irq.h"
+
+static int mbx_set_rtc_time(unsigned long time);
+unsigned long mbx_get_rtc_time(void);
+void mbx_calibrate_decr(void);
+
+extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void mackbd_init_hw(void);
 
 extern unsigned long loops_per_sec;
 
@@ -55,35 +71,10 @@
 extern unsigned long find_available_memory(void);
 extern void m8xx_cpm_reset(uint);
 
-/* this really does make things cleaner -- Cort */
-void __init powermac_init(void)
-{
-}
-
 void __init adbdev_init(void)
 {
 }
 
-void __init mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
-{
-	ide_ioreg_t port = base;
-	int i = 8;
-
-	while (i--)
-		*p++ = port++;
-	*p++ = base + 0x206;
-	if (irq != NULL)
-		*irq = 0;
-#ifdef ATA_FLASH
-	base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200);
-	for (i = 0; i < 8; ++i)
-		*p++ = base++;
-	*p = ++base;		/* Does not matter */
-	if (irq)
-		*irq = 13;
-#endif
-}
-
 __initfunc(void
 mbx_setup_arch(unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
@@ -144,4 +135,338 @@
 	xmon(0);
 #endif
 	machine_restart(NULL);
+}
+
+/* The decrementer counts at the system (internal) clock frequency divided by
+ * sixteen, or external oscillator divided by four.  Currently, we only
+ * support the MBX, which is system clock divided by sixteen.
+ */
+__initfunc(void mbx_calibrate_decr(void))
+{
+	bd_t	*binfo = (bd_t *)&res;
+	int freq, fp, divisor;
+
+	if ((((immap_t *)MBX_IMAP_ADDR)->im_clkrst.car_sccr & 0x02000000) == 0)
+		printk("WARNING: Wrong decrementer source clock.\n");
+
+	/* The manual says the frequency is in Hz, but it is really
+	 * as MHz.  The value 'fp' is the number of decrementer ticks
+	 * per second.
+	 */
+	fp = (binfo->bi_intfreq * 1000000) / 16;
+	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;
+}
+
+/* A place holder for time base interrupts, if they are ever enabled.
+*/
+void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
+{
+	printk("timebase_interrupt()\n");
+}
+
+/* The RTC on the MPC8xx is an internal register.
+ * We want to protect this during power down, so we need to unlock,
+ * modify, and re-lock.
+ */
+static int
+mbx_set_rtc_time(unsigned long time)
+{
+	((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
+	((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc = time;
+	((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
+	return(0);
+}
+
+initfunc(unsigned long
+mbx_get_rtc_time(void)
+{
+	/* First, unlock all of the registers we are going to modify.
+	 * To protect them from corruption during power down, registers
+	 * that are maintained by keep alive power are "locked".  To
+	 * modify these registers we have to write the key value to
+	 * the key location associated with the register.
+	 */
+	((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY;
+	((immap_t *)MBX_IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY;
+
+
+	/* Disable the RTC one second and alarm interrupts.
+	*/
+	((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtcsc &=
+						~(RTCSC_SIE | RTCSC_ALE);
+
+	/* Enabling the decrementer also enables the timebase interrupts
+	 * (or from the other point of view, to get decrementer interrupts
+	 * we have to enable the timebase).  The decrementer interrupt
+	 * is wired into the vector table, nothing to do here for that.
+	 */
+	((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_tbscr =
+				((mk_int_int_mask(DEC_INTERRUPT) << 8) |
+					 (TBSCR_TBF | TBSCR_TBE));
+	if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
+		panic("Could not allocate timer IRQ!");
+
+	/* Get time from the RTC.
+	*/
+	return ((immap_t *)MBX_IMAP_ADDR)->im_sit.sit_rtc;
+}
+
+void
+mbx_restart(char *cmd)
+{
+	extern void MBX_gorom(void);
+
+	MBX_gorom();
+}
+
+void
+mbx_power_off(void)
+{
+   mbx_restart(NULL);
+}
+
+void
+mbx_halt(void)
+{
+   mbx_restart(NULL)
+}
+
+
+int mbx_setup_residual(char *buffer)
+{
+        int     len = 0;
+	bd_t	*bp;
+	extern	RESIDUAL *res;
+			
+	bp = (bd_t *)res;
+			
+	len += sprintf(len+buffer,"clock\t\t: %dMHz\n"
+		       "bus clock\t: %dMHz\n",
+		       bp->bi_intfreq /*/ 1000000*/,
+		       bp->bi_busfreq /*/ 1000000*/);
+
+	return len;
+}
+
+void
+mbx_do_IRQ(struct pt_regs *regs,
+	   int            cpu,
+           int            isfake)
+{
+	int irq;
+        unsigned long bits = 0;
+
+        /* For MPC8xx, read the SIVEC register and shift the bits down
+         * to get the irq number.         */
+        bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
+        irq = bits >> 26;
+        irq += ppc8xx_pic.irq_offset;
+        bits = 1UL << irq;
+
+	if (irq < 0) {
+		printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+		       irq, regs->nip);
+		spurious_interrupts++;
+	}
+	else {
+                ppc_irq_dispatch_handler( regs, irq );
+	}
+
+}
+
+static void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+	int bits, irq;
+
+	/* A bug in the QSpan chip causes it to give us 0xff always
+	 * when doing a character read.  So read 32 bits and shift.
+	 * This doesn't seem to return useful values anyway, but
+	 * read it to make sure things are acked.
+	 * -- Cort
+	 */
+	irq = (inl(0x508) >> 24)&0xff;
+	if ( irq != 0xff ) printk("iack %d\n", irq);
+	
+	outb(0x0C, 0x20);
+	irq = inb(0x20) & 7;
+	if (irq == 2)
+	{
+		outb(0x0C, 0xA0);
+		irq = inb(0xA0);
+		irq = (irq&7) + 8;
+	}
+	bits = 1UL << irq;
+	irq += i8259_pic.irq_offset;
+	ppc_irq_dispatch_handler( regs, irq );
+}
+
+
+/* On MBX8xx, the interrupt control (SIEL) was set by EPPC-bug.  External
+ * interrupts can be either edge or level triggered, but there is no
+ * reason for us to change the EPPC-bug values (it would not work if we did).
+ */
+__initfunc(void
+mbx_init_IRQ(void))
+{
+	int i;
+
+        ppc8xx_pic.irq_offset = 16;
+        for ( i = 16 ; i < 32 ; i++ )
+                irq_desc[i].ctl = &ppc8xx_pic;
+        unmask_irq(CPM_INTERRUPT);
+
+        for ( i = 0 ; i < 16 ; i++ )
+                irq_desc[i].ctl = &i8259_pic;
+        i8259_init();
+        request_irq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL);
+        enable_irq(ISA_BRIDGE_INT);
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+void
+mbx_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+	ide_insw(port+_IO_BASE), buf, ns);
+}
+
+void
+mbx_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+	ide_outsw(port+_IO_BASE, buf, ns);
+}
+
+int
+mbx_ide_default_irq(ide_ioreg_t base)
+{
+        return 14;
+}
+
+ide_ioreg_t
+mbx_ide_default_io_base(int index)
+{
+        return index;
+}
+
+int
+mbx_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+        return 0
+}
+
+void
+mbx_ide_request_region(ide_ioreg_t from,
+			unsigned int extent,
+			const char *name)
+{
+}
+
+void
+mbx_ide_release_region(ide_ioreg_t from,
+			unsigned int extent)
+{
+}
+
+void
+mbx_ide_fix_driveid(struct hd_driveid *id)
+{
+        ppc_generic_ide_fix_driveid(id);
+}
+
+void __init mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq)
+{
+	ide_ioreg_t port = base;
+	int i = 8;
+
+	while (i--)
+		*p++ = port++;
+	*p++ = base + 0x206;
+	if (irq != NULL)
+		*irq = 0;
+#ifdef ATA_FLASH
+	base = (unsigned long) ioremap(PCMCIA_MEM_ADDR, 0x200);
+	for (i = 0; i < 8; ++i)
+		*p++ = base++;
+	*p = ++base;		/* Does not matter */
+	if (irq)
+		*irq = 13;
+#endif
+}
+#endif
+
+__initfunc(void
+mbx_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	 unsigned long r6, unsigned long r7))
+{
+
+	if ( r3 )
+		memcpy( (void *)&res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
+	
+#ifdef CONFIG_PCI
+	mbx_setup_pci_ptrs();
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* take care of initrd if we have one */
+	if ( r4 )
+	{
+		initrd_start = r4 + KERNELBASE;
+		initrd_end = r5 + KERNELBASE;
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+	/* take care of cmd line */
+	if ( r6 )
+	{
+		
+		*(char *)(r7+KERNELBASE) = 0;
+		strcpy(cmd_line, (char *)(r6+KERNELBASE));
+	}
+
+	ppc_md.setup_arch     = mbx_setup_arch;
+	ppc_md.setup_residual = mbx_setup_residual;
+	ppc_md.get_cpuinfo    = NULL;
+	ppc_md.irq_cannonicalize = NULL;
+	ppc_md.init_IRQ       = mbx_init_IRQ;
+	ppc_md.do_IRQ         = mbx_do_IRQ;
+	ppc_md.init           = NULL;
+
+	ppc_md.restart        = mbx_restart;
+	ppc_md.power_off      = mbx_power_off;
+	ppc_md.halt           = mbx_halt;
+
+	ppc_md.time_init      = NULL;
+	ppc_md.set_rtc_time   = mbx_set_rtc_time;
+	ppc_md.get_rtc_time   = mbx_get_rtc_time;
+	ppc_md.calibrate_decr = mbx_calibrate_decr;
+
+	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
+	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
+	ppc_md.kbd_translate     = pckbd_translate;
+	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+	ppc_md.kbd_leds          = pckbd_leds;
+	ppc_md.kbd_init_hw       = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+        ppc_ide_md.insw = mbx_ide_insw;
+        ppc_ide_md.outsw = mbx_ide_outsw;
+        ppc_ide_md.default_irq = mbx_ide_default_irq;
+        ppc_ide_md.default_io_base = mbx_ide_default_io_base;
+        ppc_ide_md.check_region = mbx_ide_check_region;
+        ppc_ide_md.request_region = mbx_ide_request_region;
+        ppc_ide_md.release_region = mbx_ide_release_region;
+        ppc_ide_md.fix_driveid = mbx_ide_fix_driveid;
+        ppc_ide_md.ide_init_hwif = mbx_ide_init_hwif_ports;
+
+        ppc_ide_md.io_base = _IO_BASE;
+#endif		
 }
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- v2.2.7/linux/arch/ppc/kernel/misc.S	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/misc.S	Thu Apr 29 12:39:01 1999
@@ -36,6 +36,7 @@
  * Returns (address we're running at) - (address we were linked at)
  * for use before the text and data are mapped to KERNELBASE.
  */
+
 _GLOBAL(reloc_offset)
 	mflr	r0
 	bl	1f
@@ -72,8 +73,8 @@
 	beqlr			/* nothing to do if state == 0 */
 _GLOBAL(__sti)
 _GLOBAL(_hard_sti)
-	lis	r4,n_lost_interrupts@ha
-	lwz	r4,n_lost_interrupts@l(r4)
+	lis	r4,ppc_n_lost_interrupts@ha
+	lwz	r4,ppc_n_lost_interrupts@l(r4)
 	mfmsr	r3		/* Get current state */
 	ori	r3,r3,MSR_EE	/* Turn on 'EE' bit */
 	cmpi	0,r4,0		/* lost interrupts to process first? */
@@ -93,8 +94,8 @@
 	stw	r0,20(r1)
 	stw	r3,8(r1)
 1:	bl	fake_interrupt
-	lis	r4,n_lost_interrupts@ha
-	lwz	r4,n_lost_interrupts@l(r4)
+	lis	r4,ppc_n_lost_interrupts@ha
+	lwz	r4,ppc_n_lost_interrupts@l(r4)
 	cmpi	0,r4,0
 	bne-	1b
 	lwz	r3,8(r1)
@@ -105,6 +106,20 @@
 	addi	r1,r1,16
 	blr
 
+
+/*
+ * complement mask on the msr then "or" some values on.
+ *     _nmask_and_or_msr(nmask, value_to_or)
+ */
+	_GLOBAL(_nmask_and_or_msr)
+	mfmsr	r0		/* Get current msr */
+	andc	r0,r0,r3	/* And off the bits set in r3 (first parm) */
+	or	r0,r0,r4		/* Or on the bits in r4 (second parm) */
+	sync			/* Some chip revs have problems here... */
+	mtmsr	r0		/* Update machine state */
+	blr			/* Done */
+
+
 /*
  * Flush MMU TLB
  */
@@ -613,16 +628,6 @@
 	stfd	0,-4(r5)
 	blr
 
-        .globl  __clear_msr_me
-__clear_msr_me:
-        mfmsr   r0                      /* Get current interrupt state */
-        lis     r3,0
-        ori     r3,r3,MSR_ME
-        andc    r0,r0,r3                /* Clears bit in (r4) */
-        sync                            /* Some chip revs have problems here */
-        mtmsr   r0                      /* Update machine state */
-        blr
-
 _GLOBAL(cvt_df)
 cvt_df:
 	lfd	0,-4(r5)	/* load up fpscr value */
@@ -633,6 +638,16 @@
 	stfd	0,-4(r5)
 	blr
 
+        .globl  __clear_msr_me
+__clear_msr_me:
+        mfmsr   r0                      /* Get current interrupt state */
+        lis     r3,0
+        ori     r3,r3,MSR_ME
+        andc    r0,r0,r3                /* Clears bit in (r4) */
+        sync                            /* Some chip revs have problems here */
+        mtmsr   r0                      /* Update machine state */
+        blr
+
 /*
  * Fetch the current SR register
  *   get_SR(int index)
@@ -651,6 +666,8 @@
 	sc
 	cmpi	0,r3,0		/* parent or child? */
 	bnelr			/* return if parent */
+	li	r0,0		/* clear out p->tss.regs */
+	stw	r0,TSS+PT_REGS(r2)	/* since we don't have user ctx */
 	mtlr	r4              /* fn addr in lr */
 	mr	r3,r5	        /* load arg and call fn */
 	blrl
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/mk_defs.c linux/arch/ppc/kernel/mk_defs.c
--- v2.2.7/linux/arch/ppc/kernel/mk_defs.c	Wed Sep  9 14:51:06 1998
+++ linux/arch/ppc/kernel/mk_defs.c	Thu Apr 29 12:39:01 1999
@@ -29,7 +29,7 @@
 int
 main(void)
 {
-	DEFINE(KERNELBASE, KERNELBASE);
+	/*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));
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c
--- v2.2.7/linux/arch/ppc/kernel/open_pic.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/open_pic.c	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,48 @@
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/openpic.h>
+#include <asm/irq.h>
+#include "open_pic.h"
+#include "i8259.h"
+
+#ifdef __SMP__
+void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+	smp_message_recv();
+}
+#endif /* __SMP__ */
+
+void __openfirmware chrp_mask_and_ack_irq(unsigned int irq_nr)
+{
+	if (is_8259_irq(irq_nr))
+	    i8259_pic.mask_and_ack(irq_nr);
+}
+
+static void __openfirmware chrp_mask_irq(unsigned int irq_nr)
+{
+	if (is_8259_irq(irq_nr))
+		i8259_pic.disable(irq_nr);
+	else
+		openpic_disable_irq(irq_to_openpic(irq_nr));
+}
+
+static void __openfirmware chrp_unmask_irq(unsigned int irq_nr)
+{
+	if (is_8259_irq(irq_nr))
+		i8259_pic.enable(irq_nr);
+	else
+		openpic_enable_irq(irq_to_openpic(irq_nr));
+}
+
+struct hw_interrupt_type open_pic = {
+	" OpenPIC  ",
+	NULL,
+	NULL,
+	NULL,
+	chrp_unmask_irq,
+	chrp_mask_irq,
+	chrp_mask_and_ack_irq,
+	0
+};
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/open_pic.h linux/arch/ppc/kernel/open_pic.h
--- v2.2.7/linux/arch/ppc/kernel/open_pic.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/open_pic.h	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,11 @@
+
+#ifndef _PPC_KERNEL_OPEN_PIC_H
+#define _PPC_KERNEL_OPEN_PIC_H
+
+#include "local_irq.h"
+
+extern struct hw_interrupt_type open_pic;
+
+void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
+
+#endif /* _PPC_KERNEL_OPEN_PIC_H */
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/openpic.c linux/arch/ppc/kernel/openpic.c
--- v2.2.7/linux/arch/ppc/kernel/openpic.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/openpic.c	Thu Apr 29 12:39:01 1999
@@ -190,6 +190,9 @@
 	case 2:
 	    version = "1.2";
 	    break;
+	case 3:
+	    version = "1.3";
+	    break;
 	default:
 	    version = "?";
 	    break;
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
--- v2.2.7/linux/arch/ppc/kernel/pci.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/pci.c	Thu Apr 29 12:39:01 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: pci.c,v 1.53 1999/03/12 23:38:02 cort Exp $
+ * $Id: pci.c,v 1.54 1999/03/18 04:16:04 cort Exp $
  * Common pmac/prep/chrp pci routines. -- Cort
  */
 
@@ -21,97 +21,41 @@
 #include <asm/irq.h>
 #include <asm/gg2.h>
 
-unsigned long isa_io_base;
-unsigned long isa_mem_base;
-unsigned long pci_dram_offset;
-unsigned int * pci_config_address;
-unsigned char * pci_config_data;
-
-static void fix_intr(struct device_node *node, struct pci_dev *dev);
-
-/*
- * 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);
-
-#define decl_config_access_method(name) \
-extern int name##_pcibios_read_config_byte(unsigned char bus, \
-	unsigned char dev_fn, unsigned char offset, unsigned char *val); \
-extern int name##_pcibios_read_config_word(unsigned char bus, \
-	unsigned char dev_fn, unsigned char offset, unsigned short *val); \
-extern int name##_pcibios_read_config_dword(unsigned char bus, \
-	unsigned char dev_fn, unsigned char offset, unsigned int *val); \
-extern int name##_pcibios_write_config_byte(unsigned char bus, \
-	unsigned char dev_fn, unsigned char offset, unsigned char val); \
-extern int name##_pcibios_write_config_word(unsigned char bus, \
-	unsigned char dev_fn, unsigned char offset, unsigned short val); \
-extern int name##_pcibios_write_config_dword(unsigned char bus, \
-	unsigned char dev_fn, unsigned char offset, unsigned int val)
-
-#define set_config_access_method(name) \
-	ptr_pcibios_read_config_byte = name##_pcibios_read_config_byte; \
-	ptr_pcibios_read_config_word = name##_pcibios_read_config_word; \
-	ptr_pcibios_read_config_dword = name##_pcibios_read_config_dword; \
-	ptr_pcibios_write_config_byte = name##_pcibios_write_config_byte; \
-	ptr_pcibios_write_config_word = name##_pcibios_write_config_word; \
-	ptr_pcibios_write_config_dword = name##_pcibios_write_config_dword
-
-decl_config_access_method(mech1);
-decl_config_access_method(pmac);
-decl_config_access_method(grackle);
-decl_config_access_method(gg2);
-decl_config_access_method(raven);
-decl_config_access_method(prep);
-decl_config_access_method(mbx);
-decl_config_access_method(python);
+#include "pci.h"
+
+unsigned long isa_io_base     = 0;
+unsigned long isa_mem_base    = 0;
+unsigned long pci_dram_offset = 0;
 
 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);
+	return ppc_md.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);
+	return ppc_md.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);
+	return ppc_md.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);
+	return ppc_md.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);
+	return ppc_md.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);
+	return ppc_md.pcibios_write_config_dword(bus,dev_fn,offset,val);
 }
 
 int pcibios_present(void)
@@ -123,175 +67,10 @@
 {
 }
 
-void __init setup_pci_ptrs(void)
-{
-#ifndef CONFIG_MBX
-	PPC_DEVICE *hostbridge;
-	switch (_machine) {
-	case _MACH_prep:
-                printk("PReP architecture\n");
-                if ( _prep_type == _PREP_Radstone )
-                {
-                        printk("Setting PCI access method to mech1\n");
-                        set_config_access_method(mech1);
-                        break;
-                }
-
-	  	hostbridge=residual_find_device(PROCESSORDEVICE, NULL,
-						BridgeController, PCIBridge,
-						-1, 0);
-		if (hostbridge && 
-		    hostbridge->DeviceId.Interface == PCIBridgeIndirect) {
-			PnP_TAG_PACKET * pkt;	
-			set_config_access_method(raven);
-			pkt=PnP_find_large_vendor_packet(
-			       res->DevicePnPHeap+hostbridge->AllocatedOffset, 
-			       3, 0);
-			if(pkt) { 
-#define p pkt->L4_Pack.L4_Data.L4_PPCPack
-				pci_config_address= (unsigned *)
-				  ld_le32((unsigned *) p.PPCData);
-				pci_config_data= (unsigned char *)
-				  ld_le32((unsigned *) (p.PPCData+8));
-			} else {/* default values */
-				pci_config_address= (unsigned *) 0x80000cf8;
-				pci_config_data= (unsigned char *) 0x80000cfc; 
-			}  
-		} else {
-			set_config_access_method(prep);
-		}
-		break;
-	case _MACH_Pmac:
-		if (find_devices("pci") != 0) {
-			/* looks like a G3 powermac */
-			set_config_access_method(grackle);
-		} else {
-			set_config_access_method(pmac);
-		}
-		break;
-	case _MACH_chrp:
-		if ( !strncmp("MOT",
-			      get_property(find_path_device("/"), "model", NULL),3) )
-		{
-			pci_dram_offset = 0;
-			isa_mem_base = 0xf7000000;
-			isa_io_base = 0xfe000000;
-			set_config_access_method(grackle);
-		}
-		else
-		{
-			if ( !strncmp("F5",
-			      get_property(find_path_device("/"),
-					   "ibm,model-class", NULL),2) )
-		
-			{
-				pci_dram_offset = 0x80000000;
-				isa_mem_base = 0xa0000000;
-				isa_io_base = 0x88000000;
-				set_config_access_method(python);
-			}
-			else
-			{
-				pci_dram_offset = 0;
-				isa_mem_base = 0xf7000000;
-				isa_io_base = 0xf8000000;
-				set_config_access_method(gg2);
-			}
-		}
-		break;
-	default:
-		printk("setup_pci_ptrs(): unknown machine type!\n");
-	}
-#else  /* CONFIG_MBX */
-	set_config_access_method(mbx);
-#endif /* CONFIG_MBX */	
-#undef set_config_access_method
-}
 
 void __init pcibios_fixup(void)
 {
-	extern unsigned long route_pci_interrupts(void);
-	struct pci_dev *dev;
-	extern struct bridge_data **bridges;
-	extern unsigned char *Motherboard_map;
-	extern unsigned char *Motherboard_routes;
-	unsigned char i;
-#ifndef CONFIG_MBX
-	switch (_machine )
-	{
-	case _MACH_prep:
-                if ( _prep_type == _PREP_Radstone )
-                {
-                        printk("Radstone boards require no PCI fixups\n");
-                        break;
-                }
-
-		route_pci_interrupts();
-		for(dev=pci_devices; dev; dev=dev->next)
-		{
-			/*
-			 * Use our old hard-coded kludge to figure out what
-			 * irq this device uses.  This is necessary on things
-			 * without residual data. -- Cort
-			 */
-			unsigned char d = PCI_SLOT(dev->devfn);
-			dev->irq = Motherboard_routes[Motherboard_map[d]];
-			for ( i = 0 ; i <= 5 ; i++ )
-			{
-				if ( dev->base_address[i] > 0x10000000 )
-				{
-					printk("Relocating PCI address %lx -> %lx\n",
-					       dev->base_address[i],
-					       (dev->base_address[i] & 0x00FFFFFF)
-				               | 0x01000000);
-					dev->base_address[i] =
-					  (dev->base_address[i] & 0x00FFFFFF) | 0x01000000;
-					pci_write_config_dword(dev,
-						PCI_BASE_ADDRESS_0+(i*0x4),
-						dev->base_address[i] );
-				}
-			}
-#if 0			
-			/*
-			 * If we have residual data and if it knows about this
-			 * device ask it what the irq is.
-			 *  -- Cort
-			 */
-			ppcd = residual_find_device_id( ~0L, dev->device,
-							-1,-1,-1, 0);
-#endif			
-		}
-		break;
-	case _MACH_chrp:
-		/* PCI interrupts are controlled by the OpenPIC */
-		for(dev=pci_devices; dev; dev=dev->next)
-			if (dev->irq)
-				dev->irq = openpic_to_irq(dev->irq);
-		break;
-	case _MACH_Pmac:
-		for(dev=pci_devices; dev; dev=dev->next)
-		{
-			/*
-			 * Open Firmware often doesn't initialize the,
-			 * PCI_INTERRUPT_LINE config register properly, so we
-			 * should find the device node and se if it has an
-			 * AAPL,interrupts property.
-			 */
-			struct bridge_data *bp = bridges[dev->bus->number];
-			unsigned char pin;
-
-			if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) ||
-			    !pin) 
-				continue;	/* No interrupt generated -> no fixup */
-			fix_intr(bp->node->child, dev);
-		}
-		break;
-	}
-#else /* CONFIG_MBX */
-	for(dev=pci_devices; dev; dev=dev->next)
-	{
-	}
-#endif /* CONFIG_MBX */
+	ppc_md.pcibios_fixup();
 }
 
 void __init pcibios_fixup_bus(struct pci_bus *bus)
@@ -309,7 +88,7 @@
  * fix IRQ's for cards located behind P2P bridges.
  * - Ranjit Deshpande, 01/20/99
  */
-static void __init fix_intr(struct device_node *node, struct pci_dev *dev)
+void __init fix_intr(struct device_node *node, struct pci_dev *dev)
 {
 	unsigned int *reg, *class_code;
 
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/pci.h linux/arch/ppc/kernel/pci.h
--- v2.2.7/linux/arch/ppc/kernel/pci.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/pci.h	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,36 @@
+
+#ifndef __PPC_KERNEL_PCI_H__
+#define __PPC_KERNEL_PCI_H__
+
+extern unsigned long isa_io_base;
+extern unsigned long isa_mem_base;
+extern unsigned long pci_dram_offset;
+
+extern unsigned int  *pci_config_address;
+extern unsigned char *pci_config_data;
+
+void fix_intr(struct device_node *node, struct pci_dev *dev);
+
+#define decl_config_access_method(name) \
+extern int name##_pcibios_read_config_byte(unsigned char bus, \
+	unsigned char dev_fn, unsigned char offset, unsigned char *val); \
+extern int name##_pcibios_read_config_word(unsigned char bus, \
+	unsigned char dev_fn, unsigned char offset, unsigned short *val); \
+extern int name##_pcibios_read_config_dword(unsigned char bus, \
+	unsigned char dev_fn, unsigned char offset, unsigned int *val); \
+extern int name##_pcibios_write_config_byte(unsigned char bus, \
+	unsigned char dev_fn, unsigned char offset, unsigned char val); \
+extern int name##_pcibios_write_config_word(unsigned char bus, \
+	unsigned char dev_fn, unsigned char offset, unsigned short val); \
+extern int name##_pcibios_write_config_dword(unsigned char bus, \
+	unsigned char dev_fn, unsigned char offset, unsigned int val)
+
+#define set_config_access_method(name) \
+	ppc_md.pcibios_read_config_byte = name##_pcibios_read_config_byte; \
+	ppc_md.pcibios_read_config_word = name##_pcibios_read_config_word; \
+	ppc_md.pcibios_read_config_dword = name##_pcibios_read_config_dword; \
+	ppc_md.pcibios_write_config_byte = name##_pcibios_write_config_byte; \
+	ppc_md.pcibios_write_config_word = name##_pcibios_write_config_word; \
+	ppc_md.pcibios_write_config_dword = name##_pcibios_write_config_dword
+
+#endif /* __PPC_KERNEL_PCI_H__ */
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c
--- v2.2.7/linux/arch/ppc/kernel/pmac_pci.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/pmac_pci.c	Thu Apr 29 12:39:01 1999
@@ -21,6 +21,9 @@
 #include <asm/pgtable.h>
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+
+#include "pci.h"
 
 struct bridge_data **bridges, *bridge_list;
 static int max_bus;
@@ -437,5 +440,49 @@
 		if (strcmp(dev->name, "bandit") == 0)
 			init_bandit(bp);
 	}
+}
+
+__initfunc(
+void
+pmac_pcibios_fixup(void))
+{
+	struct pci_dev *dev;
+	
+	/*
+	 * FIXME: This is broken: We should not assign IRQ's to IRQless
+	 *	  devices (look at PCI_INTERRUPT_PIN) and we also should
+	 *	  honor the existence of multi-function devices where
+	 *	  different functions have different interrupt pins. [mj]
+	 */
+	for(dev=pci_devices; dev; dev=dev->next)
+	{
+		/*
+		 * Open Firmware often doesn't initialize the,
+		 * PCI_INTERRUPT_LINE config register properly, so we
+		 * should find the device node and se if it has an
+		 * AAPL,interrupts property.
+		 */
+		struct bridge_data *bp = bridges[dev->bus->number];
+		unsigned char pin;
+			
+		if (pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin) ||
+		    !pin)
+			continue; /* No interrupt generated -> no fixup */
+                fix_intr(bp->node->child, dev);
+	}
+}
+
+__initfunc(
+void
+pmac_setup_pci_ptrs(void))
+{
+	if (find_devices("pci") != 0) {
+		/* looks like a G3 powermac */
+		set_config_access_method(grackle);
+	} else {
+		set_config_access_method(pmac);
+	}
+
+	ppc_md.pcibios_fixup = pmac_pcibios_fixup;
 }
 
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c
--- v2.2.7/linux/arch/ppc/kernel/pmac_pic.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/pmac_pic.c	Thu May  6 23:14:36 1999
@@ -0,0 +1,362 @@
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/prom.h>
+#include "pmac_pic.h"
+
+/* pmac */struct pmac_irq_hw {
+        unsigned int    flag;
+        unsigned int    enable;
+        unsigned int    ack;
+        unsigned int    level;
+};
+
+/* XXX these addresses should be obtained from the device tree */
+static volatile struct pmac_irq_hw *pmac_irq_hw[4] = {
+        (struct pmac_irq_hw *) 0xf3000020,
+        (struct pmac_irq_hw *) 0xf3000010,
+        (struct pmac_irq_hw *) 0xf4000020,
+        (struct pmac_irq_hw *) 0xf4000010,
+};
+
+static int max_irqs;
+static int max_real_irqs;
+
+#define MAXCOUNT 10000000
+
+#define GATWICK_IRQ_POOL_SIZE        10
+static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE];
+
+static void __pmac pmac_mask_and_ack_irq(unsigned int irq_nr)
+{
+        unsigned long bit = 1UL << (irq_nr & 0x1f);
+        int i = irq_nr >> 5;
+
+        if ((unsigned)irq_nr >= max_irqs)
+                return;
+
+        clear_bit(irq_nr, ppc_cached_irq_mask);
+        if (test_and_clear_bit(irq_nr, ppc_lost_interrupts))
+                atomic_dec(&ppc_n_lost_interrupts);
+        out_le32(&pmac_irq_hw[i]->ack, bit);
+        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
+        out_le32(&pmac_irq_hw[i]->ack, bit);
+        do {
+                /* make sure ack gets to controller before we enable
+                   interrupts */
+                mb();
+        } while(in_le32(&pmac_irq_hw[i]->flag) & bit);
+}
+
+static void __pmac pmac_set_irq_mask(unsigned int irq_nr)
+{
+        unsigned long bit = 1UL << (irq_nr & 0x1f);
+        int i = irq_nr >> 5;
+
+        if ((unsigned)irq_nr >= max_irqs)
+                return;
+
+        /* enable unmasked interrupts */
+        out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]);
+
+        do {
+                /* make sure mask gets to controller before we
+                   return to user */
+                mb();
+        } while((in_le32(&pmac_irq_hw[i]->enable) & bit)
+                != (ppc_cached_irq_mask[i] & bit));
+
+        /*
+         * 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 ((bit & ppc_cached_irq_mask[i])
+            && (ld_le32(&pmac_irq_hw[i]->level) & bit)
+            && !(ld_le32(&pmac_irq_hw[i]->flag) & bit)) {
+                if (!test_and_set_bit(irq_nr, ppc_lost_interrupts))
+                        atomic_inc(&ppc_n_lost_interrupts);
+        }
+}
+
+static void __pmac pmac_mask_irq(unsigned int irq_nr)
+{
+        clear_bit(irq_nr, ppc_cached_irq_mask);
+        pmac_set_irq_mask(irq_nr);
+        mb();
+}
+
+static void __pmac pmac_unmask_irq(unsigned int irq_nr)
+{
+        set_bit(irq_nr, ppc_cached_irq_mask);
+        pmac_set_irq_mask(irq_nr);
+}
+
+struct hw_interrupt_type pmac_pic = {
+        " PMAC-PIC ",
+        NULL,
+        NULL,
+        NULL,
+        pmac_unmask_irq,
+        pmac_mask_irq,
+        pmac_mask_and_ack_irq,
+        0
+};
+
+struct hw_interrupt_type gatwick_pic = {
+	" GATWICK  ",
+	NULL,
+	NULL,
+	NULL,
+	pmac_unmask_irq,
+	pmac_mask_irq,
+	pmac_mask_and_ack_irq,
+	0
+};
+
+static void gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+	int irq, bits;
+	
+	for (irq = max_irqs - 1; irq > max_real_irqs; irq -= 32) {
+		int i = irq >> 5;
+		bits = ld_le32(&pmac_irq_hw[i]->flag)
+			| ppc_lost_interrupts[i];
+		if (bits == 0)
+			continue;
+		irq -= cntlzw(bits);
+		break;
+	}
+	/* The previous version of this code allowed for this case, we
+	 * don't.  Put this here to check for it.
+	 * -- Cort
+	 */
+	if ( irq_desc[irq].ctl != &gatwick_pic )
+		printk("gatwick irq not from gatwick pic\n");
+	else
+		ppc_irq_dispatch_handler( regs, irq );
+}
+
+void
+pmac_do_IRQ(struct pt_regs *regs,
+	    int            cpu,
+            int            isfake)
+{
+	int irq;
+	unsigned long bits = 0;
+
+#ifdef __SMP__
+        /* IPI's are a hack on the powersurge -- Cort */
+        if ( cpu != 0 )
+        {
+                if (!isfake)
+                {
+#ifdef CONFIG_XMON
+                        static int xmon_2nd;
+                        if (xmon_2nd)
+                                xmon(regs);
+#endif
+                        smp_message_recv();
+                        goto out;
+                }
+                /* could be here due to a do_fake_interrupt call but we don't
+                   mess with the controller from the second cpu -- Cort */
+                goto out;
+        }
+
+        {
+                unsigned int loops = MAXCOUNT;
+                while (test_bit(0, &global_irq_lock)) {
+                        if (smp_processor_id() == global_irq_holder) {
+                                printk("uh oh, interrupt while we hold global irq lock!\n");
+#ifdef CONFIG_XMON
+                                xmon(0);
+#endif
+                                break;
+                        }
+                        if (loops-- == 0) {
+                                printk("do_IRQ waiting for irq lock (holder=%d)\n", global_irq_holder);
+#ifdef CONFIG_XMON
+                                xmon(0);
+#endif
+                        }
+                }
+        }
+#endif /* __SMP__ */
+
+        for (irq = max_real_irqs - 1; irq > 0; irq -= 32) {
+                int i = irq >> 5;
+                bits = ld_le32(&pmac_irq_hw[i]->flag)
+                        | ppc_lost_interrupts[i];
+                if (bits == 0)
+                        continue;
+                irq -= cntlzw(bits);
+                break;
+        }
+
+        if (irq < 0)
+        {
+                printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+                       irq, regs->nip);
+                ppc_spurious_interrupts++;
+        }
+        else
+        {
+                ppc_irq_dispatch_handler( regs, irq );
+        }
+#ifdef CONFIG_SMP	
+out:
+#endif /* CONFIG_SMP */
+}
+
+/* This routine will fix some missing interrupt values in the device tree
+ * on the gatwick mac-io controller used by some PowerBooks
+ */
+static void __init pmac_fix_gatwick_interrupts(struct device_node *gw, int irq_base)
+{
+	struct device_node *node;
+	int count;
+	
+	memset(gatwick_int_pool, 0, sizeof(gatwick_int_pool));
+	node = gw->child;
+	count = 0;
+	while(node)
+	{
+		/* Fix SCC */
+		if (strcasecmp(node->name, "escc") == 0)
+			if (node->child) {
+				if (node->child->n_intrs < 3) {
+					node->child->intrs = &gatwick_int_pool[count];
+					count += 3;
+				}
+				node->child->n_intrs = 3;				
+				node->child->intrs[0].line = 15+irq_base;
+				node->child->intrs[1].line =  4+irq_base;
+				node->child->intrs[2].line =  5+irq_base;
+				printk(KERN_INFO "irq: fixed SCC on second controller (%d,%d,%d)\n",
+					node->child->intrs[0].line,
+					node->child->intrs[1].line,
+					node->child->intrs[2].line);
+			}
+		/* Fix media-bay & left SWIM */
+		if (strcasecmp(node->name, "media-bay") == 0) {
+			struct device_node* ya_node;
+
+			if (node->n_intrs == 0)
+				node->intrs = &gatwick_int_pool[count++];
+			node->n_intrs = 1;
+			node->intrs[0].line = 29+irq_base;
+			printk(KERN_INFO "irq: fixed media-bay on second controller (%d)\n",
+					node->intrs[0].line);
+			
+			ya_node = node->child;
+			while(ya_node)
+			{
+				if (strcasecmp(ya_node->name, "floppy") == 0) {
+					if (ya_node->n_intrs < 2) {
+						ya_node->intrs = &gatwick_int_pool[count];
+						count += 2;
+					}
+					ya_node->n_intrs = 2;
+					ya_node->intrs[0].line = 19+irq_base;
+					ya_node->intrs[1].line =  1+irq_base;
+					printk(KERN_INFO "irq: fixed floppy on second controller (%d,%d)\n",
+						ya_node->intrs[0].line, ya_node->intrs[1].line);
+				} 
+				if (strcasecmp(ya_node->name, "ata4") == 0) {
+					if (ya_node->n_intrs < 2) {
+						ya_node->intrs = &gatwick_int_pool[count];
+						count += 2;
+					}
+					ya_node->n_intrs = 2;
+					ya_node->intrs[0].line = 14+irq_base;
+					ya_node->intrs[1].line =  3+irq_base;
+					printk(KERN_INFO "irq: fixed ide on second controller (%d,%d)\n",
+						ya_node->intrs[0].line, ya_node->intrs[1].line);
+				} 
+				ya_node = ya_node->sibling;
+			}
+		}
+		node = node->sibling;
+	}
+	if (count > 10) {
+		printk("WARNING !! Gatwick interrupt pool overflow\n");
+		printk("  GATWICK_IRQ_POOL_SIZE = %d\n", GATWICK_IRQ_POOL_SIZE);
+		printk("              requested = %d\n", count);
+	}
+}
+
+__initfunc(void
+pmac_pic_init(void))
+{
+        int i;
+        struct device_node *irqctrler;
+        unsigned long addr;
+	int second_irq = -999;
+
+
+	/* G3 powermacs have 64 interrupts, G3 Series PowerBook have 128, 
+	   others have 32 */
+	max_irqs = max_real_irqs = 32;
+	irqctrler = find_devices("mac-io");
+	if (irqctrler)
+	{
+		max_real_irqs = 64;
+		if (irqctrler->next)
+			max_irqs = 128;
+		else
+			max_irqs = 64;
+	}
+	for ( i = 0; i < max_real_irqs ; i++ )
+		irq_desc[i].ctl = &pmac_pic;
+
+	/* get addresses of first controller */
+	if (irqctrler) {
+		if  (irqctrler->n_addrs > 0) {
+			addr = (unsigned long) 
+				ioremap(irqctrler->addrs[0].address, 0x40);
+			for (i = 0; i < 2; ++i)
+				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
+					(addr + (2 - i) * 0x10);
+		}
+		
+		/* get addresses of second controller */
+		irqctrler = (irqctrler->next) ? irqctrler->next : NULL;
+		if (irqctrler && irqctrler->n_addrs > 0) {
+			addr = (unsigned long) 
+				ioremap(irqctrler->addrs[0].address, 0x40);
+			for (i = 2; i < 4; ++i)
+				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
+					(addr + (4 - i) * 0x10);
+		}
+	}
+
+	/* disable all interrupts in all controllers */
+	for (i = 0; i * 32 < max_irqs; ++i)
+		out_le32(&pmac_irq_hw[i]->enable, 0);
+	
+	/* get interrupt line of secondary interrupt controller */
+	if (irqctrler) {
+		second_irq = irqctrler->intrs[0].line;
+		printk(KERN_INFO "irq: secondary controller on irq %d\n",
+			(int)second_irq);
+		if (device_is_compatible(irqctrler, "gatwick"))
+			pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
+		for ( i = max_real_irqs ; i < max_irqs ; i++ )
+			irq_desc[i].ctl = &gatwick_pic;
+		request_irq( second_irq, gatwick_action, SA_INTERRUPT,
+			     "gatwick cascade", 0 );
+	}
+	printk("System has %d possible interrupts\n", max_irqs);
+	if (max_irqs != max_real_irqs)
+		printk(KERN_DEBUG "%d interrupts on main controller\n",
+			max_real_irqs);
+
+#ifdef CONFIG_XMON
+	request_irq(20, xmon_irq, 0, "NMI - XMON", 0);
+#endif	/* CONFIG_XMON */
+}
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/pmac_pic.h linux/arch/ppc/kernel/pmac_pic.h
--- v2.2.7/linux/arch/ppc/kernel/pmac_pic.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/pmac_pic.h	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,15 @@
+#ifndef _PPC_KERNEL_PMAC_PIC_H
+#define _PPC_KERNEL_PMAC_PIC_H
+
+#include "local_irq.h"
+
+extern struct hw_interrupt_type pmac_pic;
+
+void pmac_pic_init(void);
+void pmac_do_IRQ(struct pt_regs *regs,
+                 int            cpu,
+                 int            isfake);
+
+
+#endif /* _PPC_KERNEL_PMAC_PIC_H */
+
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c
--- v2.2.7/linux/arch/ppc/kernel/pmac_setup.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/pmac_setup.c	Thu Apr 29 12:39:01 1999
@@ -44,6 +44,7 @@
 #include <asm/prom.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
+#include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/pci-bridge.h>
 #include <asm/adb.h>
@@ -52,7 +53,36 @@
 #include <asm/ohare.h>
 #include <asm/mediabay.h>
 #include <asm/feature.h>
+#include <asm/ide.h>
+#include <asm/machdep.h>
+
 #include "time.h"
+#include "local_irq.h"
+#include "pmac_pic.h"
+
+#undef SHOW_GATWICK_IRQS
+
+unsigned long pmac_get_rtc_time(void);
+int pmac_set_rtc_time(unsigned long nowtime);
+void pmac_read_rtc_time(void);
+void pmac_calibrate_decr(void);
+void pmac_setup_pci_ptrs(void);
+
+extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int mackbd_getkeycode(unsigned int scancode);
+extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char mackbd_unexpected_up(unsigned char keycode);
+extern void mackbd_leds(unsigned char leds);
+extern void mackbd_init_hw(void);
+extern unsigned char mackbd_sysrq_xlate[128];
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+extern char pckbd_unexpected_up(unsigned char keycode);
+extern void pckbd_leds(unsigned char leds);
+extern void pckbd_init_hw(void);
 
 unsigned char drive_info;
 
@@ -291,15 +321,12 @@
 int boot_part;
 kdev_t boot_dev;
 
-void __init powermac_init(void)
+__initfunc(void
+pmac_init2(void))
 {
-  	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
-		return;
 	adb_init();
 	pmac_nvram_init();
-	if (_machine == _MACH_Pmac) {
-		media_bay_init();
-	}
+	media_bay_init();
 }
 
 #ifdef CONFIG_SCSI
@@ -402,5 +429,176 @@
 		boot_dev = NODEV;
 		printk(" (root)");
 	}
+}
+
+void
+pmac_restart(char *cmd)
+{
+	struct adb_request req;
+
+	switch (adb_hardware) {
+	case ADB_VIACUDA:
+		cuda_request(&req, NULL, 2, CUDA_PACKET,
+			     CUDA_RESET_SYSTEM);
+		for (;;)
+			cuda_poll();
+		break;
+
+	case ADB_VIAPMU:
+		pmu_restart();
+		break;
+	default:
+	}
+}
+
+void
+pmac_power_off(void)
+{
+	struct adb_request req;
+
+	switch (adb_hardware) {
+	case ADB_VIACUDA:
+		cuda_request(&req, NULL, 2, CUDA_PACKET,
+			     CUDA_POWERDOWN);
+		for (;;)
+			cuda_poll();
+		break;
+
+	case ADB_VIAPMU:
+		pmu_shutdown();
+		break;
+	default:
+	}
+}
+
+void
+pmac_halt(void)
+{
+   pmac_power_off();
+}
+
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+void
+pmac_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+	ide_insw(port, buf, ns);
+}
+
+void
+pmac_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+	ide_outsw(port, buf, ns);
+}
+
+int
+pmac_ide_default_irq(ide_ioreg_t base)
+{
+        return 0;
+}
+
+ide_ioreg_t
+pmac_ide_default_io_base(int index)
+{
+#if defined(CONFIG_BLK_DEV_IDE_PMAC)
+        return pmac_ide_regbase[index];
+#else
+	return 0;
+#endif
+}
+
+int
+pmac_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+        return 0;
+}
+
+void
+pmac_ide_request_region(ide_ioreg_t from,
+			unsigned int extent,
+			const char *name)
+{
+}
+
+void
+pmac_ide_release_region(ide_ioreg_t from,
+			unsigned int extent)
+{
+}
+
+/* Convert the shorts/longs in hd_driveid from little to big endian;
+ * chars are endian independant, of course, but strings need to be flipped.
+ * (Despite what it says in drivers/block/ide.h, they come up as little
+ * endian...)
+ *
+ * Changes to linux/hdreg.h may require changes here. */
+void
+pmac_ide_fix_driveid(struct hd_driveid *id)
+{
+        ppc_generic_ide_fix_driveid(id);
+}
+
+/* This is declared in drivers/block/ide-pmac.c */
+void pmac_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq);
+#endif
+
+__initfunc(void
+pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	  unsigned long r6, unsigned long r7))
+{
+	pmac_setup_pci_ptrs();
+
+	/* isa_io_base gets set in pmac_find_bridges */
+	isa_mem_base = PMAC_ISA_MEM_BASE;
+	pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
+	ISA_DMA_THRESHOLD = ~0L;
+	DMA_MODE_READ = 1;
+	DMA_MODE_WRITE = 2;
+
+	ppc_md.setup_arch     = pmac_setup_arch;
+	ppc_md.setup_residual = NULL;
+	ppc_md.get_cpuinfo    = pmac_get_cpuinfo;
+	ppc_md.irq_cannonicalize = NULL;
+	ppc_md.init_IRQ       = pmac_pic_init;
+	ppc_md.do_IRQ         = pmac_do_IRQ;
+	ppc_md.init           = pmac_init2;
+
+	ppc_md.restart        = pmac_restart;
+	ppc_md.power_off      = pmac_power_off;
+	ppc_md.halt           = pmac_halt;
+
+	ppc_md.time_init      = NULL;
+	ppc_md.set_rtc_time   = pmac_set_rtc_time;
+	ppc_md.get_rtc_time   = pmac_get_rtc_time;
+	ppc_md.calibrate_decr = pmac_calibrate_decr;
+
+#ifdef CONFIG_VT
+	ppc_md.kbd_setkeycode    = mackbd_setkeycode;
+	ppc_md.kbd_getkeycode    = mackbd_getkeycode;
+	ppc_md.kbd_translate     = mackbd_translate;
+	ppc_md.kbd_unexpected_up = mackbd_unexpected_up;
+	ppc_md.kbd_leds          = mackbd_leds;
+	ppc_md.kbd_init_hw       = mackbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.kbd_sysrq_xlate	 = mackbd_sysrq_xlate;
+#endif	
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE_PMAC)
+        ppc_ide_md.insw = pmac_ide_insw;
+        ppc_ide_md.outsw = pmac_ide_outsw;
+        ppc_ide_md.default_irq = pmac_ide_default_irq;
+        ppc_ide_md.default_io_base = pmac_ide_default_io_base;
+        ppc_ide_md.check_region = pmac_ide_check_region;
+        ppc_ide_md.request_region = pmac_ide_request_region;
+        ppc_ide_md.release_region = pmac_ide_release_region;
+        ppc_ide_md.fix_driveid = pmac_ide_fix_driveid;
+        ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports;
+
+        ppc_ide_md.io_base = 0;
+#endif		
 }
 
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/ppc8xx_pic.c linux/arch/ppc/kernel/ppc8xx_pic.c
--- v2.2.7/linux/arch/ppc/kernel/ppc8xx_pic.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/ppc8xx_pic.c	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,49 @@
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/irq.h>
+#include <asm/8xx_immap.h>
+#include <asm/mbx.h>
+#include "ppc8xx_pic.h"
+
+
+static void mbx_mask_irq(unsigned int irq_nr)
+{
+	if ( irq_nr == ISA_BRIDGE_INT ) return;
+	if ( irq_nr >= ppc8xx_pic.irq_offset )
+		irq_nr -= ppc8xx_pic.irq_offset;
+	ppc_cached_irq_mask[0] &= ~(1 << (31-irq_nr));
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =	ppc_cached_irq_mask[0];
+}
+
+static void mbx_unmask_irq(unsigned int irq_nr)
+{
+	if ( irq_nr >= ppc8xx_pic.irq_offset )
+		irq_nr -= ppc8xx_pic.irq_offset;
+	ppc_cached_irq_mask[0] |= (1 << (31-irq_nr));
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =	ppc_cached_irq_mask[0];
+}
+
+static void mbx_mask_and_ack(unsigned int irq_nr)
+{
+	/* this shouldn't be masked, we mask the 8259 if we need to -- Cort */
+	if ( irq_nr != ISA_BRIDGE_INT )
+		mbx_mask_irq(irq_nr);
+	if ( irq_nr >= ppc8xx_pic.irq_offset )
+		irq_nr -= ppc8xx_pic.irq_offset;
+	/* clear the pending bits */
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-irq_nr);
+}
+
+struct hw_interrupt_type ppc8xx_pic = {
+	" 8xx SIU  ",
+	NULL,
+	NULL,
+	NULL,
+	mbx_unmask_irq,
+	mbx_mask_irq,
+	mbx_mask_and_ack,
+	0
+};
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/ppc8xx_pic.h linux/arch/ppc/kernel/ppc8xx_pic.h
--- v2.2.7/linux/arch/ppc/kernel/ppc8xx_pic.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/ppc8xx_pic.h	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,9 @@
+
+#ifndef _PPC_KERNEL_PPC8xx_H
+#define _PPC_KERNEL_PPC8xx_H
+
+#include "local_irq.h"
+
+extern struct hw_interrupt_type ppc8xx_pic;
+
+#endif /* _PPC_KERNEL_PPC8xx_H */
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c
--- v2.2.7/linux/arch/ppc/kernel/ppc_ksyms.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/ppc_ksyms.c	Thu Apr 29 12:39:01 1999
@@ -27,6 +27,8 @@
 #include <asm/irq.h>
 #include <asm/feature.h>
 #include <asm/spinlock.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
 
 #define __KERNEL_SYSCALLS__
 #include <linux/unistd.h>
@@ -40,7 +42,7 @@
 extern void ProgramCheckException(struct pt_regs *regs);
 extern void SingleStepException(struct pt_regs *regs);
 extern int sys_sigreturn(struct pt_regs *regs);
-extern atomic_t n_lost_interrupts;
+extern atomic_t ppc_n_lost_interrupts;
 extern void do_lost_interrupts(unsigned long);
 extern int do_signal(sigset_t *, struct pt_regs *);
 
@@ -59,16 +61,21 @@
 EXPORT_SYMBOL(ProgramCheckException);
 EXPORT_SYMBOL(SingleStepException);
 EXPORT_SYMBOL(sys_sigreturn);
-EXPORT_SYMBOL(n_lost_interrupts);
+EXPORT_SYMBOL(ppc_n_lost_interrupts);
 EXPORT_SYMBOL(do_lost_interrupts);
 EXPORT_SYMBOL(enable_irq);
 EXPORT_SYMBOL(disable_irq);
-EXPORT_SYMBOL(local_irq_count);
-EXPORT_SYMBOL(local_bh_count);
+EXPORT_SYMBOL(ppc_local_irq_count);
+EXPORT_SYMBOL(ppc_local_bh_count);
 
 EXPORT_SYMBOL(isa_io_base);
 EXPORT_SYMBOL(isa_mem_base);
 EXPORT_SYMBOL(pci_dram_offset);
+EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
+EXPORT_SYMBOL(DMA_MODE_READ);
+EXPORT_SYMBOL(DMA_MODE_WRITE);
+EXPORT_SYMBOL(_prep_type);
+EXPORT_SYMBOL(ucSystemType);
 
 EXPORT_SYMBOL(atomic_add);
 EXPORT_SYMBOL(atomic_sub);
@@ -157,6 +164,7 @@
 EXPORT_SYMBOL(flush_instruction_cache);
 EXPORT_SYMBOL(_get_PVR);
 EXPORT_SYMBOL(giveup_fpu);
+EXPORT_SYMBOL(enable_kernel_fp);
 EXPORT_SYMBOL(flush_icache_range);
 EXPORT_SYMBOL(xchg_u32);
 #ifdef __SMP__
@@ -173,18 +181,14 @@
 EXPORT_SYMBOL(_write_unlock);
 #endif
 
-#ifndef CONFIG_MACH_SPECIFIC
 EXPORT_SYMBOL(_machine);
-#endif
+EXPORT_SYMBOL(ppc_md);
 
 EXPORT_SYMBOL(adb_request);
-EXPORT_SYMBOL(adb_autopoll);
 EXPORT_SYMBOL(adb_register);
 EXPORT_SYMBOL(cuda_request);
-EXPORT_SYMBOL(cuda_send_request);
 EXPORT_SYMBOL(cuda_poll);
 EXPORT_SYMBOL(pmu_request);
-EXPORT_SYMBOL(pmu_send_request);
 EXPORT_SYMBOL(pmu_poll);
 #ifdef CONFIG_PMAC_PBOOK
 EXPORT_SYMBOL(sleep_notifier_list);
@@ -196,7 +200,6 @@
 EXPORT_SYMBOL(find_path_device);
 EXPORT_SYMBOL(find_phandle);
 EXPORT_SYMBOL(get_property);
-EXPORT_SYMBOL(device_is_compatible);
 EXPORT_SYMBOL(pci_io_base);
 EXPORT_SYMBOL(pci_device_loc);
 EXPORT_SYMBOL(feature_set);
@@ -211,9 +214,8 @@
 EXPORT_SYMBOL(nvram_write_byte);
 #endif /* CONFIG_PMAC */
 
-#ifdef CONFIG_SOUND_MODULE
 EXPORT_SYMBOL(abs);
-#endif
+EXPORT_SYMBOL(device_is_compatible);
 
 /* The following are special because they're not called
    explicitly (the C compiler generates them).  Fortunately,
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/prep_nvram.c linux/arch/ppc/kernel/prep_nvram.c
--- v2.2.7/linux/arch/ppc/kernel/prep_nvram.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/prep_nvram.c	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,173 @@
+/*
+ *  linux/arch/ppc/kernel/prep_nvram.c
+ *
+ *  Copyright (C) 1998  Corey Minyard
+ *
+ */
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/machdep.h>
+#include <asm/prep_nvram.h>
+
+/*
+ * Allow for a maximum of 32K of PReP NvRAM data
+ */
+#define MAX_PREP_NVRAM 0x8000
+static char nvramData[MAX_PREP_NVRAM];
+static NVRAM_MAP *nvram=(NVRAM_MAP *)&nvramData[0];
+
+#define PREP_NVRAM_AS0	0x74
+#define PREP_NVRAM_AS1	0x75
+#define PREP_NVRAM_DATA	0x77
+
+unsigned char *rs_pcNvRAM;
+
+unsigned char prep_nvram_read_val(int addr)
+{
+	outb(addr, PREP_NVRAM_AS0);
+	outb(addr>>8, PREP_NVRAM_AS1);
+	return inb(PREP_NVRAM_DATA);
+}
+  
+void prep_nvram_write_val(int           addr,
+			  unsigned char val)
+{
+	outb(addr, PREP_NVRAM_AS0);
+	outb(addr>>8, PREP_NVRAM_AS1);
+   	outb(val, PREP_NVRAM_DATA);
+}
+  
+/*
+ * Most Radstone boards have NvRAM memory mapped at offset 8M in ISA space
+ */
+unsigned char rs_nvram_read_val(int addr)
+{
+	return rs_pcNvRAM[addr];
+}
+  
+void rs_nvram_write_val(int addr,
+			unsigned char val)
+{
+	rs_pcNvRAM[addr]=val;
+}
+  
+__initfunc(void init_prep_nvram(void))
+{
+	unsigned char *nvp;
+	int  i;
+	int  nvramSize;
+
+	/*
+	 * I'm making the assumption that 32k will always cover the
+	 * nvramsize.  If this isn't the case please let me know and we can
+	 * map the header, then get the size from the header, then map
+	 * the whole size. -- Cort
+	 */
+	if ( _prep_type == _PREP_Radstone )
+		rs_pcNvRAM = (unsigned char *)ioremap(_ISA_MEM_BASE+0x00800000,
+						      32<<10);
+	request_region(PREP_NVRAM_AS0, 0x8, "PReP NVRAM");
+	/*
+	 * The following could fail if the NvRAM were corrupt but
+	 * we expect the boot firmware to have checked its checksum
+	 * before boot
+	 */
+	nvp = (char *) &nvram->Header;
+	for (i=0; i<sizeof(HEADER); i++)
+	{
+		*nvp = ppc_md.nvram_read_val(i);
+		nvp++;
+	}
+	
+	/*
+	 * The PReP NvRAM may be any size so read in the header to
+	 * determine how much we must read in order to get the complete
+	 * GE area
+	 */
+	nvramSize=(int)nvram->Header.GEAddress+nvram->Header.GELength;
+	if(nvramSize>MAX_PREP_NVRAM)
+	{
+		/*
+		 * NvRAM is too large
+		 */
+		nvram->Header.GELength=0;
+		return;
+	}
+
+	/*
+	 * Read the remainder of the PReP NvRAM
+	 */
+	nvp = (char *) &nvram->GEArea[0];
+	for (i=sizeof(HEADER); i<nvramSize; i++)
+	{
+		*nvp = ppc_md.nvram_read_val(i);
+		nvp++;
+	}
+}
+
+__prep
+char *prep_nvram_get_var(const char *name)
+{
+	char *cp;
+	int  namelen;
+
+	namelen = strlen(name);
+	cp = prep_nvram_first_var();
+	while (cp != NULL) {
+		if ((strncmp(name, cp, namelen) == 0)
+		    && (cp[namelen] == '='))
+		{
+			return cp+namelen+1;
+		}
+		cp = prep_nvram_next_var(cp);
+	}
+
+	return NULL;
+}
+
+__prep
+char *prep_nvram_first_var(void)
+{
+        if (nvram->Header.GELength == 0) {
+		return NULL;
+	} else {
+		return (((char *)nvram)
+			+ ((unsigned int) nvram->Header.GEAddress));
+	}
+}
+
+__prep
+char *prep_nvram_next_var(char *name)
+{
+	char *cp;
+
+
+	cp = name;
+	while (((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength)
+	       && (*cp != '\0'))
+	{
+		cp++;
+	}
+
+	/* Skip over any null characters. */
+	while (((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength)
+	       && (*cp == '\0'))
+	{
+		cp++;
+	}
+
+	if ((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength) {
+		return cp;
+	} else {
+		return NULL;
+	}
+}
+
+
+
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c
--- v2.2.7/linux/arch/ppc/kernel/prep_pci.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/prep_pci.c	Thu Apr 29 12:39:01 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: prep_pci.c,v 1.25 1999/03/03 15:09:45 cort Exp $
+ * $Id: prep_pci.c,v 1.31 1999/04/21 18:21:37 cort Exp $
  * PReP pci functions.
  * Originally by Gary Thomas
  * rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
@@ -11,11 +11,19 @@
 #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/openpic.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
 #include <asm/ptrace.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/residual.h>
 #include <asm/processor.h>
+#include <asm/irq.h>
+#include <asm/machdep.h>
+
+#include "pci.h"
 
 #define MAX_DEVNR 22
 
@@ -169,6 +177,46 @@
    	15	/* Line 4 */
 };
    
+/* Motorola Genesis2 MVME26XX, MVME 36XX */
+/* The final version for these boards should use the Raven PPC/PCI bridge 
+interrupt controller which is much sophisticated and allows more
+devices on the PCI bus. */
+static char Genesis2_pci_IRQ_map[23] __prepdata =
+  {
+        0,	/* Slot 0  - ECC memory controller/PCI bridge */
+	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 - ISA bridge */
+	3,	/* Slot 12 - SCSI */
+  	2,	/* Slot 13 - Universe PCI/VME bridge (and 22..24) */
+  	1,	/* Slot 14 - Ethernet */
+  	0,	/* Slot 15 - Unused (graphics on 3600, would be 20 ?) */
+	4,      /* Slot 16 - PMC slot, assume uses INTA */
+	0,      /* Slot 17 */
+	0,      /* Slot 18 */
+	0,      /* Slot 19 */
+	0,      /* Slot 20 */
+	0,      /* Slot 21 */
+	0,      /* Slot 22 */
+  };
+
+static char Genesis2_pci_IRQ_routes[] __prepdata=
+   {
+   	0,	/* Line 0 - Unused */
+   	10,	/* Line 1 - INTA */
+   	11,	/* Line 2 - INTB */
+   	14,	/* Line 3 - INTC */
+   	15	/* Line 4 - INTD */
+   };
+   
 /* Motorola Series-E */
 static char Comet_pci_IRQ_map[16] __prepdata =
 {
@@ -328,106 +376,24 @@
 #define ELCRM_INT7_LVL          0x80
 #define ELCRM_INT5_LVL          0x20
 
-/*
- * Mechanism 1 configuration space access as defined in the PCI spec.
- */
-#define CFG_ADDR (volatile u_int *)0x80000cf8
-#define CFG_DATA 0x80000cfc
-
-#define CFG_DEV_ADDR(b, d, o)	(0x80000000 |	\
-				 ((b) << 16) |	\
-				 ((d) << 8) |	\
-				 ((o) & ~3))
-
-unsigned char max_bus=255;
-
-int mech1_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
-				     unsigned char offset, unsigned char *val)
-{
-	*val = 0xff;
-	if (bus > max_bus)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	out_le32(CFG_ADDR, CFG_DEV_ADDR(bus, dev_fn, offset));
-	*val = in_8((unsigned char *)CFG_DATA + (offset & 3));
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int mech1_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
-				     unsigned char offset, unsigned short *val)
-{
-	*val = 0xffff;
-	if (bus > max_bus)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	if ((offset & 1) != 0)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	out_le32(CFG_ADDR, CFG_DEV_ADDR(bus, dev_fn, offset));
-	*val = in_le16((volatile unsigned short *)(CFG_DATA + (offset&3)));
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int mech1_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
-				      unsigned char offset, unsigned int *val)
-{
-	*val = 0xffffffff;
-	if (bus > max_bus)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	if ((offset & 3) != 0)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	out_le32(CFG_ADDR, CFG_DEV_ADDR(bus, dev_fn, offset));
-	*val = in_le32((volatile unsigned int *)CFG_DATA);
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int mech1_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
-				      unsigned char offset, unsigned char val)
-{
-	if (bus > max_bus)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	out_le32(CFG_ADDR, CFG_DEV_ADDR(bus, dev_fn, offset));
-	out_8((unsigned char *)CFG_DATA + (offset & 3), val);
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int mech1_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
-				      unsigned char offset, unsigned short val)
-{
-	if (bus > max_bus)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	if ((offset & 1) != 0)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	out_le32(CFG_ADDR, CFG_DEV_ADDR(bus, dev_fn, offset));
-	out_le16((volatile unsigned short *)(CFG_DATA + (offset&3)), val);
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int mech1_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
-				    unsigned char offset, unsigned int val)
-{
-	if (bus > max_bus)
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	if ((offset & 1) != 0)
-		return PCIBIOS_BAD_REGISTER_NUMBER;
-	out_le32(CFG_ADDR, CFG_DEV_ADDR(bus, dev_fn, offset));
-	out_le32((volatile unsigned int *)CFG_DATA, val);
-	return PCIBIOS_SUCCESSFUL;
-}
+#define CFGPTR(dev) (0x80800000 | (1<<(dev>>3)) | ((dev&7)<<8) | offset)
+#define DEVNO(dev)  (dev>>3)                                  
 
 __prep
 int
 prep_pcibios_read_config_dword (unsigned char bus,
 			   unsigned char dev, unsigned char offset, unsigned int *val)
 {
-	unsigned long _val;
+	unsigned long _val;                                          
 	unsigned long *ptr;
-	dev >>= 3;
-	
-	if ((bus != 0) || (dev > MAX_DEVNR))
-	{
+
+	if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
+	{                   
 		*val = 0xFFFFFFFF;
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	} else
+		return PCIBIOS_DEVICE_NOT_FOUND;    
+	} else                                                                
 	{
-		ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
+		ptr = (unsigned long *)CFGPTR(dev);
 		_val = le32_to_cpu(*ptr);
 	}
 	*val = _val;
@@ -439,16 +405,16 @@
 prep_pcibios_read_config_word (unsigned char bus,
 			  unsigned char dev, unsigned char offset, unsigned short *val)
 {
-	unsigned short _val;
+	unsigned short _val;                                          
 	unsigned short *ptr;
-	dev >>= 3;
-	if ((bus != 0) || (dev > MAX_DEVNR))
-	{
-		*val = (unsigned short)0xFFFFFFFF;
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	} else
+
+	if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
+	{                   
+		*val = 0xFFFF;
+		return PCIBIOS_DEVICE_NOT_FOUND;    
+	} else                                                                
 	{
-		ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
+		ptr = (unsigned short *)CFGPTR(dev);
 		_val = le16_to_cpu(*ptr);
 	}
 	*val = _val;
@@ -460,16 +426,16 @@
 prep_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;
-	if ((bus != 0) || (dev > MAX_DEVNR))
-	{
-		*(unsigned long *)val = (unsigned long) 0xFFFFFFFF;
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	} else
+	unsigned char _val;                                          
+	unsigned char *ptr;
+
+	if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
+	{                   
+		*val = 0xFF;
+		return PCIBIOS_DEVICE_NOT_FOUND;    
+	} else                                                                
 	{
-		ptr = (unsigned char *)(0x80800000 | (1<<dev) | (offset ^ 1));
+		ptr = (unsigned char *)CFGPTR(dev);
 		_val = *ptr;
 	}
 	*val = _val;
@@ -483,14 +449,14 @@
 {
 	unsigned long _val;
 	unsigned long *ptr;
-	dev >>= 3;
+
 	_val = le32_to_cpu(val);
-	if ((bus != 0) || (dev > MAX_DEVNR))
+	if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
 	{
 		return PCIBIOS_DEVICE_NOT_FOUND;
 	} else
 	{
-		ptr = (unsigned long *)(0x80800000 | (1<<dev) | offset);
+		ptr = (unsigned long *)CFGPTR(dev);
 		*ptr = _val;
 	}
 	return PCIBIOS_SUCCESSFUL;
@@ -503,14 +469,14 @@
 {
 	unsigned short _val;
 	unsigned short *ptr;
-	dev >>= 3;
+
 	_val = le16_to_cpu(val);
-	if ((bus != 0) || (dev > MAX_DEVNR))
+	if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
 	{
 		return PCIBIOS_DEVICE_NOT_FOUND;
 	} else
 	{
-		ptr = (unsigned short *)(0x80800000 | (1<<dev) | offset);
+		ptr = (unsigned short *)CFGPTR(dev);
 		*ptr = _val;
 	}
 	return PCIBIOS_SUCCESSFUL;
@@ -523,20 +489,20 @@
 {
 	unsigned char _val;
 	unsigned char *ptr;
-	dev >>= 3;
+
 	_val = val;
-	if ((bus != 0) || (dev > MAX_DEVNR))
+	if ((bus != 0) || (DEVNO(dev) > MAX_DEVNR))
 	{
 		return PCIBIOS_DEVICE_NOT_FOUND;
 	} else
 	{
-		ptr = (unsigned char *)(0x80800000 | (1<<dev) | (offset^1));
+		ptr = (unsigned char *)CFGPTR(dev);
 		*ptr = _val;
 	}
 	return PCIBIOS_SUCCESSFUL;
 }
 
-__initfunc(unsigned long route_pci_interrupts(void))
+__initfunc(unsigned long prep_route_pci_interrupts(void))
 {
 	unsigned char *ibc_pirq = (unsigned char *)0x80800860;
 	unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
@@ -568,11 +534,15 @@
 			Motherboard_map = Utah_pci_IRQ_map;
 			Motherboard_routes = Utah_pci_IRQ_routes;
 			break;
-                case 0xE0: /* MTX -- close enough?? to Genesis, so reuse it */
-                        Motherboard_map_name = "Motorola MTX";
-                        Motherboard_map = Genesis_pci_IRQ_map;
-                        Motherboard_routes = Genesis_pci_IRQ_routes;
-                        break;
+		case 0xE0: /* MVME 26xx, 36xx, MTX ? */
+			Motherboard_map_name = "Genesis2";
+			Motherboard_map = Genesis2_pci_IRQ_map;
+			Motherboard_routes = Genesis2_pci_IRQ_routes;
+
+			/* Return: different ibc_pcicon and
+			   pirq already set up by firmware. */
+			return 0; 
+			break;
 		case 0x40: /* PowerStack */
 		default: /* Can't hurt, can it? */
 			Motherboard_map_name = "Blackhawk (Powerstack)";
@@ -705,5 +675,171 @@
 	/* Enable PCI interrupts */
 	*ibc_pcicon |= 0x20;
 	return 0;
+}
+
+__initfunc(
+static inline void fixup_pci_interrupts(PnP_TAG_PACKET *pkt)) {
+#define data pkt->L4_Pack.L4_Data.L4_PPCPack.PPCData
+        u_int bus = data[16];
+        u_char *End, *p;
+
+        End = data + ld_le16((u_short *)(&pkt->L4_Pack.Count0)) - 1;
+        printk("Interrupt mapping from %d to %d\n", 20, End-data);
+        for (p=data+20; p<End; p+=12){
+                struct pci_dev *dev;
+                for (dev=pci_devices; dev; dev=dev->next) {
+                        unsigned code, irq;
+                        u_char pin;
+
+                        if ( dev->bus->number != bus ||
+                             PCI_SLOT(dev->devfn) != PCI_SLOT(p[1]))
+                                continue;
+                        pci_read_config_byte(dev,  PCI_INTERRUPT_PIN, &pin);
+                        if(!pin) continue;
+                        code=ld_le16((unsigned short *)
+                                    (p+4+2*(pin-1)));
+                        /* Set vector to 0 for unrouted PCI ints. This code
+                         * is ugly but handles correctly the special case of
+                         * interrupt 0 (8259 cascade) on OpenPIC
+                         */
+
+                        irq = (code == 0xffff) ? 0 : code&0x7fff;
+                        if (p[2] == 2) { /* OpenPIC */
+                                if (irq) {
+                                        openpic_set_sense(irq, code<0x8000);
+                                        irq=openpic_to_irq(irq);
+                                } else continue;
+                        } else if (p[2] != 1){ /* Not 8259 */
+                                printk("Unknown or unsupported "
+                                       "interrupt controller"
+                                       "type %d.\n",  p[2]);
+                                continue;
+                        }
+                        dev->irq=irq;
+                }
+
+        }
+}
+
+__initfunc(
+static inline void fixup_bases(struct pci_dev *dev)) {
+        int k;
+        for (k=0; k<6; k++) {
+		/* FIXME: get the base address physical offset from 
+			the Raven instead of hard coding it.
+				-- Troy */
+                if (dev->base_address[k] &&
+                    (dev->base_address[k]&PCI_BASE_ADDRESS_SPACE)
+                    == PCI_BASE_ADDRESS_SPACE_MEMORY)
+                        dev->base_address[k]+=0xC0000000;
+                if ((dev->base_address[k] &
+                     (PCI_BASE_ADDRESS_SPACE |
+                      PCI_BASE_ADDRESS_MEM_TYPE_MASK))
+                     == (PCI_BASE_ADDRESS_SPACE_MEMORY |
+                         PCI_BASE_ADDRESS_MEM_TYPE_64))
+                        k++;
+        }
+}
+
+
+__initfunc(
+void
+prep_pcibios_fixup(void))
+{
+        struct pci_dev *dev;
+        extern unsigned char *Motherboard_map;
+        extern unsigned char *Motherboard_routes;
+        unsigned char i;
+
+        if ( _prep_type == _PREP_Radstone )
+        {
+                printk("Radstone boards require no PCI fixups\n");
+        }
+        else
+        {
+	        prep_route_pci_interrupts();
+                for(dev=pci_devices; dev; dev=dev->next)
+                {
+                        /*
+                         * Use our old hard-coded kludge to figure out what
+                         * irq this device uses.  This is necessary on things
+                         * without residual data. -- Cort
+                         */
+                        unsigned char d = PCI_SLOT(dev->devfn);
+                        dev->irq = Motherboard_routes[Motherboard_map[d]];
+                        for ( i = 0 ; i <= 5 ; i++ )
+                        {
+                                if ( dev->base_address[i] > 0x10000000 )
+                                {
+                                        printk("Relocating PCI address %lx -> %lx\n",
+                                               dev->base_address[i],
+                                               (dev->base_address[i] & 0x00FFFFFF)
+                                               | 0x01000000);
+                                        dev->base_address[i] =
+                                          (dev->base_address[i] & 0x00FFFFFF) | 0x01000000;
+                                        pci_write_config_dword(dev,
+                                                PCI_BASE_ADDRESS_0+(i*0x4),
+                                               dev->base_address[i] );
+                                }
+                        }
+#if 0
+                        /*
+                         * If we have residual data and if it knows about this
+                         * device ask it what the irq is.
+                         *  -- Cort
+                         */
+                        ppcd = residual_find_device_id( ~0L, dev->device,
+                                                        -1,-1,-1, 0);
+#endif
+		}
+	}
+}
+
+decl_config_access_method(indirect);
+
+__initfunc(
+void
+prep_setup_pci_ptrs(void))
+{
+	PPC_DEVICE *hostbridge;
+
+        printk("PReP architecture\n");
+        if ( _prep_type == _PREP_Radstone )
+        {
+		pci_config_address = (unsigned *)0x80000cf8;
+		pci_config_data = (char *)0x80000cfc;
+                set_config_access_method(indirect);		
+        }
+        else
+        {
+                hostbridge = residual_find_device(PROCESSORDEVICE, NULL,
+		       BridgeController, PCIBridge, -1, 0);
+                if (hostbridge &&
+                    hostbridge->DeviceId.Interface == PCIBridgeIndirect) {
+                        PnP_TAG_PACKET * pkt;
+                        set_config_access_method(indirect);
+                        pkt = PnP_find_large_vendor_packet(
+				res->DevicePnPHeap+hostbridge->AllocatedOffset,
+				3, 0);
+                        if(pkt)
+			{
+#define p pkt->L4_Pack.L4_Data.L4_PPCPack
+                                pci_config_address= (unsigned *)ld_le32((unsigned *) p.PPCData);
+				pci_config_data= (unsigned char *)ld_le32((unsigned *) (p.PPCData+8));
+                        }
+			else
+			{
+                                pci_config_address= (unsigned *) 0x80000cf8;
+                                pci_config_data= (unsigned char *) 0x80000cfc;
+                        }
+                }
+		else
+		{
+                        set_config_access_method(prep);
+                }
+
+        }
+
+	ppc_md.pcibios_fixup = prep_pcibios_fixup;
 }
 
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
--- v2.2.7/linux/arch/ppc/kernel/prep_setup.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/prep_setup.c	Thu Apr 29 12:39:01 1999
@@ -30,6 +30,9 @@
 #include <linux/blk.h>
 #include <linux/ioport.h>
 #include <linux/console.h>
+#include <linux/timex.h>
+#include <linux/pci.h>
+#include <linux/openpic.h>
 
 #include <asm/mmu.h>
 #include <asm/processor.h>
@@ -38,12 +41,63 @@
 #include <asm/pgtable.h>
 #include <asm/ide.h>
 #include <asm/cache.h>
+#include <asm/dma.h>
+#include <asm/machdep.h>
+#include <asm/mk48t59.h>
+#include <asm/prep_nvram.h>
+
+#include "time.h"
+#include "local_irq.h"
+#include "i8259.h"
+#include "open_pic.h"
 
 #if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE)
 #include <../drivers/sound/sound_config.h>
 #include <../drivers/sound/dev_table.h>
 #endif
 
+unsigned char ucSystemType;
+unsigned char ucBoardRev;
+unsigned char ucBoardRevMaj, ucBoardRevMin;
+
+extern unsigned long mc146818_get_rtc_time(void);
+extern int mc146818_set_rtc_time(unsigned long nowtime);
+extern unsigned long mk48t59_get_rtc_time(void);
+extern int mk48t59_set_rtc_time(unsigned long nowtime);
+
+extern unsigned char prep_nvram_read_val(int addr);
+extern void prep_nvram_write_val(int addr,
+				 unsigned char val);
+extern unsigned char rs_nvram_read_val(int addr);
+extern void rs_nvram_write_val(int addr,
+				 unsigned char val);
+
+extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
+extern int pckbd_getkeycode(unsigned int scancode);
+extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+			   char raw_mode);
+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];
+
+extern void prep_setup_pci_ptrs(void);
+
+/* these need to be here since PReP uses them for OpenPIC support */
+/* Maybe move these to a 'openpic_irq.c' file instead? --Troy */
+extern void chrp_mask_and_ack_irq(unsigned int irq_nr);
+extern void chrp_mask_irq(unsigned int irq_nr);
+extern void chrp_unmask_irq(unsigned int irq_nr);
+extern void chrp_do_IRQ(struct pt_regs *regs, int cpu, int isfake);
+extern volatile unsigned char *chrp_int_ack_special;
+
+extern char saved_command_line[256];
+
+int _prep_type;
+
+#define cached_21	(((char *)(ppc_cached_irq_mask))[3])
+#define cached_A1	(((char *)(ppc_cached_irq_mask))[2])
+
 /* for the mac fs */
 kdev_t boot_dev;
 /* used in nasty hack for sound - see prep_setup_arch() -- Cort */
@@ -60,6 +114,9 @@
 extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
 extern int rd_image_start;	/* starting block # of image */
 #endif
+#ifdef CONFIG_VGA_CONSOLE
+unsigned long vgacon_remap_base;
+#endif
 
 __prep
 int
@@ -177,6 +234,13 @@
 	outb(reg, SIO_CONFIG_RD);
 	outb(reg, SIO_CONFIG_RD);	/* Have to write twice to change! */
 
+	/*
+	 * We need to set up the NvRAM access routines early as prep_init
+	 * has yet to be called
+	 */
+	ppc_md.nvram_read_val = prep_nvram_read_val;
+	ppc_md.nvram_write_val = prep_nvram_write_val;
+
 	/* we should determine this according to what we find! -- Cort */
 	switch ( _prep_type )
 	{
@@ -210,9 +274,38 @@
 		ucBoardRev=inb(0x854);
 		ucBoardRevMaj=ucBoardRev>>5;
 		ucBoardRevMin=ucBoardRev&0x1f;
+
+		/*
+		 * Most Radstone boards have memory mapped NvRAM
+		 */
+		if((ucSystemType==RS_SYS_TYPE_PPC1) && (ucBoardRevMaj<5))
+		{
+			ppc_md.nvram_read_val = prep_nvram_read_val;
+			ppc_md.nvram_write_val = prep_nvram_write_val;
+		}
+		else
+		{
+			ppc_md.nvram_read_val = rs_nvram_read_val;
+			ppc_md.nvram_write_val = rs_nvram_write_val;
+		}
 		break;
 	}
 
+      /* Read in NVRAM data */ 
+      init_prep_nvram();
+       
+      /* if no bootargs, look in NVRAM */
+      if ( cmd_line[0] == '\0' ) {
+              char *bootargs;
+              bootargs = prep_nvram_get_var("bootargs");
+              if (bootargs != NULL) {
+                      strcpy(cmd_line, bootargs);
+
+                      /* again.. */
+                      strcpy(saved_command_line, cmd_line);
+              }
+      }
+
 	printk("Boot arguments: %s\n", cmd_line);
 	
 #ifdef CONFIG_SOUND_CS4232
@@ -263,11 +356,362 @@
 	request_region(0xc0,0x20,"dma2");
 
 #ifdef CONFIG_VGA_CONSOLE
+	/* remap the VGA memory */
+	vgacon_remap_base = 0xf0000000;
+	/*vgacon_remap_base = ioremap(0xc0000000, 0xba000);*/
         conswitchp = &vga_con;
 #endif
 }
 
-__initfunc(void prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq))
+/*
+ * Determine the decrementer frequency from the residual data
+ * This allows for a faster boot as we do not need to calibrate the
+ * decrementer against another clock. This is important for embedded systems.
+ */
+__initfunc(void prep_res_calibrate_decr(void))
+{
+	int freq, divisor;
+
+	freq = res->VitalProductData.ProcessorBusHz;
+	divisor = 4;
+	printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
+	decrementer_count = freq / HZ / divisor;
+	count_period_num = divisor;
+	count_period_den = freq / 1000000;
+}
+
+/*
+ * 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;
+
+__initfunc(void
+prep_calibrate_decr_handler(int            irq,
+			    void           *dev,
+			    struct pt_regs *regs))
+{
+	unsigned long 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 = %lu/%lu (%luMHz)\n",
+		       freq, divisor,t2>>20);
+		decrementer_count = freq / HZ / divisor;
+		count_period_num = divisor;
+		count_period_den = freq / 1000000;
+		*done_ptr = 1;
+	}
+}
+
+__initfunc(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);
+}
+
+
+/* We use the NVRAM RTC to time a second to calibrate the decrementer. */
+__initfunc(void mk48t59_calibrate_decr(void))
+{
+	unsigned long freq, divisor;
+	unsigned long t1, t2;
+        unsigned char save_control;
+        long i;
+	unsigned char sec;
+ 
+		
+	/* Make sure the time is not stopped. */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);
+	
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+			     (save_control & (~MK48T59_RTC_CB_STOP)));
+
+	/* Now make sure the read bit is off so the value will change. */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+	save_control &= ~MK48T59_RTC_CA_READ;
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+
+	/* Read the seconds value to see when it changes. */
+	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+	for (i = 0 ; i < 1000000 ; i++)	{ /* may take up to 1 second... */
+	   if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
+	      break;
+	   }
+	}
+	t1 = get_dec();
+
+	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+	for (i = 0 ; i < 1000000 ; i++)	{ /* Should take up 1 second... */
+	   if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
+	      break;
+	   }
+	}
+
+	t2 = t1 - get_dec();
+
+	freq = t2 * 60;	/* try to make freq/1e6 an integer */
+	divisor = 60;
+	printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
+	       freq, divisor,t2>>20);
+	decrementer_count = freq / HZ / divisor;
+	count_period_num = divisor;
+	count_period_den = freq / 1000000;
+}
+
+void
+prep_restart(char *cmd)
+{
+        unsigned long i = 10000;
+
+
+        _disable_interrupts();
+
+        /* set exception prefix high - to the prom */
+        _nmask_and_or_msr(0, 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");
+}
+
+/*
+ * This function will restart a board regardless of port 92 functionality
+ */
+void
+prep_direct_restart(char *cmd)
+{
+	u32 jumpaddr=0xfff00100;
+	u32 defaultmsr=MSR_IP;
+
+	/*
+	 * This will ALWAYS work regardless of port 92
+	 * functionality
+	 */
+	_disable_interrupts();
+
+	__asm__ __volatile__("\n\
+	mtspr   26, %1  /* SRR0 */
+	mtspr   27, %0  /* SRR1 */
+	rfi"
+	:
+	: "r" (defaultmsr), "r" (jumpaddr));
+	/*
+	 * Not reached
+	 */
+}
+
+void
+prep_halt(void)
+{
+        unsigned long flags;
+	_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 ( 1 ) ;
+	/*
+	 * Not reached
+	 */
+}
+
+void
+prep_power_off(void)
+{
+	prep_halt();
+}
+
+int prep_setup_residual(char *buffer)
+{
+        int len = 0;
+
+
+	/* PREP's without residual data will give incorrect values here */
+	len += sprintf(len+buffer, "clock\t\t: ");
+	if ( res->ResidualLength )
+		len += sprintf(len+buffer, "%ldMHz\n",
+		       (res->VitalProductData.ProcessorHz > 1024) ?
+		       res->VitalProductData.ProcessorHz>>20 :
+		       res->VitalProductData.ProcessorHz);
+	else
+		len += sprintf(len+buffer, "???\n");
+
+	return len;
+}
+
+u_int
+prep_irq_cannonicalize(u_int irq)
+{
+	if (irq == 2)
+	{
+		return 9;
+	}
+	else
+	{
+		return irq;
+	}
+}
+
+void                           
+prep_do_IRQ(struct pt_regs *regs, int cpu, int isfake)
+{
+        int irq;
+	
+        /*
+         * Perform an interrupt acknowledge cycle on controller 1
+         */                                                             
+        outb(0x0C, 0x20);
+        irq = inb(0x20) & 7;                                   
+        if (irq == 2)                                                     
+        {                                                                   
+                /*                                     
+                 * Interrupt is cascaded so perform interrupt
+                 * acknowledge on controller 2
+                 */
+                outb(0x0C, 0xA0);                      
+                irq = (inb(0xA0) & 7) + 8;
+        }
+        else if (irq==7)                                
+        {
+                /*                               
+                 * This may be a spurious interrupt
+                 *                         
+                 * Read the interrupt status register. If the most
+                 * significant bit is not set then there is no valid
+		 * interrupt
+		 */
+		outb(0x0b, 0x20);
+		 
+		if(~inb(0x20)&0x80)
+		{
+			printk(KERN_DEBUG "Bogus interrupt from PC = %lx\n",
+			       regs->nip);
+                        ppc_spurious_interrupts++;
+                        return;
+                }
+	}
+        ppc_irq_dispatch_handler( regs, irq );
+}		
+
+__initfunc(void
+prep_init_IRQ(void))
+{
+	int i;
+
+        for ( i = 0 ; i < 16  ; i++ )
+                irq_desc[i].ctl = &i8259_pic;
+        i8259_init();
+}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+/*
+ * IDE stuff.
+ */
+void
+prep_ide_insw(ide_ioreg_t port, void *buf, int ns)
+{
+	_insw((unsigned short *)((port)+_IO_BASE), buf, ns);
+}
+
+void
+prep_ide_outsw(ide_ioreg_t port, void *buf, int ns)
+{
+	_outsw((unsigned short *)((port)+_IO_BASE), buf, ns);
+}
+
+int
+prep_ide_default_irq(ide_ioreg_t base)
+{
+	switch (base) {
+		case 0x1f0: return 13;
+		case 0x170: return 13;
+		case 0x1e8: return 11;
+		case 0x168: return 10;
+		default:
+                        return 0;
+	}
+}
+
+ide_ioreg_t
+prep_ide_default_io_base(int index)
+{
+	switch (index) {
+		case 0: return 0x1f0;
+		case 1: return 0x170;
+		case 2: return 0x1e8;
+		case 3: return 0x168;
+		default:
+                        return 0;
+	}
+}
+
+int
+prep_ide_check_region(ide_ioreg_t from, unsigned int extent)
+{
+        return check_region(from, extent);
+}
+
+void
+prep_ide_request_region(ide_ioreg_t from,
+			unsigned int extent,
+			const char *name)
+{
+        request_region(from, extent, name);
+}
+
+void
+prep_ide_release_region(ide_ioreg_t from,
+			unsigned int extent)
+{
+        release_region(from, extent);
+}
+
+void
+prep_ide_fix_driveid(struct hd_driveid *id)
+{
+}
+
+__initfunc(void
+prep_ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq))
 {
 	ide_ioreg_t port = base;
 	int i = 8;
@@ -277,6 +721,158 @@
 	*p++ = base + 0x206;
 	if (irq != NULL)
 		*irq = 0;
+}
+#endif
+
+__initfunc(void
+prep_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	  unsigned long r6, unsigned long r7))
+{
+	int tmp;
+
+	/* make a copy of residual data */
+	if ( r3 )
+	{
+		memcpy((void *)res,(void *)(r3+KERNELBASE),
+		       sizeof(RESIDUAL));
+	}
+
+	isa_io_base = PREP_ISA_IO_BASE;
+	isa_mem_base = PREP_ISA_MEM_BASE;
+	pci_dram_offset = PREP_PCI_DRAM_OFFSET;
+	ISA_DMA_THRESHOLD = 0x00ffffff;
+	DMA_MODE_READ = 0x44;
+	DMA_MODE_WRITE = 0x48;
+
+	/* figure out what kind of prep workstation we are */
+	if ( res->ResidualLength != 0 )
+	{
+		if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
+			_prep_type = _PREP_IBM;
+                else if (!strncmp(res->VitalProductData.PrintableModel,
+                                  "Radstone",8))
+                {
+                        extern char *Motherboard_map_name;
+
+                        _prep_type = _PREP_Radstone;
+                        Motherboard_map_name=
+                                res->VitalProductData.PrintableModel;
+                }
+		else
+			_prep_type = _PREP_Motorola;
+	}
+	else /* assume motorola if no residual (netboot?) */
+	{
+		_prep_type = _PREP_Motorola;
+	}
+
+	prep_setup_pci_ptrs();
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* take care of initrd if we have one */
+	if ( r4 )
+	{
+		initrd_start = r4 + KERNELBASE;
+		initrd_end = r5 + KERNELBASE;
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+	/* take care of cmd line */
+	if ( r6  && (((char *) r6) != '\0'))
+	{
+		*(char *)(r7+KERNELBASE) = 0;
+		strcpy(cmd_line, (char *)(r6+KERNELBASE));
+	}
+
+	if ( is_powerplus ) {	/* look for a Raven OpenPIC */
+		pcibios_read_config_dword(0, 0, 0, &tmp);
+		if (tmp == PCI_VENDOR_ID_MOTOROLA + (PCI_DEVICE_ID_MOTOROLA_RAVEN<<16)) {
+			pcibios_read_config_dword(0, 0, PCI_BASE_ADDRESS_1, &tmp);
+			if (tmp) {
+				OpenPIC=(volatile struct OpenPIC *)
+					(tmp + isa_mem_base);
+				/* printk("OpenPIC found at %p: \n", OpenPIC);*/
+			}
+		} else {
+			printk ("prep_init: WARNING: can't find an OpenPIC on what looks like a PowerPlus board\n");
+		}
+	}
+
+
+	ppc_md.setup_arch     = prep_setup_arch;
+	ppc_md.setup_residual = prep_setup_residual;
+	ppc_md.get_cpuinfo    = prep_get_cpuinfo;
+	ppc_md.irq_cannonicalize = prep_irq_cannonicalize;
+	ppc_md.init_IRQ       = prep_init_IRQ;
+	ppc_md.do_IRQ         = prep_do_IRQ;
+	ppc_md.init           = NULL;
+
+	ppc_md.restart        = prep_restart;
+	ppc_md.power_off      = prep_power_off;
+	ppc_md.halt           = prep_halt;
+
+	ppc_md.time_init      = NULL;
+	if (_prep_type == _PREP_Radstone) {
+		/*
+		 * We require a direct restart as port 92 does not work on
+		 * all Radstone boards
+		 */
+		ppc_md.restart        = prep_direct_restart;
+		/*
+		 * The RTC device used varies according to board type
+		 */
+		if(((ucSystemType==RS_SYS_TYPE_PPC1) && (ucBoardRevMaj>=5)) ||
+		   (ucSystemType==RS_SYS_TYPE_PPC1a))
+		{
+			ppc_md.set_rtc_time   = mk48t59_set_rtc_time;
+			ppc_md.get_rtc_time   = mk48t59_get_rtc_time;
+		}
+		else
+		{
+			ppc_md.set_rtc_time   = mc146818_set_rtc_time;
+			ppc_md.get_rtc_time   = mc146818_get_rtc_time;
+		}
+		/*
+		 * Determine the decrementer rate from the residual data
+		 */
+		ppc_md.calibrate_decr = prep_res_calibrate_decr;
+	}
+	else if (_prep_type == _PREP_IBM) {
+		ppc_md.set_rtc_time   = mc146818_set_rtc_time;
+		ppc_md.get_rtc_time   = mc146818_get_rtc_time;
+		ppc_md.calibrate_decr = prep_calibrate_decr;
+	}
+	else {
+		ppc_md.set_rtc_time   = mk48t59_set_rtc_time;
+		ppc_md.get_rtc_time   = mk48t59_get_rtc_time;
+		ppc_md.calibrate_decr = mk48t59_calibrate_decr;
+	}
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+        ppc_ide_md.insw = prep_ide_insw;
+        ppc_ide_md.outsw = prep_ide_outsw;
+        ppc_ide_md.default_irq = prep_ide_default_irq;
+        ppc_ide_md.default_io_base = prep_ide_default_io_base;
+        ppc_ide_md.check_region = prep_ide_check_region;
+        ppc_ide_md.request_region = prep_ide_request_region;
+        ppc_ide_md.release_region = prep_ide_release_region;
+        ppc_ide_md.fix_driveid = prep_ide_fix_driveid;
+        ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports;
+
+        ppc_ide_md.io_base = _IO_BASE;
+#endif		
+
+#ifdef CONFIG_VT
+	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
+	ppc_md.kbd_getkeycode    = pckbd_getkeycode;
+	ppc_md.kbd_translate     = pckbd_translate;
+	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
+	ppc_md.kbd_leds          = pckbd_leds;
+	ppc_md.kbd_init_hw       = pckbd_init_hw;
+#ifdef CONFIG_MAGIC_SYSRQ
+	ppc_md.kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
+#endif
+#endif
 }
 
 #ifdef CONFIG_SOUND_MODULE
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/prep_time.c linux/arch/ppc/kernel/prep_time.c
--- v2.2.7/linux/arch/ppc/kernel/prep_time.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/prep_time.c	Thu Apr 29 12:39:01 1999
@@ -22,7 +22,9 @@
 #include <asm/segment.h>
 #include <asm/io.h>
 #include <asm/processor.h>
-#include <asm/nvram.h>
+#include <asm/machdep.h>
+#include <asm/prep_nvram.h>
+#include <asm/mk48t59.h>
 
 #include "time.h"
 
@@ -41,133 +43,44 @@
  * is setup at boot time to use the correct addresses.
  * -- Cort
  */
-/*
- * translate from mc146818 to m48t18  addresses
- */
-unsigned int clock_transl[] __prepdata = { 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 */
-};
-
-/*
- * The following struture is used to access the MK48T18
- */
-typedef volatile struct _MK48T18 {
-	unsigned char	ucNvRAM[0x3ff8]; /* NvRAM locations */
-	unsigned char	ucControl;
-	unsigned char	ucSecond;	/* 0-59 */
-	unsigned char	ucMinute;	/* 0-59 */
-	unsigned char	ucHour;		/* 0-23 */
-	unsigned char	ucDay;		/* 1-7 */
-	unsigned char	ucDate;		/* 1-31 */
-	unsigned char	ucMonth;	/* 1-12 */
-	unsigned char	ucYear;		/* 0-99 */
-} MK48T18, *PMK48T18;
-
-/*
- * The control register contains a 5 bit calibration value plus sign
- * and read/write enable bits
- */
-#define MK48T18_CTRL_CAL_MASK	0x1f
-#define MK48T18_CTRL_CAL_SIGN	0x20
-#define MK48T18_CTRL_READ	0x40
-#define MK48T18_CTRL_WRITE	0x80
-/*
- * The STOP bit is the most significant bit of the seconds location
- */
-#define MK48T18_SEC_MASK	0x7f
-#define MK48T18_SEC_STOP	0x80
-/*
- * The day location also contains the frequency test bit which should
- * be zero for normal operation
- */
-#define MK48T18_DAY_MASK	0x07
-#define MK48T18_DAY_FT		0x40
-
-__prep
-int prep_cmos_clock_read(int addr)
-{
-	if ( _prep_type == _PREP_IBM )
-		return CMOS_READ(addr);
-	else if ( _prep_type == _PREP_Motorola )
-	{
-		outb(clock_transl[addr]>>8, NVRAM_AS1);
-		outb(clock_transl[addr], NVRAM_AS0);
-		return (inb(NVRAM_DATA));
-	}
-        else if ( _prep_type == _PREP_Radstone )
-                return CMOS_READ(addr);
-
-	printk("Unknown machine in prep_cmos_clock_read()!\n");
-	return -1;
-}
-
-__prep
-void prep_cmos_clock_write(unsigned long val, int addr)
-{
-	if ( _prep_type == _PREP_IBM )
-	{
-		CMOS_WRITE(val,addr);
-		return;
-	}
-	else if ( _prep_type == _PREP_Motorola )
-	{
-		outb(clock_transl[addr]>>8, NVRAM_AS1);
-		outb(clock_transl[addr], NVRAM_AS0);
-		outb(val,NVRAM_DATA);
-		return;
-	}
-        else if ( _prep_type == _PREP_Radstone )
-        {
-                CMOS_WRITE(val,addr);
-                return;
-        }
-
-	printk("Unknown machine in prep_cmos_clock_write()!\n");
-}
 
 /*
  * Set the hardware clock. -- Cort
  */
 __prep
-int prep_set_rtc_time(unsigned long nowtime)
+int mc146818_set_rtc_time(unsigned long nowtime)
 {
 	unsigned char save_control, save_freq_select;
 	struct rtc_time tm;
 
 	to_tm(nowtime, &tm);
 
-	save_control = prep_cmos_clock_read(RTC_CONTROL); /* tell the clock it's being set */
-
-	prep_cmos_clock_write((save_control|RTC_SET), RTC_CONTROL);
-
-	save_freq_select = prep_cmos_clock_read(RTC_FREQ_SELECT); /* stop and reset prescaler */
+	/* tell the clock it's being set */
+	save_control = CMOS_READ(RTC_CONTROL);
 	
-	prep_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
-        tm.tm_year -= 1900;
+	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+	
+	/* stop and reset prescaler */
+	save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
+	
+	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+	
+        tm.tm_year = (tm.tm_year - 1900) % 100;
 	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
 		BIN_TO_BCD(tm.tm_sec);
 		BIN_TO_BCD(tm.tm_min);
 		BIN_TO_BCD(tm.tm_hour);
 		BIN_TO_BCD(tm.tm_mon);
-		BIN_TO_BCD(tm.tm_wday);
 		BIN_TO_BCD(tm.tm_mday);
 		BIN_TO_BCD(tm.tm_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_wday+1,RTC_DAY_OF_WEEK);
-	prep_cmos_clock_write(tm.tm_mday,RTC_DAY_OF_MONTH);
-	prep_cmos_clock_write(tm.tm_year,RTC_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);
+	
 	/* The following flags have to be released exactly in this order,
 	 * otherwise the DS12887 (popular MC146818A clone with integrated
 	 * battery and quartz) will not reset the oscillator and will not
@@ -175,52 +88,14 @@
 	 * the Dallas Semiconductor data sheets, but who believes data
 	 * sheets anyway ...                           -- Markus Kuhn
 	 */
-	prep_cmos_clock_write(save_control, RTC_CONTROL);
-	prep_cmos_clock_write(save_freq_select, RTC_FREQ_SELECT);
+	CMOS_WRITE(save_control,     RTC_CONTROL);
+	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
 
-	/*
-	 * Radstone Technology PPC1a boards use an MK48T18 device
-	 * as the "master" RTC but also have a DS1287 equivalent incorporated
-	 * into the PCI-ISA bridge device. The DS1287 is initialised by the boot
-	 * firmware to reflect the value held in the MK48T18 and thus the
-	 * time may be read from this device both here and in the rtc driver.
-	 * Whenever we set the time, however, if it is to be preserved across
-	 * boots we must also update the "master" RTC.
-	 */
-	if((_prep_type==_PREP_Radstone) && (ucSystemType==RS_SYS_TYPE_PPC1a))
-	{
-		PMK48T18 pMk48t18=(PMK48T18)(_ISA_MEM_BASE+0x00800000);
-
-		/*
-		 * Set the write enable bit
-		 */
-		pMk48t18->ucControl|=MK48T18_CTRL_WRITE;
-		eieio();
-		/*
-		 * Update the clock
-		 */
-		pMk48t18->ucSecond=tm.tm_sec;
-		pMk48t18->ucMinute=tm.tm_min;
-		pMk48t18->ucHour=tm.tm_hour;
-		pMk48t18->ucMonth=tm.tm_mon;
-		pMk48t18->ucDay=tm.tm_wday+1;
-		pMk48t18->ucDate=tm.tm_mday;
-		pMk48t18->ucYear=tm.tm_year;
-
-		eieio();
-		/*
-		 * Clear the write enable bit
-		 */
-		pMk48t18->ucControl&=~MK48T18_CTRL_WRITE;
-	}
-
-	if ( (time_state == TIME_ERROR) || (time_state == TIME_BAD) )
-		time_state = TIME_OK;
 	return 0;
 }
 
 __prep
-unsigned long prep_get_rtc_time(void)
+unsigned long mc146818_get_rtc_time(void)
 {
 	unsigned int year, mon, day, hour, min, sec;
 	int i;
@@ -232,29 +107,123 @@
 	 */
 	/* read RTC exactly on falling edge of update flag */
 	for (i = 0 ; i < 1000000 ; i++)	/* may take up to 1 second... */
-		if (prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP)
+		if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
 			break;
 	for (i = 0 ; i < 1000000 ; i++)	/* must try at least 2.228 ms */
-		if (!(prep_cmos_clock_read(RTC_FREQ_SELECT) & RTC_UIP))
+		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
 			break;
 	do { /* Isn't this overkill ? UIP above should guarantee consistency */
-		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);
-	    BCD_TO_BIN(hour);
-	    BCD_TO_BIN(day);
-	    BCD_TO_BIN(mon);
-	    BCD_TO_BIN(year);
-	  }
+		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)
+	{
+		BCD_TO_BIN(sec);
+		BCD_TO_BIN(min);
+		BCD_TO_BIN(hour);
+		BCD_TO_BIN(day);
+		BCD_TO_BIN(mon);
+		BCD_TO_BIN(year);
+	}
 	if ((year += 1900) < 1970)
 		year += 100;
+	return mktime(year, mon, day, hour, min, sec);
+}
+
+__prep
+int mk48t59_set_rtc_time(unsigned long nowtime)
+{
+	unsigned char save_control;
+	struct rtc_time tm;
+
+
+	to_tm(nowtime, &tm);
+
+	/* tell the clock it's being written */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+	
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+			     (save_control | MK48T59_RTC_CA_WRITE));
+
+        tm.tm_year = (tm.tm_year - 1900) % 100;
+	BIN_TO_BCD(tm.tm_sec);
+	BIN_TO_BCD(tm.tm_min);
+	BIN_TO_BCD(tm.tm_hour);
+	BIN_TO_BCD(tm.tm_mon);
+	BIN_TO_BCD(tm.tm_mday);
+	BIN_TO_BCD(tm.tm_year);
+
+	ppc_md.nvram_write_val(MK48T59_RTC_SECONDS,      tm.tm_sec);
+	ppc_md.nvram_write_val(MK48T59_RTC_MINUTES,      tm.tm_min);
+	ppc_md.nvram_write_val(MK48T59_RTC_HOURS,        tm.tm_hour);
+	ppc_md.nvram_write_val(MK48T59_RTC_MONTH,        tm.tm_mon);
+	ppc_md.nvram_write_val(MK48T59_RTC_DAY_OF_MONTH, tm.tm_mday);
+	ppc_md.nvram_write_val(MK48T59_RTC_YEAR,         tm.tm_year);
+	
+	/* Turn off the write bit. */
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+	return 0;
+}
+
+__prep
+unsigned long mk48t59_get_rtc_time(void)
+{
+	unsigned char save_control;
+	unsigned int year, mon, day, hour, min, sec;
+	int i;
+
+	/* Make sure the time is not stopped. */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLB);
+	
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+			     (save_control & (~MK48T59_RTC_CB_STOP)));
+
+	/* Now make sure the read bit is off so the value will change. */
+	save_control = ppc_md.nvram_read_val(MK48T59_RTC_CONTROLA);
+	save_control &= ~MK48T59_RTC_CA_READ;
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+	/* Read the seconds value to see when it changes. */
+	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+		
+	/* Wait until the seconds value changes, then read the value. */
+	for (i = 0 ; i < 1000000 ; i++)	{ /* may take up to 1 second... */
+	   if (ppc_md.nvram_read_val(MK48T59_RTC_SECONDS) != sec) {
+	      break;
+	   }
+	}
+
+	/* Set the register to read the value. */
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA,
+			     (save_control | MK48T59_RTC_CA_READ));
+
+	sec = ppc_md.nvram_read_val(MK48T59_RTC_SECONDS);
+	min = ppc_md.nvram_read_val(MK48T59_RTC_MINUTES);
+	hour = ppc_md.nvram_read_val(MK48T59_RTC_HOURS);
+	day = ppc_md.nvram_read_val(MK48T59_RTC_DAY_OF_MONTH);
+	mon = ppc_md.nvram_read_val(MK48T59_RTC_MONTH);
+	year = ppc_md.nvram_read_val(MK48T59_RTC_YEAR);
+
+	/* Let the time values change again. */
+	ppc_md.nvram_write_val(MK48T59_RTC_CONTROLA, save_control);
+
+	BCD_TO_BIN(sec);
+	BCD_TO_BIN(min);
+	BCD_TO_BIN(hour);
+	BCD_TO_BIN(day);
+	BCD_TO_BIN(mon);
+	BCD_TO_BIN(year);
+
+	year = year + 1900;
+	if (year < 1970) {
+		year += 100;
+	}
+
 	return mktime(year, mon, day, hour, min, sec);
 }
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- v2.2.7/linux/arch/ppc/kernel/process.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/process.c	Thu Apr 29 12:39:01 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: process.c,v 1.75 1999/02/12 07:06:29 cort Exp $
+ * $Id: process.c,v 1.78 1999/04/07 07:27:00 paulus Exp $
  *
  *  linux/arch/ppc/kernel/process.c
  *
@@ -77,17 +77,25 @@
 int
 dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs)
 {
-#ifdef __SMP__
-	if ( regs->msr & MSR_FP )
-		smp_giveup_fpu(current);
-#else
-	if (last_task_used_math == current)
-		giveup_fpu();
-#endif	
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
 	memcpy(fpregs, &current->tss.fpr[0], sizeof(*fpregs));
 	return 1;
 }
 
+void
+enable_kernel_fp(void)
+{
+#ifdef __SMP__
+	if (current->tss.regs && (current->tss.regs->msr & MSR_FP))
+		giveup_fpu(current);
+	else
+		giveup_fpu(NULL);	/* just enables FP for kernel */
+#else
+	giveup_fpu(last_task_used_math);
+#endif /* __SMP__ */
+}
+
 /* check to make sure the kernel stack is healthy */
 int check_stack(struct task_struct *tsk)
 {
@@ -176,8 +184,8 @@
 	 * reload its fp regs.
 	 *  -- Cort
 	 */
-	if ( prev->tss.regs->msr & MSR_FP )
-		smp_giveup_fpu(prev);
+	if (prev->tss.regs && (prev->tss.regs->msr & MSR_FP))
+		giveup_fpu(prev);
 
 	prev->last_processor = prev->processor;
 	current_set[smp_processor_id()] = new;
@@ -237,7 +245,12 @@
 
 	printk("Instruction DUMP:");
 	for(i = -3; i < 6; i++)
-		printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>');
+	{
+		unsigned long p;
+		if (__get_user( p, &pc[i] ))
+			break;
+		printk("%c%08lx%c",i?' ':'<',p,i?' ':'>');
+	}
 	printk("\n");
 }
 
@@ -290,13 +303,8 @@
 	 * copy fpu info - assume lazy fpu switch now always
 	 *  -- Cort
 	 */
-#ifdef __SMP__
-	if ( regs->msr & MSR_FP )
-		smp_giveup_fpu(current);
-#else	
-	if ( last_task_used_math == current )
-		giveup_fpu();
-#endif	  
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
 
 	memcpy(&p->tss.fpr, &current->tss.fpr, sizeof(p->tss.fpr));
 	p->tss.fpscr = current->tss.fpscr;
@@ -424,13 +432,8 @@
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename))
 		goto out;
-#ifdef __SMP__	  
-	if ( regs->msr & MSR_FP )
-		smp_giveup_fpu(current);
-#else	  
-	if ( last_task_used_math == current )
-		giveup_fpu();
-#endif	
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
 	error = do_execve(filename, (char **) a1, (char **) a2, regs);
 	putname(filename);
 out:
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- v2.2.7/linux/arch/ppc/kernel/prom.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/prom.c	Thu Apr 29 12:39:01 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: prom.c,v 1.50 1999/03/16 10:40:34 cort Exp $
+ * $Id: prom.c,v 1.53 1999/04/22 22:45:42 cort Exp $
  *
  * Procedures for interfacing to the Open Firmware PROM on
  * Power Macintosh computers.
@@ -16,6 +16,7 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/version.h>
+#include <asm/spinlock.h>
 #include <asm/prom.h>
 #include <asm/page.h>
 #include <asm/processor.h>
@@ -263,9 +264,11 @@
 void
 prom_init(int r3, int r4, prom_entry pp)
 {
+#ifdef CONFIG_SMP	
 	int cpu = 0, i;
 	phandle node;
 	char type[16], *path;
+#endif	
 	unsigned long mem;
 	ihandle prom_rtas;
 	unsigned long offset = reloc_offset();
@@ -1141,7 +1144,7 @@
 	if (cp == NULL)
 		return 0;
 	while (cplen > 0) {
-		if (strcasecmp(cp, compat) == 0)
+		if (strncasecmp(cp, compat, strlen(compat)) == 0)
 			return 1;
 		l = strlen(cp) + 1;
 		cp += l;
@@ -1277,6 +1280,8 @@
 }
 #endif
 
+spinlock_t rtas_lock = SPIN_LOCK_UNLOCKED;
+
 /* this can be called after setup -- Cort */
 __openfirmware
 int
@@ -1307,7 +1312,9 @@
 	for (i = 0; i < nargs; ++i)
 		u.words[i+3] = va_arg(list, unsigned long);
 	va_end(list);
+	spin_lock(&rtas_lock);
 	enter_rtas((void *)__pa(&u));
+	spin_unlock(&rtas_lock);
 	if (nret > 1 && outputs != NULL)
 		for (i = 0; i < nret-1; ++i)
 			outputs[i] = u.words[i+nargs+4];
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/ptrace.c linux/arch/ppc/kernel/ptrace.c
--- v2.2.7/linux/arch/ppc/kernel/ptrace.c	Thu Dec 31 10:28:59 1998
+++ linux/arch/ppc/kernel/ptrace.c	Thu Apr 29 12:39:01 1999
@@ -392,14 +392,8 @@
 				tmp = get_reg(child, addr);
 			}
 			else if (addr >= PT_FPR0 && addr <= PT_FPSCR) {
-#ifdef __SMP__
-				if (child->tss.regs->msr & MSR_FP )
-					smp_giveup_fpu(child);
-#else			  
-			  /* only current can be last task to use math on SMP */
-				if (last_task_used_math == child)
-					giveup_fpu();
-#endif				
+				if (child->tss.regs->msr & MSR_FP)
+					giveup_fpu(child);
 				tmp = ((long *)child->tss.fpr)[addr - PT_FPR0];
 			}
 			else
@@ -433,13 +427,8 @@
 				goto out;
 			}
 			if (addr >= PT_FPR0 && addr < PT_FPR0 + 64) {
-#ifndef __SMP__
-				if (last_task_used_math == child)
-					giveup_fpu();
-#else	
-				if (child->tss.regs->msr & MSR_FP )
-					smp_giveup_fpu(child);
-#endif				
+				if (child->tss.regs->msr & MSR_FP)
+					giveup_fpu(child);
 				((long *)child->tss.fpr)[addr - PT_FPR0] = data;
 				ret = 0;
 				goto out;
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.2.7/linux/arch/ppc/kernel/setup.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/setup.c	Thu Apr 29 12:39:01 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: setup.c,v 1.130 1999/03/11 01:45:15 cort Exp $
+ * $Id: setup.c,v 1.132 1999/03/24 00:32:19 cort Exp $
  * Common prep/pmac/chrp boot and setup code.
  */
 
@@ -30,31 +30,62 @@
 #include <asm/8xx_immap.h>
 #endif
 #include <asm/bootx.h>
+#include <asm/machdep.h>
+#include <asm/ide.h>
 
-/* APUS defs */
-extern unsigned long m68k_machtype;
-extern int parse_bootinfo(const struct bi_record *);
-extern char _end[];
-#ifdef CONFIG_APUS
-extern struct mem_info ramdisk;
-unsigned long isa_io_base;
-unsigned long isa_mem_base;
-unsigned long pci_dram_offset;
-#endif
-/* END APUS defs */
+extern void pmac_init(unsigned long r3,
+                      unsigned long r4,
+                      unsigned long r5,
+                      unsigned long r6,
+                      unsigned long r7);
+
+extern void chrp_init(unsigned long r3,
+                      unsigned long r4,
+                      unsigned long r5,
+                      unsigned long r6,
+                      unsigned long r7);
+
+extern void prep_init(unsigned long r3,
+                      unsigned long r4,
+                      unsigned long r5,
+                      unsigned long r6,
+                      unsigned long r7);
+
+extern void mbx_init(unsigned long r3,
+		     unsigned long r4,
+		     unsigned long r5,
+		     unsigned long r6,
+		     unsigned long r7);
+
+extern void apus_init(unsigned long r3,
+                      unsigned long r4,
+                      unsigned long r5,
+                      unsigned long r6,
+                      unsigned long r7);
 
 extern boot_infos_t *boot_infos;
 extern char cmd_line[512];
 char saved_command_line[256];
 unsigned char aux_device_present;
 
-#if !defined(CONFIG_MACH_SPECIFIC)
+struct ide_machdep_calls ppc_ide_md;
+
 unsigned long ISA_DMA_THRESHOLD;
 unsigned long DMA_MODE_READ, DMA_MODE_WRITE;
-int _machine;
-/* if we have openfirmware */
-unsigned long have_of;
-#endif /* ! CONFIG_MACH_SPECIFIC */
+
+/* Temporary hacks until machdep.h is fully done. */
+int _machine = 0;
+/* do we have OF? */
+int have_of = 0;
+int is_prep = 0;
+int is_chrp = 0;
+/* For MTX/MVME boards.. with Raven/Falcon Chipset
+      Real close to CHRP, but boot like PReP (via PPCbug)
+      There's probably a nicer way to do this.. --Troy */
+int is_powerplus = 0;
+
+struct machdep_calls ppc_md;
+
 
 /* copy of the residual data */
 #ifndef CONFIG_MBX
@@ -65,15 +96,6 @@
 
 RESIDUAL *res = (RESIDUAL *)&__res;
 
-int _prep_type;
-/*
- * This is used to identify the board type from a given PReP board
- * vendor. Board revision is also made available.
- */
-unsigned char ucSystemType;
-unsigned char ucBoardRev;
-unsigned char ucBoardRevMaj, ucBoardRevMin;
-
 /*
  * Perhaps we can put the pmac screen_info[] here
  * on pmac as well so we don't need the ifdef's.
@@ -122,164 +144,28 @@
 };
 #endif /* CONFIG_MBX */
 
-/* cmd is ignored for now... */
 void machine_restart(char *cmd)
 {
-#ifndef CONFIG_MBX
-	unsigned long flags;
-	struct adb_request req;
-
-	switch(_machine)
-	{
-	case _MACH_Pmac:
-		switch (adb_hardware) {
-		case ADB_VIACUDA:
-			cuda_request(&req, NULL, 2, CUDA_PACKET,
-				     CUDA_RESET_SYSTEM);
-			for (;;)
-				cuda_poll();
-			break;
-		case ADB_VIAPMU:
-			pmu_restart();
-			break;
-		default:
-		}
-		break;
-
-	case _MACH_chrp:
-#if 0		/* RTAS doesn't seem to work on Longtrail.
-		   For now, do it the same way as the PReP. */
-	        /*err = call_rtas("system-reboot", 0, 1, NULL);
-		  printk("RTAS system-reboot returned %d\n", err);
-		  for (;;);*/
-		
-		{
-			extern unsigned int rtas_entry, rtas_data, rtas_size;
-			unsigned long status, value;
-			printk("rtas_ent`ry: %08x rtas_data: %08x rtas_size: %08x\n",
-			       rtas_entry,rtas_data,rtas_size);
-		}
-#endif
-	case _MACH_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 ( 1 ) ;
-                break;
-		/*
-		 * Not reached
-		 */
-	case _MACH_apus:
-		cli();
-
-		APUS_WRITE(APUS_REG_LOCK, 
-			   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK2);
-		APUS_WRITE(APUS_REG_LOCK, 
-			   REGLOCK_BLACKMAGICK1|REGLOCK_BLACKMAGICK3);
-		APUS_WRITE(APUS_REG_LOCK, 
-			   REGLOCK_BLACKMAGICK2|REGLOCK_BLACKMAGICK3);
-		APUS_WRITE(APUS_REG_SHADOW, REGSHADOW_SELFRESET);
-		APUS_WRITE(APUS_REG_RESET, REGRESET_AMIGARESET);
-		for(;;);
-		break;
-	}
-#else /* CONFIG_MBX */
-        extern void __clear_msr_me(void);
-        __volatile__ unsigned char dummy;
-	
-        cli();
-        ((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr |= 0x00000080;
-        __clear_msr_me();
-        dummy = ((immap_t *)IMAP_ADDR)->im_clkrst.res[0];
- 
-	printk("Restart failed\n");
-	while(1);
-#endif /* CONFIG_MBX */
+	ppc_md.restart(cmd);
 }
-
+  
 void machine_power_off(void)
 {
-#ifndef CONFIG_MBX	
-	struct adb_request req;
-#if 0	
-	int err;
-#endif	
-
-	switch (_machine) {
-	case _MACH_Pmac:
-		switch (adb_hardware) {
-		case ADB_VIACUDA:
-			cuda_request(&req, NULL, 2, CUDA_PACKET,
-				     CUDA_POWERDOWN);
-			for (;;)
-				cuda_poll();
-			break;
-		case ADB_VIAPMU:
-			pmu_shutdown();
-			break;
-		default:
-		}
-		break;
-
-	case _MACH_chrp:
-#if 0		/* RTAS doesn't seem to work on Longtrail.
-		   For now, do it the same way as the PReP. */
-		err = call_rtas("power-off", 2, 1, NULL, 0, 0);
-		printk("RTAS system-reboot returned %d\n", err);
-		for (;;);
-#endif
-
-	case _MACH_prep:
-		machine_restart(NULL);
-	case _MACH_apus:
-		for (;;);
-	}
-	for (;;);
-#else /* CONFIG_MBX */
-	machine_halt();
-#endif /* CONFIG_MBX */
+	ppc_md.power_off();
 }
-
+  
 void machine_halt(void)
 {
-	if ( _machine == _MACH_Pmac )
-	{
-		machine_power_off();
-	}
-	else /* prep, chrp or apus */
-		machine_restart(NULL);
+	ppc_md.halt();
 }
-
+  
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 void ide_init_hwif_ports (ide_ioreg_t *p, ide_ioreg_t base, int *irq)
 {
-#if !defined(CONFIG_MBX) && !defined(CONFIG_APUS)
-	switch (_machine) {
-#if defined(CONFIG_BLK_DEV_IDE_PMAC)
-	case _MACH_Pmac:
-	  	pmac_ide_init_hwif_ports(p,base,irq);
-		break;
-#endif		
-	case _MACH_chrp:
-		chrp_ide_init_hwif_ports(p,base,irq);
-		break;
-	case _MACH_prep:
-		prep_ide_init_hwif_ports(p,base,irq);
-		break;
+	if (ppc_ide_md.ide_init_hwif != NULL) {
+		ppc_ide_md.ide_init_hwif(p, base, irq);
 	}
-#endif
-#if defined(CONFIG_MBX)
-	mbx_ide_init_hwif_ports(p,base,irq);
-#endif	
 }
-EXPORT_SYMBOL(ide_init_hwif_ports);
 #endif
 
 unsigned long cpu_temp(void)
@@ -313,10 +199,6 @@
 
 int get_cpuinfo(char *buffer)
 {
-	extern int pmac_get_cpuinfo(char *);
-	extern int chrp_get_cpuinfo(char *);	
-	extern int prep_get_cpuinfo(char *);
-	extern int apus_get_cpuinfo(char *);
 	unsigned long len = 0;
 	unsigned long bogosum = 0;
 	unsigned long i;
@@ -380,7 +262,6 @@
 			break;
 		}
 		
-#ifndef CONFIG_MBX
 		/*
 		 * Assume here that all clock rates are the same in a
 		 * smp system.  -- Cort
@@ -397,33 +278,11 @@
 			len += sprintf(len+buffer, "clock\t\t: %dMHz\n",
 				       *fp / 1000000);
 		}
-		
-		/* PREP's without residual data for some reason will give
-		   incorrect values here */
-		if ( is_prep )
-		{
-			len += sprintf(len+buffer, "clock\t\t: ");
-			if ( res->ResidualLength )
-				len += sprintf(len+buffer, "%ldMHz\n",
-				       (res->VitalProductData.ProcessorHz > 1024) ?
-				       res->VitalProductData.ProcessorHz>>20 :
-				       res->VitalProductData.ProcessorHz);
-			else
-				len += sprintf(len+buffer, "???\n");
-		}
-#else /* CONFIG_MBX */
+
+		if (ppc_md.setup_residual != NULL)
 		{
-			bd_t	*bp;
-			extern	RESIDUAL *res;
-			
-			bp = (bd_t *)res;
-			
-			len += sprintf(len+buffer,"clock\t\t: %dMHz\n"
-				      "bus clock\t: %dMHz\n",
-				      bp->bi_intfreq /*/ 1000000*/,
-				      bp->bi_busfreq /*/ 1000000*/);
+			len += ppc_md.setup_residual(buffer + len);
 		}
-#endif /* CONFIG_MBX */		
 		
 		len += sprintf(len+buffer, "revision\t: %ld.%ld\n",
 			       (GET_PVR & 0xff00) >> 8, GET_PVR & 0xff);
@@ -438,8 +297,8 @@
 	if ( i )
 		len += sprintf(buffer+len, "\n");
 	len += sprintf(buffer+len,"total bogomips\t: %lu.%02lu\n",
-	       (bogosum+2500)/500000,
-	       (bogosum+2500)/5000 % 100);
+		       (bogosum+2500)/500000,
+		       (bogosum+2500)/5000 % 100);
 #endif /* __SMP__ */
 
 	/*
@@ -455,27 +314,14 @@
 			       zero_cache_hits,zero_cache_calls,
 			       /* : 1 below is so we don't div by zero */
 			       (zero_cache_hits*100) /
-			            ((zero_cache_calls)?zero_cache_calls:1));
+			       ((zero_cache_calls)?zero_cache_calls:1));
 	}
 
-#ifndef CONFIG_MBX
-	switch (_machine)
+	if (ppc_md.get_cpuinfo != NULL)
 	{
-	case _MACH_Pmac:
-		len += pmac_get_cpuinfo(buffer+len);
-		break;
-	case _MACH_prep:
-		len += prep_get_cpuinfo(buffer+len);
-		break;
-	case _MACH_chrp:
-		len += chrp_get_cpuinfo(buffer+len);
-		break;
-	case _MACH_apus:
-		/* Not much point in printing m68k info when it is not
-                   used. */
-		break;
+		len += ppc_md.get_cpuinfo(buffer+len);
 	}
-#endif /* ndef CONFIG_MBX */	
+
 	return len;
 }
 
@@ -487,25 +333,22 @@
 identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
 		 unsigned long r6, unsigned long r7)
 {
-	extern void setup_pci_ptrs(void);
 	
 #ifdef __SMP__
 	if ( first_cpu_booted ) return 0;
 #endif /* __SMP__ */
 	
-#ifndef CONFIG_MBX
 #ifndef CONFIG_MACH_SPECIFIC
 	/* boot loader will tell us if we're APUS */
 	if ( r3 == 0x61707573 )
 	{
 		_machine = _MACH_apus;
-		have_of = 0;
 		r3 = 0;
 	}
 	/* prep boot loader tells us if we're prep or not */
 	else if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) ) {
 		_machine = _MACH_prep;
-		have_of = 0;
+		is_prep = 1;
 	} else {
 		char *model;
 
@@ -516,19 +359,49 @@
 		/* ask the OF info if we're a chrp or pmac */
 		model = get_property(find_path_device("/"), "device_type", NULL);
 		if ( model && !strncmp("chrp",model,4) )
+		{
 			_machine = _MACH_chrp;
+			is_chrp = 1;
+		}
 		else
 		{
 			model = get_property(find_path_device("/"),
 					     "model", NULL);
 			if ( model && !strncmp(model, "IBM", 3))
+			{
 				_machine = _MACH_chrp;
+				is_chrp = 1;
+			}
 			else
+			{
 				_machine = _MACH_Pmac;
+				is_prep = 1;
+			}
 		}
 
 	}
-#endif /* CONFIG_MACH_SPECIFIC */		
+#else /* CONFIG_MACH_SPECIFIC */
+
+#ifdef CONFIG_PREP
+	_machine = _MACH_prep;
+	is_prep  = 1;
+#elif defined(CONFIG_CHRP)
+	_machine = _MACH_chrp;
+	is_chrp  = 1;
+	have_of  = 1;
+#elif defined(CONFIG_PMAC)
+	_machine = _MACH_Pmac;
+	have_of  = 1;
+#elif defined(CONFIG_MBX)
+	_machine = _MACH_mbx;
+#elif defined(CONFIG_FADS)
+	_machine = _MACH_fads;
+#elif defined(CONFIG_APUS)
+	_machine = _MACH_apus;
+#else
+#error "Machine not defined correctly"
+#endif /* CONFIG_APUS */
+#endif /* CONFIG_MACH_SPECIFIC */
 
 	if ( have_of )
 	{
@@ -587,138 +460,31 @@
 		cmd_line[sizeof(cmd_line) - 1] = 0;
 	}
 
-
 	switch (_machine)
 	{
 	case _MACH_Pmac:
-		setup_pci_ptrs();
-		/* isa_io_base gets set in pmac_find_bridges */
-		isa_mem_base = PMAC_ISA_MEM_BASE;
-		pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
-#if !defined(CONFIG_MACH_SPECIFIC)
-		ISA_DMA_THRESHOLD = ~0L;
-		DMA_MODE_READ = 1;
-		DMA_MODE_WRITE = 2;
-#endif /* ! CONFIG_MACH_SPECIFIC */
+                pmac_init(r3, r4, r5, r6, r7);
 		break;
 	case _MACH_prep:
-		/* make a copy of residual data */
-		if ( r3 )
-			memcpy((void *)res,(void *)(r3+KERNELBASE),
-			       sizeof(RESIDUAL));
-		isa_io_base = PREP_ISA_IO_BASE;
-		isa_mem_base = PREP_ISA_MEM_BASE;
-		pci_dram_offset = PREP_PCI_DRAM_OFFSET;
-#if !defined(CONFIG_MACH_SPECIFIC)
-		ISA_DMA_THRESHOLD = 0x00ffffff;
-		DMA_MODE_READ = 0x44;
-		DMA_MODE_WRITE = 0x48;
-#endif /* ! CONFIG_MACH_SPECIFIC */
-		/* figure out what kind of prep workstation we are */
-		if ( res->ResidualLength != 0 )
-		{
-			if ( !strncmp(res->VitalProductData.PrintableModel,"IBM",3) )
-				_prep_type = _PREP_IBM;
-			else if (!strncmp(res->VitalProductData.PrintableModel,
-					  "Radstone",8))
-			{
-				extern char *Motherboard_map_name;
-
-				_prep_type = _PREP_Radstone;
-				Motherboard_map_name=
-					res->VitalProductData.PrintableModel;
-			}
-			else
-				_prep_type = _PREP_Motorola;
-		}
-		else /* assume motorola if no residual (netboot?) */
-			_prep_type = _PREP_Motorola;
-		setup_pci_ptrs();
-#ifdef CONFIG_BLK_DEV_INITRD
-		/* take care of initrd if we have one */
-		if ( r4 )
-		{
-			initrd_start = r4 + KERNELBASE;
-			initrd_end = r5 + KERNELBASE;
-		}
-#endif /* CONFIG_BLK_DEV_INITRD */
-		/* take care of cmd line */
-		if ( r6 )
-		{
-			*(char *)(r7+KERNELBASE) = 0;
-			strcpy(cmd_line, (char *)(r6+KERNELBASE));
-		}
+                prep_init(r3, r4, r5, r6, r7);
 		break;
 	case _MACH_chrp:
-		setup_pci_ptrs();
-#ifdef CONFIG_BLK_DEV_INITRD
-		/* take care of initrd if we have one */
-		if ( r3 )
-		{
-			initrd_start = r3 + KERNELBASE;
-			initrd_end = r3 + r4 + KERNELBASE;
-		}
-#endif /* CONFIG_BLK_DEV_INITRD */
-		/* pci_dram_offset/isa_io_base/isa_mem_base set by setup_pci_ptrs() */
-#if !defined(CONFIG_MACH_SPECIFIC)
-		ISA_DMA_THRESHOLD = ~0L;
-		DMA_MODE_READ = 0x44;
-		DMA_MODE_WRITE = 0x48;
-#endif /* ! CONFIG_MACH_SPECIFIC */
+                chrp_init(r3, r4, r5, r6, r7);
 		break;
-#ifdef CONFIG_APUS		
+#ifdef CONFIG_APUS
 	case _MACH_apus:
-		/* Parse bootinfo. The bootinfo is located right after
-                   the kernel bss */
-		parse_bootinfo((const struct bi_record *)&_end);
-#ifdef CONFIG_BLK_DEV_INITRD
-		/* Take care of initrd if we have one. Use data from
-		   bootinfo to avoid the need to initialize PPC
-		   registers when kernel is booted via a PPC reset. */
-		if ( ramdisk.addr ) {
-			initrd_start = (unsigned long) __va(ramdisk.addr);
-			initrd_end = (unsigned long) 
-				__va(ramdisk.size + ramdisk.addr);
-		}
-		/* Make sure code below is not executed. */
-		r4 = 0;
-		r6 = 0;
-#endif /* CONFIG_BLK_DEV_INITRD */
-#if !defined(CONFIG_MACH_SPECIFIC)
-		ISA_DMA_THRESHOLD = 0x00ffffff;
-#endif /* ! CONFIG_MACH_SPECIFIC */
+                apus_init(r3, r4, r5, r6, r7);
 		break;
 #endif
+#ifdef CONFIG_MBX
+        case _MACH_mbx:
+                mbx_init(r3, r4, r5, r6, r7);
+                break;
+#endif
 	default:
 		printk("Unknown machine type in identify_machine!\n");
 	}
 
-#else /* CONFIG_MBX */
-
-	if ( r3 )
-		memcpy( (void *)res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
-	
-#ifdef CONFIG_PCI
-	setup_pci_ptrs();
-#endif
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	/* take care of initrd if we have one */
-	if ( r4 )
-	{
-		initrd_start = r4 + KERNELBASE;
-		initrd_end = r5 + KERNELBASE;
-	}
-#endif /* CONFIG_BLK_DEV_INITRD */
-	/* take care of cmd line */
-	if ( r6 )
-	{
-		
-		*(char *)(r7+KERNELBASE) = 0;
-		strcpy(cmd_line, (char *)(r6+KERNELBASE));
-	}
-#endif /* CONFIG_MBX */
-
 	/* Check for nobats option (used in mapin_ram). */
 	if (strstr(cmd_line, "nobats")) {
 		extern int __map_without_bats;
@@ -740,14 +506,17 @@
 	}
 }
 
+__initfunc(void
+	   ppc_init(void))
+{
+	if (ppc_md.init != NULL) {
+		ppc_md.init();
+	}
+}
+
 __initfunc(void setup_arch(char **cmdline_p,
-	unsigned long * memory_start_p, unsigned long * memory_end_p))
+			   unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
-	extern void pmac_setup_arch(unsigned long *, unsigned long *);
-	extern void chrp_setup_arch(unsigned long *, unsigned long *);
-	extern void prep_setup_arch(unsigned long *, unsigned long *);
-	extern void mbx_setup_arch(unsigned long *, unsigned long *);
-	extern void apus_setup_arch(unsigned long *, unsigned long *);
 	extern int panic_timeout;
 	extern char _etext[], _edata[];
 	extern char *klimit;
@@ -776,27 +545,113 @@
 	*memory_start_p = find_available_memory();
 	*memory_end_p = (unsigned long) end_of_DRAM;
 
-#ifdef CONFIG_MBX
-	mbx_setup_arch(memory_start_p,memory_end_p);
-#else /* CONFIG_MBX */	
-	switch (_machine) {
-	case _MACH_Pmac:
-		pmac_setup_arch(memory_start_p, memory_end_p);
-		break;
-	case _MACH_prep:
-		prep_setup_arch(memory_start_p, memory_end_p);
-		break;
-	case _MACH_chrp:
-		chrp_setup_arch(memory_start_p, memory_end_p);
-		break;
-#ifdef CONFIG_APUS		
-	case _MACH_apus:
-		m68k_machtype = MACH_AMIGA;
-		apus_setup_arch(memory_start_p,memory_end_p);
-		break;
-#endif
-	default:
-		printk("Unknown machine %d in setup_arch()\n", _machine);
-	}
-#endif /* CONFIG_MBX */	
+	ppc_md.setup_arch(memory_start_p, memory_end_p);
+}
+
+void ppc_generic_ide_fix_driveid(struct hd_driveid *id)
+{
+        int i;
+	unsigned short *stringcast;
+
+
+	id->config         = __le16_to_cpu(id->config);
+	id->cyls           = __le16_to_cpu(id->cyls);
+	id->reserved2      = __le16_to_cpu(id->reserved2);
+	id->heads          = __le16_to_cpu(id->heads);
+	id->track_bytes    = __le16_to_cpu(id->track_bytes);
+	id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
+	id->sectors        = __le16_to_cpu(id->sectors);
+	id->vendor0        = __le16_to_cpu(id->vendor0);
+	id->vendor1        = __le16_to_cpu(id->vendor1);
+	id->vendor2        = __le16_to_cpu(id->vendor2);
+	stringcast = (unsigned short *)&id->serial_no[0];
+	for (i=0; i<(20/2); i++)
+	        stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->buf_type       = __le16_to_cpu(id->buf_type);
+	id->buf_size       = __le16_to_cpu(id->buf_size);
+	id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
+	stringcast = (unsigned short *)&id->fw_rev[0];
+	for (i=0; i<(8/2); i++)
+	        stringcast[i] = __le16_to_cpu(stringcast[i]);
+	stringcast = (unsigned short *)&id->model[0];
+	for (i=0; i<(40/2); i++)
+	        stringcast[i] = __le16_to_cpu(stringcast[i]);
+	id->dword_io       = __le16_to_cpu(id->dword_io);
+	id->reserved50     = __le16_to_cpu(id->reserved50);
+	id->field_valid    = __le16_to_cpu(id->field_valid);
+	id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
+	id->cur_heads      = __le16_to_cpu(id->cur_heads);
+	id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
+	id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
+	id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
+	id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
+	id->dma_1word      = __le16_to_cpu(id->dma_1word);
+	id->dma_mword      = __le16_to_cpu(id->dma_mword);
+	id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
+	id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
+	id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
+	id->eide_pio       = __le16_to_cpu(id->eide_pio);
+	id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
+	id->word69         = __le16_to_cpu(id->word69);
+	id->word70         = __le16_to_cpu(id->word70);
+	id->word71         = __le16_to_cpu(id->word71);
+	id->word72         = __le16_to_cpu(id->word72);
+	id->word73         = __le16_to_cpu(id->word73);
+	id->word74         = __le16_to_cpu(id->word74);
+	id->word75         = __le16_to_cpu(id->word75);
+	id->word76         = __le16_to_cpu(id->word76);
+	id->word77         = __le16_to_cpu(id->word77);
+	id->word78         = __le16_to_cpu(id->word78);
+	id->word79         = __le16_to_cpu(id->word79);
+	id->word80         = __le16_to_cpu(id->word80);
+	id->word81         = __le16_to_cpu(id->word81);
+	id->command_sets   = __le16_to_cpu(id->command_sets);
+	id->word83         = __le16_to_cpu(id->word83);
+	id->word84         = __le16_to_cpu(id->word84);
+	id->word85         = __le16_to_cpu(id->word85);
+	id->word86         = __le16_to_cpu(id->word86);
+	id->word87         = __le16_to_cpu(id->word87);
+	id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
+	id->word89         = __le16_to_cpu(id->word89);
+	id->word90         = __le16_to_cpu(id->word90);
+	id->word91         = __le16_to_cpu(id->word91);
+	id->word92         = __le16_to_cpu(id->word92);
+	id->word93         = __le16_to_cpu(id->word93);
+	id->word94         = __le16_to_cpu(id->word94);
+	id->word95         = __le16_to_cpu(id->word95);
+	id->word96         = __le16_to_cpu(id->word96);
+	id->word97         = __le16_to_cpu(id->word97);
+	id->word98         = __le16_to_cpu(id->word98);
+	id->word99         = __le16_to_cpu(id->word99);
+	id->word100        = __le16_to_cpu(id->word100);
+	id->word101        = __le16_to_cpu(id->word101);
+	id->word102        = __le16_to_cpu(id->word102);
+	id->word103        = __le16_to_cpu(id->word103);
+	id->word104        = __le16_to_cpu(id->word104);
+	id->word105        = __le16_to_cpu(id->word105);
+	id->word106        = __le16_to_cpu(id->word106);
+	id->word107        = __le16_to_cpu(id->word107);
+	id->word108        = __le16_to_cpu(id->word108);
+	id->word109        = __le16_to_cpu(id->word109);
+	id->word110        = __le16_to_cpu(id->word110);
+	id->word111        = __le16_to_cpu(id->word111);
+	id->word112        = __le16_to_cpu(id->word112);
+	id->word113        = __le16_to_cpu(id->word113);
+	id->word114        = __le16_to_cpu(id->word114);
+	id->word115        = __le16_to_cpu(id->word115);
+	id->word116        = __le16_to_cpu(id->word116);
+	id->word117        = __le16_to_cpu(id->word117);
+	id->word118        = __le16_to_cpu(id->word118);
+	id->word119        = __le16_to_cpu(id->word119);
+	id->word120        = __le16_to_cpu(id->word120);
+	id->word121        = __le16_to_cpu(id->word121);
+	id->word122        = __le16_to_cpu(id->word122);
+	id->word123        = __le16_to_cpu(id->word123);
+	id->word124        = __le16_to_cpu(id->word124);
+	id->word125        = __le16_to_cpu(id->word125);
+	id->word126        = __le16_to_cpu(id->word126);
+	id->word127        = __le16_to_cpu(id->word127);
+	id->security       = __le16_to_cpu(id->security);
+	for (i=0; i<127; i++)
+	        id->reserved[i] = __le16_to_cpu(id->reserved[i]);
 }
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c
--- v2.2.7/linux/arch/ppc/kernel/signal.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/signal.c	Thu Apr 29 12:39:01 1999
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/ppc/kernel/signal.c
  *
- *  $Id: signal.c,v 1.23 1999/03/01 16:51:53 cort Exp $
+ *  $Id: signal.c,v 1.24 1999/04/03 11:25:16 paulus Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -218,13 +218,8 @@
 	if (sc == (struct sigcontext_struct *)(sigctx.regs)) {
 		/* Last stacked signal - restore registers */
 		sr = (struct sigregs *) sigctx.regs;
-#ifdef __SMP__
-		if ( regs->msr & MSR_FP  )
-			smp_giveup_fpu(current);
-#else	
-		if (last_task_used_math == current)
-			giveup_fpu();
-#endif		
+		if (regs->msr & MSR_FP )
+			giveup_fpu(current);
 		if (copy_from_user(saved_regs, &sr->gp_regs,
 				   sizeof(sr->gp_regs)))
 			goto badframe;
@@ -271,13 +266,8 @@
 
 	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto badframe;
-#ifdef __SMP__
-		if ( regs->msr & MSR_FP  )
-			smp_giveup_fpu(current);
-#else	
-		if (last_task_used_math == current)
-			giveup_fpu();
-#endif		
+		if (regs->msr & MSR_FP)
+			giveup_fpu(current);
 	if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
 	    || __copy_to_user(&frame->fp_regs, current->tss.fpr,
 			      ELF_NFPREG * sizeof(double))
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- v2.2.7/linux/arch/ppc/kernel/smp.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/smp.c	Thu Apr 29 12:39:01 1999
@@ -1,10 +1,13 @@
 /*
- * $Id: smp.c,v 1.48 1999/03/16 10:40:32 cort Exp $
+ * $Id: smp.c,v 1.49 1999/03/18 04:16:31 cort Exp $
  *
  * Smp support for ppc.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
  * deal of code from the sparc and intel versions.
+ *
+ * Support for PReP (Motorola MTX/MVME) SMP by Troy Benjegerdes
+ * (troy@microux.com, hozer@drgw.net)
  */
 
 #include <linux/kernel.h>
@@ -253,6 +256,7 @@
 	 * cpu 0, the master -- Cort
 	 */
 	cpu_callin_map[0] = 1;
+	cpu_callin_map[1] = 0;
         smp_store_cpu_info(0);
         active_kernel_processor = 0;
 	current->processor = 0;
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/syscalls.c linux/arch/ppc/kernel/syscalls.c
--- v2.2.7/linux/arch/ppc/kernel/syscalls.c	Mon Oct  5 13:13:36 1998
+++ linux/arch/ppc/kernel/syscalls.c	Sat May  8 11:14:01 1999
@@ -205,12 +205,15 @@
 
 	lock_kernel();
 	if (!(flags & MAP_ANONYMOUS)) {
-		if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
+		file = fget(fd);
+		if (!file)
 			goto out;
 	}
 	
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 	ret = do_mmap(file, addr, len, prot, flags, offset);
+	if (file)
+		fput(file);
 out:
 	unlock_kernel();
 	return ret;
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- v2.2.7/linux/arch/ppc/kernel/time.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/kernel/time.c	Thu Apr 29 12:39:01 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: time.c,v 1.45 1999/03/03 15:09:59 cort Exp $
+ * $Id: time.c,v 1.47 1999/03/18 05:11:11 cort Exp $
  * Common time routines among all ppc machines.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) to merge
@@ -41,18 +41,14 @@
 #include <asm/processor.h>
 #include <asm/nvram.h>
 #include <asm/cache.h>
-#ifdef CONFIG_MBX
-#include <asm/mbx.h>
-#endif
+/* Fixme - Why is this here? - Corey */
 #ifdef CONFIG_8xx
 #include <asm/8xx_immap.h>
 #endif
+#include <asm/machdep.h>
 
 #include "time.h"
 
-/* this is set to the appropriate pmac/prep/chrp func in init_IRQ() */
-int (*set_rtc_time)(unsigned long);
-
 void smp_local_timer_interrupt(struct pt_regs *);
 
 /* keep track of when we need to update the rtc */
@@ -116,16 +112,21 @@
 			 */
 			if ( xtime.tv_sec > last_rtc_update + 660 )
 			{
-				if (set_rtc_time(xtime.tv_sec) == 0)
+				if (ppc_md.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 */
+				}
+				else {
+					/* do it again in 60 s */
+					last_rtc_update = xtime.tv_sec - 60;
+				}
 			}
 		}
 	}
 #ifdef __SMP__
 	smp_local_timer_interrupt(regs);
 #endif		
+
+	/* Fixme - make this more generic - Corey */
 #ifdef CONFIG_APUS
 	{
 		extern void apus_heartbeat (void);
@@ -135,28 +136,6 @@
 	hardirq_exit(cpu);
 }
 
-#ifdef CONFIG_MBX
-/* A place holder for time base interrupts, if they are ever enabled.
-*/
-void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
-{
-	printk("timebase_interrupt()\n");
-}
-
-/* The RTC on the MPC8xx is an internal register.
- * We want to protect this during power down, so we need to unlock,
- * modify, and re-lock.
- */
-static int
-mbx_set_rtc_time(unsigned long time)
-{
-	((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
-	((immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time;
-	((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
-	return(0);
-}
-#endif /* CONFIG_MBX */
-
 /*
  * This version of gettimeofday has microsecond resolution.
  */
@@ -203,199 +182,29 @@
 
 __initfunc(void time_init(void))
 {
-#ifndef CONFIG_MBX
+        if (ppc_md.time_init != NULL)
+        {
+                ppc_md.time_init();
+        }
+
 	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 if (!smp_processor_id()) {
+                ppc_md.calibrate_decr();
 	}
 
-	switch (_machine) {
-	case _MACH_Pmac:
-		xtime.tv_sec = pmac_get_rtc_time();
-		if ( (_get_PVR() >> 16) != 1 && (!smp_processor_id()) )
-			pmac_calibrate_decr();
-		if ( !smp_processor_id() )
-			set_rtc_time = pmac_set_rtc_time;
-		break;
-	case _MACH_chrp:
-		chrp_time_init();
-		xtime.tv_sec = chrp_get_rtc_time();
-		if ((_get_PVR() >> 16) != 1)
-			chrp_calibrate_decr();
-		set_rtc_time = chrp_set_rtc_time;
-		break;
-	case _MACH_prep:
-		xtime.tv_sec = prep_get_rtc_time();
-		prep_calibrate_decr();
-		set_rtc_time = prep_set_rtc_time;
-		break;
-#ifdef CONFIG_APUS		
-	case _MACH_apus:
-	{
-		xtime.tv_sec = apus_get_rtc_time();
-		apus_calibrate_decr();
-		set_rtc_time = apus_set_rtc_time;
- 		break;
-	}
-#endif	
-	}
-	xtime.tv_usec = 0;
-#else /* CONFIG_MBX */
-	mbx_calibrate_decr();
-	set_rtc_time = mbx_set_rtc_time;
-
-	/* First, unlock all of the registers we are going to modify.
-	 * To protect them from corruption during power down, registers
-	 * that are maintained by keep alive power are "locked".  To
-	 * modify these registers we have to write the key value to
-	 * the key location associated with the register.
-	 */
-	((immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY;
-	((immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY;
-
-
-	/* Disable the RTC one second and alarm interrupts.
-	*/
-	((immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc &=
-						~(RTCSC_SIE | RTCSC_ALE);
-
-	/* Enabling the decrementer also enables the timebase interrupts
-	 * (or from the other point of view, to get decrementer interrupts
-	 * we have to enable the timebase).  The decrementer interrupt
-	 * is wired into the vector table, nothing to do here for that.
-	 */
-	((immap_t *)IMAP_ADDR)->im_sit.sit_tbscr =
-				((mk_int_int_mask(DEC_INTERRUPT) << 8) |
-					 (TBSCR_TBF | TBSCR_TBE));
-	if (request_irq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
-		panic("Could not allocate timer IRQ!");
-
-	/* Get time from the RTC.
-	*/
-	xtime.tv_sec = ((immap_t *)IMAP_ADDR)->im_sit.sit_rtc;
-	xtime.tv_usec = 0;
+        xtime.tv_sec = ppc_md.get_rtc_time();
+        xtime.tv_usec = 0;
 
-#endif /* CONFIG_MBX */
 	set_dec(decrementer_count);
 	/* mark the rtc/on-chip timer as in sync
 	 * so we don't update right away
 	 */
 	last_rtc_update = xtime.tv_sec;
 }
-
-#ifndef CONFIG_MBX
-/*
- * 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;
-__initfunc(void prep_calibrate_decr(void))
-{
-	unsigned long flags;
-	unsigned long freq, divisor;
-
-	/* the Powerstack II's have trouble with the timer so
-	 * we use a default value -- Cort
-	 */
-	if ( (_prep_type == _PREP_Motorola) &&
-	     ((inb(0x800) & 0xF0) & 0x40) )
-	{
-		static unsigned long t2 = 0;
-		
-		t2 = 998700000/60;
-		freq = t2 * 60;	/* try to make freq/1e6 an integer */
-		divisor = 60;
-		printk("time_init: decrementer frequency = %lu/%lu (%luMHz)\n",
-		       freq, divisor,t2>>20);
-		decrementer_count = freq / HZ / divisor;
-		count_period_num = divisor;
-		count_period_den = freq / 1000000;
-		return;
-	}
-	if ( _prep_type == _PREP_Radstone )
-	{
-		freq = res->VitalProductData.ProcessorBusHz;
-		divisor = 4;
-		printk("time_init: decrementer frequency = %d/%d\n", freq, divisor);
-		decrementer_count = freq / HZ / divisor;
-		count_period_num = divisor;
-		count_period_den = freq / 1000000;
-		return;
-	}
-	
-	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);
-}
-
-__initfunc(void prep_calibrate_decr_handler(int irq, void *dev, struct pt_regs * regs))
-{
-	unsigned long 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 = %lu/%lu (%luMHz)\n",
-		       freq, divisor,t2>>20);
-		decrementer_count = freq / HZ / divisor;
-		count_period_num = divisor;
-		count_period_den = freq / 1000000;
-		*done_ptr = 1;
-	}
-}
-
-#else /* CONFIG_MBX */
-
-/* The decrementer counts at the system (internal) clock frequency divided by
- * sixteen, or external oscillator divided by four.  Currently, we only
- * support the MBX, which is system clock divided by sixteen.
- */
-__initfunc(void mbx_calibrate_decr(void))
-{
-	bd_t	*binfo = (bd_t *)res;
-	int freq, fp, divisor;
-
-	if ((((immap_t *)IMAP_ADDR)->im_clkrst.car_sccr & 0x02000000) == 0)
-		printk("WARNING: Wrong decrementer source clock.\n");
-
-	/* The manual says the frequency is in Hz, but it is really
-	 * as MHz.  The value 'fp' is the number of decrementer ticks
-	 * per second.
-	 */
-	fp = (binfo->bi_intfreq * 1000000) / 16;
-	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;
-}
-#endif /* CONFIG_MBX */
 
 /* 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
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/time.h linux/arch/ppc/kernel/time.h
--- v2.2.7/linux/arch/ppc/kernel/time.h	Thu Apr 23 20:21:29 1998
+++ linux/arch/ppc/kernel/time.h	Thu Apr 29 12:39:01 1999
@@ -1,5 +1,5 @@
 /*
- * $Id: time.h,v 1.10 1998/04/01 07:46:03 geert Exp $
+ * $Id: time.h,v 1.11 1999/03/18 04:16:34 cort Exp $
  * Common time prototypes and such for all ppc machines.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) to merge
@@ -9,32 +9,15 @@
 #include <linux/mc146818rtc.h>
 
 /* time.c */
-void prep_calibrate_decr_handler(int, void *,struct pt_regs *);
-void prep_calibrate_decr(void);
-void pmac_calibrate_decr(void);
-extern void apus_calibrate_decr(void);
 extern unsigned decrementer_count;
 extern unsigned count_period_num;
 extern unsigned count_period_den;
-extern unsigned long mktime(unsigned int, unsigned int,unsigned int,
+extern unsigned long mktime(unsigned int, unsigned int, unsigned int,
 			    unsigned int, unsigned int, unsigned int);
 extern void to_tm(int tim, struct rtc_time * tm);
 extern unsigned long last_rtc_update;
 
-/* pmac/prep/chrp_time.c */
-unsigned long prep_get_rtc_time(void);
-unsigned long pmac_get_rtc_time(void);
-unsigned long chrp_get_rtc_time(void);
-unsigned long apus_get_rtc_time(void);
-int prep_set_rtc_time(unsigned long nowtime);
-int pmac_set_rtc_time(unsigned long nowtime);
-int chrp_set_rtc_time(unsigned long nowtime);
-int apus_set_rtc_time(unsigned long nowtime);
-void pmac_read_rtc_time(void);
-void chrp_calibrate_decr(void);
-void chrp_time_init(void);
 int via_calibrate_decr(void);
-void mbx_calibrate_decr(void);
 
 /* Accessor functions for the decrementer register. */
 static __inline__ unsigned int get_dec(void)
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c
--- v2.2.7/linux/arch/ppc/kernel/traps.c	Thu Jan  7 15:11:36 1999
+++ linux/arch/ppc/kernel/traps.c	Thu Apr 29 12:39:01 1999
@@ -191,13 +191,8 @@
 {
 	int fixed;
 
-#ifdef __SMP__
-	if (regs->msr & MSR_FP )
-		smp_giveup_fpu(current);
-#else	
-	if (last_task_used_math == current)
-		giveup_fpu();
-#endif	
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
 	fixed = fix_alignment(regs);
 	if (fixed == 1) {
 		regs->nip += 4;	/* skip over emulated instruction */
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/lib/strcase.c linux/arch/ppc/lib/strcase.c
--- v2.2.7/linux/arch/ppc/lib/strcase.c	Sat Aug 16 09:51:08 1997
+++ linux/arch/ppc/lib/strcase.c	Thu Apr 29 12:39:01 1999
@@ -10,3 +10,14 @@
 	} while (c1 == c2 && c1 != 0);
 	return c1 - c2;
 }
+
+int strncasecmp(const char *s1, const char *s2, int n)
+{
+	int c1, c2;
+
+	do {
+		c1 = tolower(*s1++);
+		c2 = tolower(*s2++);
+	} while ((--n > 0) && c1 == c2 && c1 != 0);
+	return c1 - c2;
+}
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/mbxboot/head.S linux/arch/ppc/mbxboot/head.S
--- v2.2.7/linux/arch/ppc/mbxboot/head.S	Fri Apr 16 14:47:30 1999
+++ linux/arch/ppc/mbxboot/head.S	Thu Apr 29 12:39:01 1999
@@ -6,7 +6,7 @@
 	.text
 
 /*
- * $Id: head.S,v 1.2 1999/02/17 06:29:41 cort Exp $
+ * $Id: head.S,v 1.4 1999/04/22 06:32:09 davem Exp $
  *	
  * This code is loaded by the ROM loader at some arbitrary location.
  * Move it to high memory so that it can load the kernel at 0x0000.
@@ -67,7 +67,7 @@
 	mr      r11, r21
 	lis	r8,start@h
 	ori	r8,r8,start@l
-	li	r9,end@h
+	lis	r9,end@h
 	ori	r9,r9,end@l
 	sub	r7,r8,r9
 	srwi	r7,r7,2
diff -u --recursive --new-file v2.2.7/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.2.7/linux/arch/ppc/mm/init.c	Tue Mar 23 14:35:46 1999
+++ linux/arch/ppc/mm/init.c	Thu Apr 29 12:39:01 1999
@@ -1,5 +1,5 @@
- /*
- *  $Id: init.c,v 1.150 1999/03/10 08:16:33 cort Exp $
+/*
+ *  $Id: init.c,v 1.163 1999/04/09 06:37:13 cort Exp $
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
@@ -132,6 +132,8 @@
 	unsigned long limit;
 	unsigned long phys;
 } bat_addrs[4];
+unsigned long inline v_mapped_by_bats(unsigned long);
+unsigned long inline p_mapped_by_bats(unsigned long);
 #endif /* CONFIG_8xx */
 
 /*
@@ -144,6 +146,7 @@
 /* optimization for 603 to load the tlb directly from the linux table -- Cort */
 #define NO_RELOAD_HTAB 1 /* change in kernel/head.S too! */
 
+
 void __bad_pte(pmd_t *pmd)
 {
 	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
@@ -332,15 +335,42 @@
 	 * virt == phys; for addresses below this we use
 	 * space going down from ioremap_base (ioremap_bot
 	 * records where we're up to).
-	 *
-	 * We should also look out for a frame buffer and
-	 * map it with a free BAT register, if there is one.
 	 */
 	p = addr & PAGE_MASK;
 	size = PAGE_ALIGN(addr + size) - p;
+
+	/*
+	 * Don't allow anybody to remap normal RAM that we're using.
+	 * mem_init() sets high_memory so only do the check after that.
+	 */
+	if ( mem_init_done && (p < virt_to_phys(high_memory)) )
+	{
+		printk("__ioremap(): phys addr %0lx is RAM lr %p\n", p,
+		       __builtin_return_address(0));
+		return NULL;
+	}
+
 	if (size == 0)
 		return NULL;
 
+#ifndef CONFIG_8xx
+#if 0	
+	/*
+	 * Is it already mapped?  Perhaps overlapped by a previous
+	 * BAT mapping.  If the whole area is mapped then we're done,
+	 * otherwise remap it since we want to keep the virt addrs for
+	 * each request contiguous.
+	 *
+	 * We make the assumption here that if the bottom and top
+	 * of the range we want are mapped then it's mapped to the
+	 * same virt address (and this is contiguous).
+	 *  -- Cort
+	 */
+	if ( (v = p_mapped_by_bats(addr)) /*&& p_mapped_by_bats(addr+(size-1))*/ )
+		goto out;
+#endif	
+#endif /* CONFIG_8xx */
+	
 	if (mem_init_done) {
 		struct vm_struct *area;
 		area = get_vm_area(size);
@@ -358,9 +388,15 @@
 		flags |= pgprot_val(PAGE_KERNEL);
 	if (flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU))
 		flags |= _PAGE_GUARDED;
+
+#ifndef CONFIG_8xx	
+	/*
+	 * Is it a candidate for a BAT mapping?
+	 */
+#endif /* CONFIG_8xx */
+	
 	for (i = 0; i < size; i += PAGE_SIZE)
 		map_page(&init_task, v+i, p+i, flags);
-
 	return (void *) (v + (addr & ~PAGE_MASK));
 }
 
@@ -412,9 +448,7 @@
 {
 	pmd_t *pd;
 	pte_t *pg;
-#ifndef CONFIG_8xx
-	int b;
-#endif
+	
 	if (tsk->mm->pgd == NULL) {
 		/* Allocate upper level page map */
 		tsk->mm->pgd = (pgd_t *) MMU_get_page();
@@ -422,20 +456,8 @@
 	/* Use upper 10 bits of VA to index the first level map */
 	pd = (pmd_t *) (tsk->mm->pgd + (va >> PGDIR_SHIFT));
 	if (pmd_none(*pd)) {
-#ifndef CONFIG_8xx
-		/*
-		 * Need to allocate second-level table, but first
-		 * check whether this address is already mapped by
-		 * the BATs; if so, don't bother allocating the page.
-		 */
-		for (b = 0; b < 4; ++b) {
-			if (va >= bat_addrs[b].start
-			    && va <= bat_addrs[b].limit) {
-				/* XXX should check the phys address matches */
-				return;
-			}
-		}
-#endif /* CONFIG_8xx */
+		if ( v_mapped_by_bats(va) )
+			return;
 		pg = (pte_t *) MMU_get_page();
 		pmd_val(*pd) = (unsigned long) pg;
 	}
@@ -680,6 +702,33 @@
 static void sort_mem_pieces(struct mem_pieces *);
 static void coalesce_mem_pieces(struct mem_pieces *);
 
+/*
+ * Return 1 if this VA is mapped by BATs
+ */
+unsigned long inline v_mapped_by_bats(unsigned long va)
+{
+	int b;
+	for (b = 0; b < 4; ++b)
+		if (va >= bat_addrs[b].start
+	    	    && va < bat_addrs[b].limit)
+			return 1;
+	return 0;
+}
+
+/*
+ * Return VA for a given PA or 0 if not mapped
+ */
+unsigned long inline p_mapped_by_bats(unsigned long pa)
+{
+	int b;
+	for (b = 0; b < 4; ++b)
+		if (pa >= bat_addrs[b].phys
+	    	    && pa < (bat_addrs[b].limit-bat_addrs[b].start)
+		              +bat_addrs[b].phys)
+			return bat_addrs[b].start+(pa-bat_addrs[b].phys);
+	return 0;
+}
+
 __initfunc(static void sort_mem_pieces(struct mem_pieces *mp))
 {
 	unsigned long a, s;
@@ -836,7 +885,7 @@
 
 		setbat(2, KERNELBASE, mem_base, bl, RAM_PAGE);
 		done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1;
-		if (done < tot) {
+		if ((done < tot) && !bat_addrs[3].limit) {
 			/* use BAT3 to cover a bit more */
 			tot -= done;
 			for (bl = 128<<10; bl < max_size; bl <<= 1)
@@ -990,11 +1039,13 @@
 	switch (_machine) {
 	case _MACH_prep:
 		setbat(0, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
-		setbat(1, 0xd0000000, 0xc0000000, 0x10000000, IO_PAGE);
+		setbat(1, 0xf0000000, 0xc0000000, 0x08000000, IO_PAGE);
+		ioremap_base = 0xf0000000;
 		break;
 	case _MACH_chrp:
 		setbat(0, 0xf8000000, 0xf8000000, 0x08000000, IO_PAGE);
 		setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
+		setbat(3, 0x90000000, 0x90000000, 0x10000000, IO_PAGE);
 		break;
 	case _MACH_Pmac:
 		{
@@ -1245,7 +1296,7 @@
 	int i;
 	
 	/* max amount of RAM we allow -- Cort */
-#define RAM_LIMIT (768<<20)	
+#define RAM_LIMIT (768<<20)
 
 	memory_node = find_devices("memory");
 	if (memory_node == NULL) {
@@ -1530,4 +1581,3 @@
 	}
 }
 #endif /* ndef CONFIG_8xx */
-
diff -u --recursive --new-file v2.2.7/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.2.7/linux/arch/sparc64/kernel/ioctl32.c	Mon Mar 29 11:09:11 1999
+++ linux/arch/sparc64/kernel/ioctl32.c	Wed Apr 28 14:40:07 1999
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.60 1999/03/22 10:40:54 jj Exp $
+/* $Id: ioctl32.c,v 1.61 1999/04/28 19:44:31 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
@@ -26,6 +26,7 @@
 #include <linux/fs.h>
 #include <linux/file.h>
 #include <linux/fd.h>
+#include <linux/ppp_defs.h>
 #include <linux/if_ppp.h>
 #include <linux/mtio.h>
 #include <linux/cdrom.h>
diff -u --recursive --new-file v2.2.7/linux/drivers/Makefile linux/drivers/Makefile
--- v2.2.7/linux/drivers/Makefile	Wed Apr 28 11:37:30 1999
+++ linux/drivers/Makefile	Mon May 10 10:18:34 1999
@@ -47,7 +47,11 @@
 ifeq ($(CONFIG_USB),y)
 SUB_DIRS += usb
 MOD_SUB_DIRS += usb
-endif
+else
+  ifeq ($(CONFIG_USB),m)
+  MOD_SUB_DIRS += usb
+  endif
+endif 
 
 # If CONFIG_SCSI is set, the core of SCSI support will be added to the kernel,
 # but some of the low-level things may also be modules.
diff -u --recursive --new-file v2.2.7/linux/drivers/block/Config.in linux/drivers/block/Config.in
--- v2.2.7/linux/drivers/block/Config.in	Thu Dec 31 10:28:59 1998
+++ linux/drivers/block/Config.in	Thu Apr 29 12:53:48 1999
@@ -51,13 +51,15 @@
           bool '   Winbond SL82c105 support' CONFIG_BLK_DEV_SL82C105
       fi
     fi
-    if [ "$CONFIG_PMAC" = "y" ]; then
-      define_bool CONFIG_BLK_DEV_IDE_PMAC y
-      bool '   PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC
-      if [ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" ]; then
-        define_bool CONFIG_BLK_DEV_IDEDMA y
-	bool '     Use DMA by default' CONFIG_PMAC_IDEDMA_AUTO
-      fi
+    if [ "$CONFIG_PMAC" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then
+      bool '   Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC
+        if [ "$CONFIG_BLK_DEV_IDE_PMAC" != "n" ]; then
+          bool '     PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC
+          if [ "$CONFIG_BLK_DEV_IDEDMA_PMAC" = "y" ]; then
+            define_bool CONFIG_BLK_DEV_IDEDMA y
+            bool '     Use DMA by default' CONFIG_PMAC_IDEDMA_AUTO
+          fi
+       fi
     fi
     bool '   Other IDE chipset support' CONFIG_IDE_CHIPSETS
     if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
diff -u --recursive --new-file v2.2.7/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.2.7/linux/drivers/block/ide.c	Tue Mar 23 14:35:47 1999
+++ linux/drivers/block/ide.c	Mon May  3 09:34:51 1999
@@ -813,7 +813,7 @@
 		ide_end_drive_cmd(drive, stat, err);
 		return;
 	}
-	if (stat & BUSY_STAT) {		/* other bits are useless when BUSY */
+	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */
 		rq->errors |= ERROR_RESET;
 	} else {
 		if (drive->media == ide_disk && (stat & ERR_STAT)) {
diff -u --recursive --new-file v2.2.7/linux/drivers/block/rd.c linux/drivers/block/rd.c
--- v2.2.7/linux/drivers/block/rd.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/block/rd.c	Thu Apr 29 11:53:41 1999
@@ -33,11 +33,13 @@
  *
  *  Added initrd: Werner Almesberger & Hans Lermen, Feb '96
  *
-* 4/25/96 : Made RAM disk size a parameter (default is now 4 MB) 
+ * 4/25/96 : Made RAM disk size a parameter (default is now 4 MB) 
  *		- Chad Page
  *
  * Add support for fs images split across >1 disk, Paul Gortmaker, Mar '98
  *
+ * Make block size and block size shift for RAM disks a global macro
+ * and set blk_size for -ENOSPC,     Werner Fink <werner@suse.de>, Apr '99
  */
 
 #include <linux/config.h>
@@ -47,6 +49,7 @@
 #include <linux/romfs_fs.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
+#include <linux/hdreg.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
@@ -70,6 +73,15 @@
 #define MAJOR_NR RAMDISK_MAJOR
 #include <linux/blk.h>
 
+/*
+ * We use a block size of 512 bytes in comparision to BLOCK_SIZE
+ * defined in include/linux/blk.h. This because of the finer
+ * granularity for filling up a RAM disk.
+ */
+#define RDBLK_SIZE_BITS		9
+#define RDBLK_SIZE		(1<<RDBLK_SIZE_BITS)
+
+
 /* The RAM disk size is now a parameter */
 #define NUM_RAMDISKS 16		/* This cannot be overridden (yet) */ 
 
@@ -89,8 +101,10 @@
 /* Various static variables go here.  Most are used only in the RAM disk code.
  */
 
-static int rd_length[NUM_RAMDISKS];
-static int rd_blocksizes[NUM_RAMDISKS];
+static unsigned long rd_length[NUM_RAMDISKS];	/* Size of RAM disks in bytes   */
+static int rd_hardsec[NUM_RAMDISKS];		/* Size of real blocks in bytes */
+static int rd_blocksizes[NUM_RAMDISKS];		/* Size of 1024 byte blocks :)  */
+static int rd_kbsize[NUM_RAMDISKS];		/* Size in blocks of 1024 bytes */
 
 /*
  * Parameters for the boot-loading of the RAM disk.  These are set by
@@ -120,9 +134,12 @@
 static void rd_request(void)
 {
 	unsigned int minor;
-	int offset, len;
+	unsigned long offset, len;
 
 repeat:
+	if (!CURRENT)
+		return;
+
 	INIT_REQUEST;
 	
 	minor = MINOR(CURRENT->rq_dev);
@@ -132,14 +149,20 @@
 		goto repeat;
 	}
 	
-	offset = CURRENT->sector << 9;
-	len = CURRENT->current_nr_sectors << 9;
+	offset = CURRENT->sector << RDBLK_SIZE_BITS;
+	len = CURRENT->current_nr_sectors << RDBLK_SIZE_BITS;
 
 	if ((offset + len) > rd_length[minor]) {
 		end_request(0);
 		goto repeat;
 	}
 
+	if ((CURRENT->cmd != READ) && (CURRENT->cmd != WRITE)) {
+		printk(KERN_INFO "RAMDISK: bad command: %d\n", CURRENT->cmd);
+		end_request(0);
+		goto repeat;
+	}
+
 	/*
 	 * If we're reading, fill the buffer with 0's.  This is okay since
          * we're using protected buffers which should never get freed...
@@ -158,24 +181,31 @@
 
 static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
+	unsigned int minor;
+
 	if (!inode || !inode->i_rdev) 	
 		return -EINVAL;
 
+	minor = MINOR(inode->i_rdev);
+
 	switch (cmd) {
 		case BLKFLSBUF:
 			if (!capable(CAP_SYS_ADMIN)) return -EACCES;
 			invalidate_buffers(inode->i_rdev);
 			break;
+
          	case BLKGETSIZE:   /* Return device size */
 			if (!arg)  return -EINVAL;
-			return put_user(rd_length[MINOR(inode->i_rdev)] / 512, 
-				 (long *) arg);
-		case BLKSSZGET:
-			/* Block size of media */
-			return put_user(rd_blocksizes[MINOR(inode->i_rdev)],
-						    (int *)arg);
+			return put_user(rd_length[minor] >> RDBLK_SIZE_BITS, (long *) arg);
+
+		case BLKSSZGET:	   /* Block size of media */
+			if (!arg)  return -EINVAL;
+			return put_user(rd_blocksizes[minor], (int *)arg);
+
+		RO_IOCTLS(inode->i_rdev, arg);
+
 		default:
-			break;
+			return -EINVAL;
 	};
 
 	return 0;
@@ -263,7 +293,7 @@
 	rd_open,	/* open */
 	NULL,		/* flush */
 	rd_release,	/* module needs to decrement use count */
-	block_fsync		/* fsync */ 
+	block_fsync	/* fsync */ 
 };
 
 /* This is the registration and initialization section of the RAM disk driver */
@@ -279,11 +309,16 @@
 	blk_dev[MAJOR_NR].request_fn = &rd_request;
 
 	for (i = 0; i < NUM_RAMDISKS; i++) {
-		rd_length[i] = (rd_size * 1024);
-		rd_blocksizes[i] = 1024;
+		/* rd_size is given in kB */
+		rd_length[i] = (rd_size << BLOCK_SIZE_BITS);
+		rd_hardsec[i] = RDBLK_SIZE;
+		rd_blocksizes[i] = BLOCK_SIZE;
+		rd_kbsize[i] = (rd_length[i] >> BLOCK_SIZE_BITS);
 	}
 
-	blksize_size[MAJOR_NR] = rd_blocksizes;
+	hardsect_size[MAJOR_NR] = rd_hardsec;		/* Size of the RAM disk blocks */
+	blksize_size[MAJOR_NR] = rd_blocksizes;		/* Avoid set_blocksize() check */
+	blk_size[MAJOR_NR] = rd_kbsize;			/* Size of the RAM disk in kB  */
 
 	printk("RAM disk driver initialized:  %d RAM disks of %dK size\n",
 							NUM_RAMDISKS, rd_size);
@@ -295,7 +330,8 @@
 
 #ifdef MODULE
 
-MODULE_PARM (rd_size, "1i");
+MODULE_PARM     (rd_size, "1i");
+MODULE_PARM_DESC(rd_size, "Size of each RAM disk.");
 
 int init_module(void)
 {
@@ -427,7 +463,7 @@
 /*
  * This routine loads in the RAM disk image.
  */
-__initfunc(static void rd_load_image(kdev_t device,int offset))
+__initfunc(static void rd_load_image(kdev_t device, int offset, int unit))
 {
  	struct inode inode, out_inode;
 	struct file infile, outfile;
@@ -440,7 +476,7 @@
 	unsigned short devblocks = 0;
 	char rotator[4] = { '|' , '/' , '-' , '\\' };
 
-	ram_device = MKDEV(MAJOR_NR, 0);
+	ram_device = MKDEV(MAJOR_NR, unit);
 
 	memset(&infile, 0, sizeof(infile));
 	memset(&inode, 0, sizeof(inode));
@@ -480,9 +516,9 @@
 		goto done;
 	}
 
-	if (nblocks > (rd_length[0] >> BLOCK_SIZE_BITS)) {
+	if (nblocks > (rd_length[unit] >> RDBLK_SIZE_BITS)) {
 		printk("RAMDISK: image too big! (%d/%d blocks)\n",
-		       nblocks, rd_length[0] >> BLOCK_SIZE_BITS);
+		       nblocks, rd_length[unit] >> RDBLK_SIZE_BITS);
 		goto done;
 	}
 		
@@ -538,7 +574,7 @@
 
 successful_load:
 	invalidate_buffers(device);
-	ROOT_DEV = MKDEV(MAJOR_NR,0);
+	ROOT_DEV = MKDEV(MAJOR_NR, unit);
 
 done:
 	if (infile.f_op->release)
@@ -547,12 +583,21 @@
 }
 
 
-__initfunc(void rd_load(void))
+__initfunc(static void rd_load_disk(int n))
 {
+#ifdef CONFIG_BLK_DEV_INITRD
+	extern kdev_t real_root_dev;
+#endif
+
 	if (rd_doload == 0)
 		return;
-	
-	if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR) return;
+
+	if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR
+#ifdef CONFIG_BLK_DEV_INITRD
+		&& MAJOR(real_root_dev) != FLOPPY_MAJOR
+#endif
+	)
+		return;
 
 	if (rd_prompt) {
 #ifdef CONFIG_BLK_DEV_FD
@@ -563,15 +608,24 @@
 		wait_for_keypress();
 	}
 
-	rd_load_image(ROOT_DEV,rd_image_start);
+	rd_load_image(ROOT_DEV,rd_image_start, n);
 
 }
 
+__initfunc(void rd_load(void))
+{
+	rd_load_disk(0);
+}
+
+__initfunc(void rd_load_secondary(void))
+{
+	rd_load_disk(1);
+}
 
 #ifdef CONFIG_BLK_DEV_INITRD
 __initfunc(void initrd_load(void))
 {
-	rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0);
+	rd_load_image(MKDEV(MAJOR_NR, INITRD_MINOR),0,0);
 }
 #endif
 
@@ -695,7 +749,14 @@
 crd_load(struct file * fp, struct file *outfp))
 {
 	int result;
-	
+
+	insize = 0;		/* valid bytes in inbuf */
+	inptr = 0;		/* index of next byte to be processed in inbuf */
+	outcnt = 0;		/* bytes in output buffer */
+	exit_code = 0;
+	bytes_out = 0;
+	crc = (ulg)0xffffffffL; /* shift register contents */
+
 	crd_infp = fp;
 	crd_outfp = outfp;
 	inbuf = kmalloc(INBUFSIZ, GFP_KERNEL);
diff -u --recursive --new-file v2.2.7/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.2.7/linux/drivers/cdrom/cdrom.c	Tue Mar 23 14:35:47 1999
+++ linux/drivers/cdrom/cdrom.c	Thu Apr 29 11:53:41 1999
@@ -120,11 +120,16 @@
   2.54 Mar 15, 1999 - Jens Axboe <axboe@image.dk>
   -- Check capability mask from low level driver when counting tracks as
   per suggestion from Corey J. Scotts <cstotts@blue.weeg.uiowa.edu>.
+  
+  2.55 Apr 25, 1999 - Jens Axboe <axboe@image.dk>
+  -- autoclose was mistakenly checked against CDC_OPEN_TRAY instead of
+  CDC_CLOSE_TRAY.
+  -- proc info didn't mask against capabilities mask.
 
 -------------------------------------------------------------------------*/
 
-#define REVISION "Revision: 2.54"
-#define VERSION "Id: cdrom.c 2.54 1999/03/15"
+#define REVISION "Revision: 2.55"
+#define VERSION "Id: cdrom.c 2.55 1999/04/25"
 
 /* I use an error-log mask to give fine grain control over the type of
    messages dumped to the system logs.  The available masks include: */
@@ -268,7 +273,7 @@
 	cdo->n_minors = 0;
         cdi->options = CDO_USE_FFLAGS;
 	
-	if (autoclose==1 && cdo->capability & ~cdi->mask & CDC_OPEN_TRAY)
+	if (autoclose==1 && cdo->capability & ~cdi->mask & CDC_CLOSE_TRAY)
 		cdi->options |= (int) CDO_AUTO_CLOSE;
 	if (autoeject==1 && cdo->capability & ~cdi->mask & CDC_OPEN_TRAY)
 		cdi->options |= (int) CDO_AUTO_EJECT;
@@ -1097,27 +1102,27 @@
 	pos += sprintf(cdrom_drive_info+pos, "\nCan close tray:\t");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
 	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-			   ((cdi->ops->capability & CDC_CLOSE_TRAY)!=0));
+		((cdi->ops->capability & ~cdi->mask & CDC_CLOSE_TRAY)!=0));
 
 	pos += sprintf(cdrom_drive_info+pos, "\nCan open tray:\t");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
 	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-			   ((cdi->ops->capability & CDC_OPEN_TRAY)!=0));
+		   ((cdi->ops->capability & ~cdi->mask & CDC_OPEN_TRAY)!=0));
 
 	pos += sprintf(cdrom_drive_info+pos, "\nCan lock tray:\t");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
 	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-			   ((cdi->ops->capability & CDC_LOCK)!=0));
+		   ((cdi->ops->capability & ~cdi->mask & CDC_LOCK)!=0));
 
 	pos += sprintf(cdrom_drive_info+pos, "\nCan change speed:");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
 	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-			   ((cdi->ops->capability & CDC_SELECT_SPEED)!=0));
+		   ((cdi->ops->capability & ~cdi->mask & CDC_SELECT_SPEED)!=0));
 
 	pos += sprintf(cdrom_drive_info+pos, "\nCan select disk:");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
 	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-			   ((cdi->ops->capability & CDC_SELECT_DISC)!=0));
+		   ((cdi->ops->capability & ~cdi->mask & CDC_SELECT_DISC)!=0));
 
 	pos += sprintf(cdrom_drive_info+pos, "\nCan read multisession:");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
@@ -1137,7 +1142,7 @@
 	pos += sprintf(cdrom_drive_info+pos, "\nCan play audio:\t");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
 	    pos += sprintf(cdrom_drive_info+pos, "\t%d",
-			   ((cdi->ops->capability & CDC_PLAY_AUDIO)!=0));
+		   ((cdi->ops->capability & ~cdi->mask & CDC_PLAY_AUDIO)!=0));
 
         strcpy(cdrom_drive_info+pos,"\n\n");
 	*lenp=pos+3;
diff -u --recursive --new-file v2.2.7/linux/drivers/cdrom/mcdx.h linux/drivers/cdrom/mcdx.h
--- v2.2.7/linux/drivers/cdrom/mcdx.h	Wed Jan 20 23:14:05 1999
+++ linux/drivers/cdrom/mcdx.h	Thu Apr 29 11:53:41 1999
@@ -176,8 +176,10 @@
 #define MCDX_ST_DRV 0x00ff		/* mask to query the drive status */
 
 #ifndef I_WAS_HERE
+#ifndef MODULE
 #warning You have not edited mcdx.h
 #warning Perhaps irq and i/o settings are wrong.
+#endif
 #endif
 
 /* ex:set ts=4 sw=4: */
diff -u --recursive --new-file v2.2.7/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.2.7/linux/drivers/char/Config.in	Fri Apr 16 14:47:30 1999
+++ linux/drivers/char/Config.in	Fri May  7 11:05:30 1999
@@ -137,6 +137,9 @@
     dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
   fi
   dep_tristate 'Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
+  if [ "$CONFIG_PMAC" = "y" ]; then
+    dep_tristate 'PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV
+  fi
   dep_tristate 'SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV
   dep_tristate 'SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV
   if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then
diff -u --recursive --new-file v2.2.7/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.2.7/linux/drivers/char/Makefile	Wed Apr 28 11:37:30 1999
+++ linux/drivers/char/Makefile	Fri May  7 11:05:30 1999
@@ -283,12 +283,12 @@
 endif
 
 ifeq ($(CONFIG_NVRAM),y)
-  ifeq ($(CONFIG_PMAC)$(CONFIG_CHRP),)
+  ifeq ($(CONFIG_PPC),)
   L_OBJS += nvram.o
   endif
 else
   ifeq ($(CONFIG_NVRAM),m)
-    ifeq ($(CONFIG_PMAC)$(CONFIG_CHRP),)
+    ifeq ($(CONFIG_PPC),)
     M_OBJS += nvram.o
     endif
   endif
@@ -351,6 +351,14 @@
 else
   ifeq ($(CONFIG_VIDEO_PMS),m)
   M_OBJS += pms.o
+  endif
+endif
+
+ifeq ($(CONFIG_VIDEO_PLANB),y)
+L_OBJS += planb.o
+else
+  ifeq ($(CONFIG_VIDEO_PLANB),m)
+  M_OBJS += planb.o
   endif
 endif
 
diff -u --recursive --new-file v2.2.7/linux/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c
--- v2.2.7/linux/drivers/char/adbmouse.c	Thu Nov 19 09:56:28 1998
+++ linux/drivers/char/adbmouse.c	Thu Apr 29 12:53:48 1999
@@ -113,7 +113,7 @@
      *  on a logitech mouseman, the right and mid buttons sometimes behave
      *  strangely until they both have been pressed after booting. */
     /* data valid only if extended mouse format ! */
-    if (nb == 4)
+    if (nb >= 4)
 	buttons = (buttons&6) | (buf[3] & 0x80 ? 1 : 0); /* 1+3 unchanged */
 
     add_mouse_randomness(((~buttons&7) << 16) + ((buf[2]&0x7f) << 8) + (buf[1]&0x7f));
diff -u --recursive --new-file v2.2.7/linux/drivers/char/isicom.c linux/drivers/char/isicom.c
--- v2.2.7/linux/drivers/char/isicom.c	Fri Apr 16 14:47:30 1999
+++ linux/drivers/char/isicom.c	Fri May  7 11:05:30 1999
@@ -13,6 +13,23 @@
  *					(fixed range check bug as a side effect)
  *					Printk clean up
  *	9/12/98	alan@redhat.com		Rough port to 2.1.x
+ *
+ *
+ *	***********************************************************
+ *
+ *	To use this driver you also need the support package. You 
+ *	can find this in RPM format on
+ *		ftp://ftp.linux.org.uk/pub/linux/alan
+ * 	
+ *	You can find the original tools for this direct from Multitech
+ *		ftp://ftp.multitech.com/ISI-Cards/
+ *
+ *	Having installed the cards the module options (/etc/conf.modules)
+ *
+ *	options isicom   io=card1,card2,card3,card4 irq=card1,card2,card3,card4
+ *
+ *	Omit those entries for boards you don't have installed.
+ *
  */
 
 #include <linux/module.h>
diff -u --recursive --new-file v2.2.7/linux/drivers/char/lp.c linux/drivers/char/lp.c
--- v2.2.7/linux/drivers/char/lp.c	Tue Mar 23 14:35:47 1999
+++ linux/drivers/char/lp.c	Mon May 10 10:26:31 1999
@@ -202,9 +202,7 @@
 /* Test if the printer is not acking the strobe */
 #define	LP_NO_ACKING(status)	((status) & LP_PACK)
 /* Test if the printer has error conditions */
-#define LP_NO_ERROR(status)					\
-	 (((status) & (LP_POUTPA|LP_PSELECD|LP_PERRORP)) ==	\
-	 (LP_PSELECD|LP_PERRORP))
+#define LP_NO_ERROR(status)	((status) & LP_PERRORP)
 
 #undef LP_DEBUG
 #undef LP_READ_DEBUG
@@ -424,7 +422,10 @@
 {
 	unsigned int last = lp_table[minor].last_error;
 	unsigned char status = r_str(minor);
-	if ((status & LP_POUTPA)) {
+	if (status & LP_PERRORP)
+		/* No error. */
+		last = 0;
+	else if ((status & LP_POUTPA)) {
 		if (last != LP_POUTPA) {
 			last = LP_POUTPA;
 			printk(KERN_INFO "lp%d out of paper\n", minor);
@@ -434,13 +435,12 @@
 			last = LP_PSELECD;
 			printk(KERN_INFO "lp%d off-line\n", minor);
 		}
-	} else if (!(status & LP_PERRORP)) {
+	} else {
 		if (last != LP_PERRORP) {
 			last = LP_PERRORP;
-			printk(KERN_INFO "lp%d on fire!\n", minor);
+			printk(KERN_INFO "lp%d on fire\n", minor);
 		}
 	}
-	else last = 0;
 
 	lp_table[minor].last_error = last;
 
diff -u --recursive --new-file v2.2.7/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.2.7/linux/drivers/char/mem.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/char/mem.c	Mon May 10 10:18:34 1999
@@ -57,7 +57,10 @@
 #ifdef CONFIG_USB_OHCI
 int ohci_init(void);
 #endif
-
+#ifdef CONFIG_USB_OHCI_HCD
+int ohci_hcd_init(void);
+#endif
+     
 static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
 			    const char * buf, size_t count, loff_t *ppos)
 {
@@ -605,11 +608,16 @@
 	if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
 		printk("unable to get major %d for memory devs\n", MEM_MAJOR);
 	rand_initialize();
+#ifdef CONFIG_USB
 #ifdef CONFIG_USB_UHCI
 	uhci_init();
 #endif
 #ifdef CONFIG_USB_OHCI
 	ohci_init();
+#endif
+#ifdef CONFIG_USB_OHCI_HCD
+        ohci_hcd_init(); 
+#endif
 #endif
 #if defined (CONFIG_FB)
 	fbmem_init();
diff -u --recursive --new-file v2.2.7/linux/drivers/char/planb.c linux/drivers/char/planb.c
--- v2.2.7/linux/drivers/char/planb.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/planb.c	Mon May 10 10:17:28 1999
@@ -0,0 +1,2389 @@
+/* 
+    planb - PlanB frame grabber driver
+
+    PlanB is used in the 7x00/8x00 series of PowerMacintosh
+    Computers as video input DMA controller.
+
+    Copyright (C) 1998 Michel Lanners (mlan@cpu.lu)
+
+    Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de)
+
+    Additional debugging and coding by Takashi Oe (toe@unlinfo.unl.edu)
+	(Some codes are stolen from proposed v4l2 videodev.c
+		of Bill Dirks <dirks@rendition.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.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* $Id: planb.c,v 1.18 1999/05/02 17:36:34 mlan Exp $ */
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/malloc.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/wrapper.h>
+#include <linux/tqueue.h>
+#include <linux/videodev.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/dbdma.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/irq.h>
+
+#include "planb.h"
+#include "saa7196.h"
+
+
+/* Would you mind for some ugly debugging? */
+//#define DEBUG(x...) printk(KERN_DEBUG ## x) /* Debug driver */
+#define DEBUG(x...) 		/* Don't debug driver */	
+//#define IDEBUG(x...) printk(KERN_DEBUG ## x) /* Debug interrupt part */
+#define IDEBUG(x...) 		/* Don't debug interrupt part */
+
+/* Ever seen a Mac with more than 1 of these? */
+#define PLANB_MAX 1
+
+static int planb_num;
+static struct planb planbs[PLANB_MAX];
+static volatile struct planb_registers *planb_regs;
+
+static int def_norm = PLANB_DEF_NORM;	/* default norm */
+
+MODULE_PARM(def_norm, "i");
+MODULE_PARM_DESC(def_norm, "Default startup norm (0=PAL, 1=NTSC, 2=SECAM)");
+
+/* ------------------ PlanB Exported Functions ------------------ */
+static long planb_write(struct video_device *, const char *, unsigned long, int);
+static long planb_read(struct video_device *, char *, unsigned long, int);
+static int planb_open(struct video_device *, int);
+static void planb_close(struct video_device *);
+static int planb_ioctl(struct video_device *, unsigned int, void *);
+static int planb_init_done(struct video_device *);
+static int planb_mmap(struct video_device *, const char *, unsigned long);
+static void planb_irq(int, void *, struct pt_regs *);
+static void release_planb(void);
+int init_planbs(struct video_init *);
+
+/* ------------------ PlanB Internal Functions ------------------ */
+static int planb_prepare_open(struct planb *);
+static void planb_prepare_close(struct planb *);
+static void saa_write_reg(unsigned char, unsigned char);
+static unsigned char saa_status(int, struct planb *);
+static void saa_set(unsigned char, unsigned char, struct planb *);
+static void saa_init_regs(struct planb *);
+static void * rvmalloc(unsigned long);
+static void rvfree(void *, unsigned long);
+static unsigned long vmalloc_to_bus(void *);
+static unsigned long vmalloc_to_phys(void *);
+static int fbuffer_alloc(struct planb *);
+static int vgrab(struct planb *, struct video_mmap *);
+static void add_clip(struct planb *, struct video_clip *);
+static void fill_cmd_buff(struct planb *);
+static void cmd_buff(struct planb *);
+static volatile struct dbdma_cmd *setup_grab_cmd(int, struct planb *);
+static void overlay_start(struct planb *);
+static void overlay_stop(struct planb *);
+static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *, unsigned short,
+	unsigned int);
+static inline void tab_cmd_store(volatile struct dbdma_cmd *, unsigned int,
+	unsigned int);
+static inline void tab_cmd_gen(volatile struct dbdma_cmd *, unsigned short,
+	unsigned short, unsigned int, unsigned int);
+static int init_planb(struct planb *);
+static int find_planb(void);
+static void planb_pre_capture(int, int, struct planb *);
+static volatile struct dbdma_cmd *cmd_geo_setup(volatile struct dbdma_cmd *,
+					int, int, int, int, int, struct planb *);
+static inline void planb_dbdma_stop(volatile struct dbdma_regs *);
+static unsigned int saa_geo_setup(int, int, int, int, struct planb *);
+static inline int overlay_is_active(struct planb *);
+
+/*******************************/
+/* Memory management functions */
+/*******************************/
+
+static void * rvmalloc(unsigned long size)
+{
+	void *mem, *memptr;
+	unsigned long page;
+        
+	mem=vmalloc(size);
+	if (mem) 
+	{
+		memset(mem, 0, size); /* Clear the ram out, leave no junk */
+		memptr = mem;
+		while (size > 0) 
+                {
+	                page = vmalloc_to_phys(memptr);
+			mem_map_reserve(MAP_NR(phys_to_virt(page)));
+			memptr+=PAGE_SIZE;
+			size-=PAGE_SIZE;
+		}
+	}
+	return mem;
+}
+
+static void rvfree(void * mem, unsigned long size)
+{
+	void *memptr;
+        unsigned long page;
+        
+	if (mem) 
+	{
+		memptr = mem;
+		while (size > 0) 
+                {
+	                page = vmalloc_to_phys(memptr);
+			mem_map_unreserve(MAP_NR(phys_to_virt(page)));
+			memptr += PAGE_SIZE;
+			size-=PAGE_SIZE;
+		}
+		vfree(mem);
+	}
+}
+
+/*  Useful for using vmalloc()ed memory as DMA target  */
+static unsigned long vmalloc_to_bus(void *virt)
+{
+	pgd_t		*pgd;
+	pmd_t		*pmd;
+	pte_t		*pte;
+	unsigned long	a = (unsigned long)virt;
+
+	if (pgd_none(*(pgd = pgd_offset(current->mm, a))) ||
+	    pmd_none(*(pmd = pmd_offset(pgd,         a))) ||
+	    pte_none(*(pte = pte_offset(pmd,         a))))
+		return 0;
+	return virt_to_bus((void *)pte_page(*pte))
+		+ (a & (PAGE_SIZE - 1));
+}
+
+static unsigned long vmalloc_to_phys(void *virt) {
+	return virt_to_phys(bus_to_virt(vmalloc_to_bus(virt)));
+}
+
+/*
+ *	Create the giant waste of buffer space we need for now
+ *	until we get DMA to user space sorted out (probably 2.3.x)
+ *
+ *	We only create this as and when someone uses mmap
+ */
+ 
+static int fbuffer_alloc(struct planb *pb)
+{
+	if(!pb->fbuffer)
+		pb->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS
+					* PLANB_MAX_FBUF);
+	else
+		printk(KERN_ERR "PlanB: Double alloc of fbuffer!\n");
+	if(!pb->fbuffer)
+		return -ENOBUFS;
+	return 0;
+}
+
+/*****************************/
+/* Hardware access functions */
+/*****************************/
+
+static void saa_write_reg(unsigned char addr, unsigned char val)
+{
+	planb_regs->saa_addr = addr; eieio();
+	planb_regs->saa_regval = val; eieio();
+	return;
+}
+
+/* return  status byte 0 or 1: */
+static unsigned char saa_status(int byte, struct planb *pb)
+{
+	saa_regs[pb->win.norm][SAA7196_STDC] =
+		(saa_regs[pb->win.norm][SAA7196_STDC] & ~2) | ((byte & 1) << 1);
+	saa_write_reg (SAA7196_STDC, saa_regs[pb->win.norm][SAA7196_STDC]);
+
+	/* Let's wait 30msec for this one */
+	current->state = TASK_INTERRUPTIBLE;
+#if LINUX_VERSION_CODE >= 0x02017F
+	schedule_timeout(30 * HZ / 1000);
+#else
+	current->timeout = jiffies + 30 * HZ / 1000;	/* 30 ms */;
+	schedule();
+#endif
+
+	return (unsigned char)in_8 (&planb_regs->saa_status);
+}
+
+static void saa_set(unsigned char addr, unsigned char val, struct planb *pb)
+{
+	if(saa_regs[pb->win.norm][addr] != val) {
+		saa_regs[pb->win.norm][addr] = val;
+		saa_write_reg (addr, val);
+	}
+	return;
+}
+
+static void saa_init_regs(struct planb *pb)
+{
+	int i;
+
+	for (i = 0; i < SAA7196_NUMREGS; i++)
+		saa_write_reg (i, saa_regs[pb->win.norm][i]);
+}
+
+static unsigned int saa_geo_setup(int width, int height, int interlace, int bpp,
+	struct planb *pb)
+{
+	int ht, norm = pb->win.norm;
+
+	switch(bpp) {
+	case 2:
+		/* RGB555+a 1x16-bit + 16-bit transparent */
+		saa_regs[norm][SAA7196_FMTS] &= ~0x3;
+		break;
+	case 1:
+	case 4:
+		/* RGB888 1x24-bit + 8-bit transparent */
+		saa_regs[norm][SAA7196_FMTS] &= ~0x1;
+		saa_regs[norm][SAA7196_FMTS] |= 0x2;
+		break;
+	default:
+		return -EINVAL;
+	}
+	ht = (interlace ? height / 2 : height);
+	saa_regs[norm][SAA7196_OUTPIX] = (unsigned char) (width & 0x00ff);
+	saa_regs[norm][SAA7196_HFILT] = (saa_regs[norm][SAA7196_HFILT] & ~0x3)
+						| (width >> 8 & 0x3);
+	saa_regs[norm][SAA7196_OUTLINE] = (unsigned char) (ht & 0xff);
+	saa_regs[norm][SAA7196_VYP] = (saa_regs[norm][SAA7196_VYP] & ~0x3)
+						| (ht >> 8 & 0x3);
+	/* feed both fields if interlaced, or else feed only even fields */
+	saa_regs[norm][SAA7196_FMTS] = (interlace) ?
+					(saa_regs[norm][SAA7196_FMTS] & ~0x60)
+					: (saa_regs[norm][SAA7196_FMTS] | 0x60);
+	/* transparent mode; extended format enabled */
+	saa_regs[norm][SAA7196_DPATH] |= 0x3;
+
+	return 0;
+}
+
+/***************************/
+/* DBDMA support functions */
+/***************************/
+
+static inline void planb_dbdma_restart(volatile struct dbdma_regs *ch)
+{
+	out_le32(&ch->control, PLANB_CLR(RUN));
+	out_le32(&ch->control, PLANB_SET(RUN|WAKE) | PLANB_CLR(PAUSE));
+}
+
+static inline void planb_dbdma_stop(volatile struct dbdma_regs *ch)
+{
+	int i = 0;
+
+	out_le32(&ch->control, PLANB_CLR(RUN) | PLANB_SET(FLUSH));
+	while((in_le32(&ch->status) == (ACTIVE | FLUSH)) && (i < 999)) {
+		IDEBUG("PlanB: waiting for DMA to stop\n");
+		i++;
+	}
+}
+
+static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *ch,
+	unsigned short command, unsigned int cmd_dep)
+{
+	st_le16(&ch->command, command);
+	st_le32(&ch->cmd_dep, cmd_dep);
+}
+
+static inline void tab_cmd_store(volatile struct dbdma_cmd *ch,
+	unsigned int phy_addr, unsigned int cmd_dep)
+{
+	st_le16(&ch->command, STORE_WORD | KEY_SYSTEM);
+	st_le16(&ch->req_count, 4);
+	st_le32(&ch->phy_addr, phy_addr);
+	st_le32(&ch->cmd_dep, cmd_dep);
+}
+
+static inline void tab_cmd_gen(volatile struct dbdma_cmd *ch,
+	unsigned short command, unsigned short req_count,
+	unsigned int phy_addr, unsigned int cmd_dep)
+{
+	st_le16(&ch->command, command);
+	st_le16(&ch->req_count, req_count);
+	st_le32(&ch->phy_addr, phy_addr);
+	st_le32(&ch->cmd_dep, cmd_dep);
+}
+
+static volatile struct dbdma_cmd *cmd_geo_setup(
+	volatile struct dbdma_cmd *c1, int width, int height, int interlace,
+	int bpp, int clip, struct planb *pb)
+{
+	int norm = pb->win.norm;
+
+	if((saa_geo_setup(width, height, interlace, bpp, pb)) != 0)
+		return (volatile struct dbdma_cmd *)NULL;
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
+							SAA7196_FMTS);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
+					saa_regs[norm][SAA7196_FMTS]);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
+							SAA7196_DPATH);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
+					saa_regs[norm][SAA7196_DPATH]);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->even),
+					bpp | ((clip)? PLANB_CLIPMASK: 0));
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->odd),
+					bpp | ((clip)? PLANB_CLIPMASK: 0));
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
+							SAA7196_OUTPIX);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
+					saa_regs[norm][SAA7196_OUTPIX]);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
+							SAA7196_HFILT);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
+					saa_regs[norm][SAA7196_HFILT]);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
+							SAA7196_OUTLINE);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
+					saa_regs[norm][SAA7196_OUTLINE]);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr),
+							SAA7196_VYP);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval),
+					saa_regs[norm][SAA7196_VYP]);
+	return c1;
+}
+
+/******************************/
+/* misc. supporting functions */
+/******************************/
+
+static void __planb_wait(struct planb *pb)
+{
+	struct wait_queue wait = { current, NULL };
+
+	add_wait_queue(&pb->lockq, &wait);
+repeat:
+	current->state = TASK_UNINTERRUPTIBLE;
+	if (pb->lock) {
+		schedule();
+		goto repeat;
+	}
+	remove_wait_queue(&pb->lockq, &wait);
+	current->state = TASK_RUNNING;
+}
+
+static inline void planb_wait(struct planb *pb)
+{
+	DEBUG("PlanB: planb_wait\n");
+	if(pb->lock)
+		__planb_wait(pb);
+}
+
+static inline void planb_lock(struct planb *pb)
+{
+	DEBUG("PlanB: planb_lock\n");
+	if(pb->lock)
+		__planb_wait(pb);
+	pb->lock = 1;
+}
+
+static inline void planb_unlock(struct planb *pb)
+{
+	DEBUG("PlanB: planb_unlock\n");
+	pb->lock = 0;
+	wake_up(&pb->lockq);
+}
+
+/***************/
+/* Driver Core */
+/***************/
+
+static int planb_prepare_open(struct planb *pb)
+{
+	int	i, size;
+
+	/* allocate memory for two plus alpha command buffers (size: max lines,
+	   plus 40 commands handling, plus 1 alignment), plus dummy command buf,
+	   plus clipmask buffer, plus frame grabbing status */
+	size = (pb->tab_size*(2+MAX_GBUFFERS*TAB_FACTOR)+1+MAX_GBUFFERS
+		* PLANB_DUMMY)*sizeof(struct dbdma_cmd)
+		+(PLANB_MAXLINES*((PLANB_MAXPIXELS+7)& ~7))/8
+		+MAX_GBUFFERS*sizeof(unsigned int);
+	if ((pb->priv_space = kmalloc (size, GFP_KERNEL)) == 0)
+		return -ENOMEM;
+	memset ((void *) pb->priv_space, 0, size);
+	pb->overlay_last1 = pb->ch1_cmd = (volatile struct dbdma_cmd *)
+						DBDMA_ALIGN (pb->priv_space);
+	pb->overlay_last2 = pb->ch2_cmd = pb->ch1_cmd + pb->tab_size;
+	pb->ch1_cmd_phys = virt_to_bus(pb->ch1_cmd);
+	pb->cap_cmd[0] = pb->ch2_cmd + pb->tab_size;
+	pb->pre_cmd[0] = pb->cap_cmd[0] + pb->tab_size * TAB_FACTOR;
+	for (i = 1; i < MAX_GBUFFERS; i++) {
+		pb->cap_cmd[i] = pb->pre_cmd[i-1] + PLANB_DUMMY;
+		pb->pre_cmd[i] = pb->cap_cmd[i] + pb->tab_size * TAB_FACTOR;
+	}
+	pb->frame_stat=(volatile unsigned int *)(pb->pre_cmd[MAX_GBUFFERS-1]
+						+ PLANB_DUMMY);
+	pb->mask = (unsigned char *)(pb->frame_stat+MAX_GBUFFERS);
+
+	pb->fbuffer = (unsigned char *)rvmalloc(MAX_GBUFFERS * PLANB_MAX_FBUF);
+	if (!pb->fbuffer) {
+		kfree(pb->priv_space);
+		return -ENOMEM;
+	}
+	pb->grabbing = 0;
+	for (i = 0; i < MAX_GBUFFERS; i++) {
+		pb->frame_stat[i] = GBUFFER_UNUSED;
+		pb->gwidth[i] = 0;
+		pb->gheight[i] = 0;
+		pb->gfmt[i] = 0;
+		pb->gnorm_switch[i] = 0;
+#ifndef PLANB_GSCANLINE
+		pb->lsize[i] = 0;
+		pb->lnum[i] = 0;
+		pb->l_fr_addr[i]=(unsigned char *)rvmalloc(PAGE_SIZE*MAX_LNUM);
+		if (!pb->l_fr_addr[i]) {
+			int j;
+			kfree(pb->priv_space);
+			rvfree((void *)pb->fbuffer, MAX_GBUFFERS
+							* PLANB_MAX_FBUF);
+			for(j = 0; j < i; j++)
+				rvfree((void *)pb->l_fr_addr[j], PAGE_SIZE
+								* MAX_LNUM);
+			return -ENOMEM;
+		}
+#endif /* PLANB_GSCANLINE */
+	}
+	pb->gcount = 0;
+	pb->suspend = 0;
+	pb->last_fr = -999;
+	pb->prev_last_fr = -999;
+	return 0;   
+}
+
+static void planb_prepare_close(struct planb *pb)
+{
+#ifndef PLANB_GSCANLINE
+	int i;
+#endif
+
+	/* make sure the dma's are idle */
+	planb_dbdma_stop(&pb->planb_base->ch2);
+	planb_dbdma_stop(&pb->planb_base->ch1);
+	/* free kernel memory of command buffers */
+	if(pb->priv_space != 0) {
+		kfree (pb->priv_space);
+		pb->priv_space = 0;
+		pb->cmd_buff_inited = 0;
+	}
+	if(pb->fbuffer)
+		rvfree((void *)pb->fbuffer, MAX_GBUFFERS*PLANB_MAX_FBUF);
+	pb->fbuffer = NULL;
+#ifndef PLANB_GSCANLINE
+	for(i = 0; i < MAX_GBUFFERS; i++) {
+		if(pb->l_fr_addr[i])
+			rvfree((void *)pb->l_fr_addr[i], PAGE_SIZE * MAX_LNUM);
+		pb->l_fr_addr[i] = NULL;
+	}
+#endif /* PLANB_GSCANLINE */
+}
+
+/*****************************/
+/* overlay support functions */
+/*****************************/
+
+static void overlay_start(struct planb *pb)
+{
+
+	DEBUG("PlanB: overlay_start()\n");
+
+	if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
+
+		DEBUG("PlanB: presumably, grabbing is in progress...\n");
+
+		planb_dbdma_stop(&pb->planb_base->ch2);
+		out_le32 (&pb->planb_base->ch2.cmdptr,
+						virt_to_bus(pb->ch2_cmd));
+		planb_dbdma_restart(&pb->planb_base->ch2);
+		st_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
+		tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
+					DBDMA_NOP | BR_ALWAYS,
+					virt_to_bus(pb->ch1_cmd));
+		eieio();
+		pb->prev_last_fr = pb->last_fr;
+		pb->last_fr = -2;
+		if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
+			IDEBUG("PlanB: became inactive "
+				"in the mean time... reactivating\n");
+			planb_dbdma_stop(&pb->planb_base->ch1);
+			out_le32 (&pb->planb_base->ch1.cmdptr,
+						virt_to_bus(pb->ch1_cmd));
+			planb_dbdma_restart(&pb->planb_base->ch1);
+		}
+	} else {
+
+		DEBUG("PlanB: currently idle, so can do whatever\n");
+
+		planb_dbdma_stop(&pb->planb_base->ch2);
+		planb_dbdma_stop(&pb->planb_base->ch1);
+		st_le32 (&pb->planb_base->ch2.cmdptr,
+						virt_to_bus(pb->ch2_cmd));
+		st_le32 (&pb->planb_base->ch1.cmdptr,
+						virt_to_bus(pb->ch1_cmd));
+		out_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
+		planb_dbdma_restart(&pb->planb_base->ch2);
+		planb_dbdma_restart(&pb->planb_base->ch1);
+		pb->last_fr = -1;
+	}
+	return;
+}
+
+static void overlay_stop(struct planb *pb)
+{
+	DEBUG("PlanB: overlay_stop()\n");
+
+	if(pb->last_fr == -1) {
+
+		DEBUG("PlanB: no grabbing, it seems...\n");
+
+		planb_dbdma_stop(&pb->planb_base->ch2);
+		planb_dbdma_stop(&pb->planb_base->ch1);
+		pb->last_fr = -999;
+	} else if(pb->last_fr == -2) {
+		unsigned int cmd_dep;
+		tab_cmd_dbdma(pb->cap_cmd[pb->prev_last_fr], DBDMA_STOP, 0);
+		eieio();
+		cmd_dep = (unsigned int)in_le32(&pb->overlay_last1->cmd_dep);
+		if(overlay_is_active(pb)) {
+
+			DEBUG("PlanB: overlay is currently active\n");
+
+			planb_dbdma_stop(&pb->planb_base->ch2);
+			planb_dbdma_stop(&pb->planb_base->ch1);
+			if(cmd_dep != pb->ch1_cmd_phys) {
+				out_le32(&pb->planb_base->ch1.cmdptr,
+						virt_to_bus(pb->overlay_last1));
+				planb_dbdma_restart(&pb->planb_base->ch1);
+			}
+		}
+		pb->last_fr = pb->prev_last_fr;
+		pb->prev_last_fr = -999;
+	}
+	return;
+}
+
+static void suspend_overlay(struct planb *pb)
+{
+	int fr = -1;
+	struct dbdma_cmd last;
+
+	DEBUG("PlanB: suspend_overlay: %d\n", pb->suspend);
+
+	if(pb->suspend++)
+		return;
+	if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
+		if(pb->last_fr == -2) {
+			fr = pb->prev_last_fr;
+			memcpy(&last, (void*)pb->last_cmd[fr], sizeof(last));
+			tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
+		}
+		if(overlay_is_active(pb)) {
+			planb_dbdma_stop(&pb->planb_base->ch2);
+			planb_dbdma_stop(&pb->planb_base->ch1);
+			pb->suspended.overlay = 1;
+			pb->suspended.frame = fr;
+			memcpy(&pb->suspended.cmd, &last, sizeof(last));
+			return;
+		}
+	}
+	pb->suspended.overlay = 0;
+	pb->suspended.frame = fr;
+	memcpy(&pb->suspended.cmd, &last, sizeof(last));
+	return;
+}
+
+static void resume_overlay(struct planb *pb)
+{
+
+	DEBUG("PlanB: resume_overlay: %d\n", pb->suspend);
+
+	if(pb->suspend > 1)
+		return;
+	if(pb->suspended.frame != -1) {
+		memcpy((void*)pb->last_cmd[pb->suspended.frame],
+				&pb->suspended.cmd, sizeof(pb->suspended.cmd));
+	}
+	if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) {
+		goto finish;
+	}
+	if(pb->suspended.overlay) {
+
+		DEBUG("PlanB: overlay being resumed\n");
+
+		st_le16 (&pb->ch1_cmd->command, DBDMA_NOP);
+		st_le16 (&pb->ch2_cmd->command, DBDMA_NOP);
+		/* Set command buffer addresses */
+		st_le32(&pb->planb_base->ch1.cmdptr,
+					virt_to_bus(pb->overlay_last1));
+		out_le32(&pb->planb_base->ch2.cmdptr,
+					virt_to_bus(pb->overlay_last2));
+		/* Start the DMA controller */
+		out_le32 (&pb->planb_base->ch2.control,
+				PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
+		out_le32 (&pb->planb_base->ch1.control,
+				PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
+	} else if(pb->suspended.frame != -1) {
+		out_le32(&pb->planb_base->ch1.cmdptr,
+				virt_to_bus(pb->last_cmd[pb->suspended.frame]));
+		out_le32 (&pb->planb_base->ch1.control,
+				PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE));
+	}
+
+finish:
+	pb->suspend--;
+	wake_up_interruptible(&pb->suspendq);
+}
+
+static void add_clip(struct planb *pb, struct video_clip *clip) 
+{
+	volatile unsigned char	*base;
+	int	xc = clip->x, yc = clip->y;
+	int	wc = clip->width, hc = clip->height;
+	int	ww = pb->win.width, hw = pb->win.height;
+	int	x, y, xtmp1, xtmp2;
+
+	DEBUG("PlanB: clip %dx%d+%d+%d\n", wc, hc, xc, yc);
+
+	if(xc < 0) {
+		wc += xc;
+		xc = 0;
+	}
+	if(yc < 0) {
+		hc += yc;
+		yc = 0;
+	}
+	if(xc + wc > ww)
+		wc = ww - xc;
+	if(wc <= 0) /* Nothing to do */
+		return;
+	if(yc + hc > hw)
+		hc = hw - yc;
+
+	for (y = yc; y < yc+hc; y++) {
+		xtmp1=xc>>3;
+		xtmp2=(xc+wc)>>3;
+		base = pb->mask + y*96;
+		if(xc != 0 || wc >= 8)
+			*(base + xtmp1) &= (unsigned char)(0x00ff &
+				(0xff00 >> (xc&7)));
+		for (x = xtmp1 + 1; x < xtmp2; x++) {
+			*(base + x) = 0;
+		}
+		if(xc < (ww & ~0x7))
+			*(base + xtmp2) &= (unsigned char)(0x00ff >>
+				((xc+wc) & 7));
+	}
+
+	return;
+}
+
+static void fill_cmd_buff(struct planb *pb)
+{
+	int restore = 0;
+	volatile struct dbdma_cmd last;
+
+	DEBUG("PlanB: fill_cmd_buff()\n");
+
+	if(pb->overlay_last1 != pb->ch1_cmd) {
+		restore = 1;
+		last = *(pb->overlay_last1);
+	}
+	memset ((void *) pb->ch1_cmd, 0, 2 * pb->tab_size
+					* sizeof(struct dbdma_cmd));
+	cmd_buff (pb);
+	if(restore)
+		*(pb->overlay_last1) = last;
+	if(pb->suspended.overlay) {
+		unsigned long jump_addr = in_le32(&pb->overlay_last1->cmd_dep);
+		if(jump_addr != pb->ch1_cmd_phys) {
+			int i;
+
+			DEBUG("PlanB: adjusting ch1's jump address\n");
+
+			for(i = 0; i < MAX_GBUFFERS; i++) {
+				if(pb->need_pre_capture[i]) {
+				    if(jump_addr == virt_to_bus(pb->pre_cmd[i]))
+					goto found;
+				} else {
+				    if(jump_addr == virt_to_bus(pb->cap_cmd[i]))
+					goto found;
+				}
+			}
+
+			DEBUG("PlanB: not found...\n");
+
+			goto out;
+found:
+			if(pb->need_pre_capture[i])
+				out_le32(&pb->pre_cmd[i]->phy_addr,
+						virt_to_bus(pb->overlay_last1));
+			else
+				out_le32(&pb->cap_cmd[i]->phy_addr,
+						virt_to_bus(pb->overlay_last1));
+		}
+	}
+out:
+	pb->cmd_buff_inited = 1;
+
+	return;
+}
+
+static void cmd_buff(struct planb *pb)
+{
+	int		i, bpp, count, nlines, stepsize, interlace;
+	unsigned long	base, jump, addr_com, addr_dep;
+	volatile struct dbdma_cmd *c1 = pb->ch1_cmd;
+	volatile struct dbdma_cmd *c2 = pb->ch2_cmd;
+
+	interlace = pb->win.interlace;
+	bpp = pb->win.bpp;
+	count = (bpp * ((pb->win.x + pb->win.width > pb->win.swidth) ?
+		(pb->win.swidth - pb->win.x) : pb->win.width));
+	nlines = ((pb->win.y + pb->win.height > pb->win.sheight) ?
+		(pb->win.sheight - pb->win.y) : pb->win.height);
+
+	/* Do video in: */
+
+	/* Preamble commands: */
+	addr_com = virt_to_bus(c1);
+	addr_dep = virt_to_bus(&c1->cmd_dep);
+	tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
+	jump = virt_to_bus(c1+16); /* 14 by cmd_geo_setup() and 2 for padding */
+	if((c1 = cmd_geo_setup(c1, pb->win.width, pb->win.height, interlace,
+					bpp, 1, pb)) == NULL) {
+		printk(KERN_WARNING "PlanB: encountered serious problems\n");
+		tab_cmd_dbdma(pb->ch1_cmd + 1, DBDMA_STOP, 0);
+		tab_cmd_dbdma(pb->ch2_cmd + 1, DBDMA_STOP, 0);
+		return;
+	}
+	tab_cmd_store(c1++, addr_com, (unsigned)(DBDMA_NOP | BR_ALWAYS) << 16);
+	tab_cmd_store(c1++, addr_dep, jump);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
+							PLANB_SET(FIELD_SYNC));
+		/* (1) wait for field sync to be set */
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+							PLANB_SET(ODD_FIELD));
+		/* wait for field sync to be cleared */
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
+		/* if not odd field, wait until field sync is set again */
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
+		/* assert ch_sync to ch2 */
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control),
+							PLANB_SET(CH_SYNC));
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+							PLANB_SET(DMA_ABORT));
+
+	base = (pb->frame_buffer_phys + pb->offset + pb->win.y * (pb->win.bpl
+					+ pb->win.pad) + pb->win.x * bpp);
+
+	if (interlace) {
+		stepsize = 2;
+		jump = virt_to_bus(c1 + (nlines + 1) / 2);
+	} else {
+		stepsize = 1;
+		jump = virt_to_bus(c1 + nlines);
+	}
+
+	/* even field data: */
+	for (i=0; i < nlines; i += stepsize, c1++)
+		tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET,
+			count, base + i * (pb->win.bpl + pb->win.pad), jump);
+
+	/* For non-interlaced, we use even fields only */
+	if (!interlace)
+		goto cmd_tab_data_end;
+
+	/* Resync to odd field */
+		/* (2) wait for field sync to be set */
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+							PLANB_SET(ODD_FIELD));
+		/* wait for field sync to be cleared */
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
+		/* if not odd field, wait until field sync is set again */
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
+		/* assert ch_sync to ch2 */
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control),
+							PLANB_SET(CH_SYNC));
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+							PLANB_SET(DMA_ABORT));
+	
+	/* odd field data: */
+	jump = virt_to_bus(c1 + nlines / 2);
+	for (i=1; i < nlines; i += stepsize, c1++)
+		tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
+			base + i * (pb->win.bpl + pb->win.pad), jump);
+
+	/* And jump back to the start */
+cmd_tab_data_end:
+	pb->overlay_last1 = c1;	/* keep a pointer to the last command */
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch1_cmd));
+
+	/* Clipmask command buffer */
+
+	/* Preamble commands: */
+	tab_cmd_dbdma(c2++, DBDMA_NOP, 0);
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel),
+							PLANB_SET(CH_SYNC));
+		/* wait until ch1 asserts ch_sync */
+	tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0);
+		/* clear ch_sync asserted by ch1 */
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.control),
+							PLANB_CLR(CH_SYNC));
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel),
+							PLANB_SET(FIELD_SYNC));
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
+							PLANB_SET(ODD_FIELD));
+
+	/* jump to end of even field if appropriate */
+	/* this points to (interlace)? pos. C: pos. B */
+	jump = (interlace) ? virt_to_bus(c2 + (nlines + 1) / 2 + 2):
+						virt_to_bus(c2 + nlines + 2);
+		/* if odd field, skip over to odd field clipmasking */
+	tab_cmd_dbdma(c2++, DBDMA_NOP | BR_IFSET, jump);
+
+	/* even field mask: */
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
+							PLANB_SET(DMA_ABORT));
+	/* this points to pos. B */
+	jump = (interlace) ? virt_to_bus(c2 + nlines + 1):
+						virt_to_bus(c2 + nlines);
+	base = virt_to_bus(pb->mask);
+	for (i=0; i < nlines; i += stepsize, c2++)
+		tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96,
+			base + i * 96, jump);
+
+	/* For non-interlaced, we use only even fields */
+	if(!interlace)
+		goto cmd_tab_mask_end;
+
+	/* odd field mask: */
+/* C */	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel),
+							PLANB_SET(DMA_ABORT));
+	/* this points to pos. B */
+	jump = virt_to_bus(c2 + nlines / 2);
+	base = virt_to_bus(pb->mask);
+	for (i=1; i < nlines; i += 2, c2++)     /* abort if set */
+		tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96,
+			base + i * 96, jump);
+
+	/* Inform channel 1 and jump back to start */
+cmd_tab_mask_end:
+	/* ok, I just realized this is kind of flawed. */
+	/* this part is reached only after odd field clipmasking. */
+	/* wanna clean up? */
+		/* wait for field sync to be set */
+		/* corresponds to fsync (1) of ch1 */
+/* B */	tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0);
+		/* restart ch1, meant to clear any dead bit or something */
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control),
+							PLANB_CLR(RUN));
+	tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control),
+							PLANB_SET(RUN));
+	pb->overlay_last2 = c2;	/* keep a pointer to the last command */
+		/* start over even field clipmasking */
+	tab_cmd_dbdma(c2, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch2_cmd));
+
+	eieio();
+	return;
+}
+
+/*********************************/
+/* grabdisplay support functions */
+/*********************************/
+
+static int palette2fmt[] = {
+       0,
+       PLANB_GRAY,
+       0,
+       0,
+       0,
+       PLANB_COLOUR32,
+       PLANB_COLOUR15,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+       0,
+};
+#define PLANB_PALETTE_MAX 15
+
+#define SWAP4(x) (((x>>24) & 0x000000ff) |\
+                  ((x>>8)  & 0x0000ff00) |\
+                  ((x<<8)  & 0x00ff0000) |\
+                  ((x<<24) & 0xff000000))
+
+static inline int overlay_is_active(struct planb *pb)
+{
+	unsigned int size = pb->tab_size * sizeof(struct dbdma_cmd);
+	unsigned int caddr = (unsigned)in_le32(&pb->planb_base->ch1.cmdptr);
+
+	return (in_le32(&pb->overlay_last1->cmd_dep) == pb->ch1_cmd_phys)
+			&& (caddr < (pb->ch1_cmd_phys + size))
+			&& (caddr >= (unsigned)pb->ch1_cmd_phys);
+}
+
+static int vgrab(struct planb *pb, struct video_mmap *mp)
+{
+	unsigned int fr = mp->frame;
+	unsigned int format;
+
+	if(pb->fbuffer==NULL) {
+		if(fbuffer_alloc(pb))
+			return -ENOBUFS;
+	}
+
+	IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb->grabbing,
+						mp->width, mp->height, fr);
+
+	if(pb->grabbing >= MAX_GBUFFERS)
+		return -ENOBUFS;
+	if(fr > (MAX_GBUFFERS - 1) || fr < 0)
+		return -EINVAL;
+	if(mp->height <= 0 || mp->width <= 0)
+		return -EINVAL;
+	if(mp->format < 0 || mp->format >= PLANB_PALETTE_MAX)
+		return -EINVAL;
+	if((format = palette2fmt[mp->format]) == 0)
+		return -EINVAL;
+	if (mp->height * mp->width * format > PLANB_MAX_FBUF) /* format = bpp */
+		return -EINVAL;
+
+	planb_lock(pb);
+	pb->gbuffer[fr] = (unsigned char *)(pb->fbuffer + PLANB_MAX_FBUF * fr);
+	if(mp->width != pb->gwidth[fr] || mp->height != pb->gheight[fr] ||
+			format != pb->gfmt[fr] || (pb->gnorm_switch[fr])) {
+#ifdef PLANB_GSCANLINE
+		int i;
+#else
+		unsigned int osize = pb->gwidth[fr] * pb->gheight[fr]
+								* pb->gfmt[fr];
+		unsigned int nsize = mp->width * mp->height * format;
+#endif
+
+		IDEBUG("PlanB: gwidth = %d, gheight = %d, mp->format = %u\n",
+					mp->width, mp->height, mp->format);
+
+#ifndef PLANB_GSCANLINE
+		if(pb->gnorm_switch[fr])
+			nsize = 0;
+		if(nsize < osize)
+			memset((void *)(pb->gbuffer[fr] + nsize), 0,
+								osize - nsize);
+		memset((void *)pb->l_fr_addr[fr], 0, PAGE_SIZE * pb->lnum[fr]);
+#else
+/* XXX TODO */
+/*
+		if(pb->gnorm_switch[fr])
+			memset((void *)pb->gbuffer[fr], 0,
+					pb->gbytes_per_line * pb->gheight[fr]);
+		else {
+			if(mp->
+			for(i = 0; i < pb->gheight[fr]; i++) {
+				memset((void *)(pb->gbuffer[fr]
+					+ pb->gbytes_per_line * i
+			}
+		}
+*/
+#endif
+		pb->gwidth[fr] = mp->width;
+		pb->gheight[fr] = mp->height;
+		pb->gfmt[fr] = format;
+		pb->last_cmd[fr] = setup_grab_cmd(fr, pb);
+		planb_pre_capture(fr, pb->gfmt[fr], pb); /* gfmt = bpp */
+		pb->need_pre_capture[fr] = 1;
+		pb->gnorm_switch[fr] = 0;
+	} else
+		pb->need_pre_capture[fr] = 0;
+	pb->frame_stat[fr] = GBUFFER_GRABBING;
+	if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
+
+		IDEBUG("PlanB: ch1 inactive, initiating grabbing\n");
+
+		planb_dbdma_stop(&pb->planb_base->ch1);
+		if(pb->need_pre_capture[fr]) {
+
+			IDEBUG("PlanB: padding pre-capture sequence\n");
+
+			out_le32 (&pb->planb_base->ch1.cmdptr,
+						virt_to_bus(pb->pre_cmd[fr]));
+		} else {
+			tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
+			tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0);
+		/* let's be on the safe side. here is not timing critical. */
+			tab_cmd_dbdma((pb->cap_cmd[fr] + 1), DBDMA_NOP, 0);
+			out_le32 (&pb->planb_base->ch1.cmdptr,
+						virt_to_bus(pb->cap_cmd[fr]));
+		}
+		planb_dbdma_restart(&pb->planb_base->ch1);
+		pb->last_fr = fr;
+	} else {
+		int i;
+
+		IDEBUG("PlanB: ch1 active, grabbing being queued\n");
+
+		if((pb->last_fr == -1) || ((pb->last_fr == -2) &&
+						overlay_is_active(pb))) {
+
+			IDEBUG("PlanB: overlay is active, grabbing defered\n");
+
+			tab_cmd_dbdma(pb->last_cmd[fr],
+					DBDMA_NOP | BR_ALWAYS,
+					virt_to_bus(pb->ch1_cmd));
+			if(pb->need_pre_capture[fr]) {
+
+				IDEBUG("PlanB: padding pre-capture sequence\n");
+
+				tab_cmd_store(pb->pre_cmd[fr],
+				    virt_to_bus(&pb->overlay_last1->cmd_dep),
+						virt_to_bus(pb->ch1_cmd));
+				eieio();
+				out_le32 (&pb->overlay_last1->cmd_dep,
+						virt_to_bus(pb->pre_cmd[fr]));
+			} else {
+				tab_cmd_store(pb->cap_cmd[fr],
+				    virt_to_bus(&pb->overlay_last1->cmd_dep),
+						virt_to_bus(pb->ch1_cmd));
+				tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
+								DBDMA_NOP, 0);
+				eieio();
+				out_le32 (&pb->overlay_last1->cmd_dep,
+						virt_to_bus(pb->cap_cmd[fr]));
+			}
+			for(i = 0; overlay_is_active(pb) && i < 999; i++)
+				IDEBUG("PlanB: waiting for overlay done\n");
+			tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0);
+			pb->prev_last_fr = fr;
+			pb->last_fr = -2;
+		} else if(pb->last_fr == -2) {
+
+			IDEBUG("PlanB: mixed mode detected, grabbing"
+				" will be done before activating overlay\n");
+
+			tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0);
+			if(pb->need_pre_capture[fr]) {
+
+				IDEBUG("PlanB: padding pre-capture sequence\n");
+
+				tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr],
+						DBDMA_NOP | BR_ALWAYS,
+						virt_to_bus(pb->pre_cmd[fr]));
+				eieio();
+			} else {
+				tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0);
+				if(pb->gwidth[pb->prev_last_fr] !=
+								pb->gwidth[fr]
+					|| pb->gheight[pb->prev_last_fr] !=
+								pb->gheight[fr]
+					|| pb->gfmt[pb->prev_last_fr] !=
+								pb->gfmt[fr])
+					tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
+								DBDMA_NOP, 0);
+				else
+					tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
+					    DBDMA_NOP | BR_ALWAYS,
+					    virt_to_bus(pb->cap_cmd[fr] + 16));
+				tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr],
+						DBDMA_NOP | BR_ALWAYS,
+						virt_to_bus(pb->cap_cmd[fr]));
+				eieio();
+			}
+			tab_cmd_dbdma(pb->last_cmd[fr],
+					DBDMA_NOP | BR_ALWAYS,
+					virt_to_bus(pb->ch1_cmd));
+			eieio();
+			pb->prev_last_fr = fr;
+			pb->last_fr = -2;
+		} else {
+
+			IDEBUG("PlanB: active grabbing session detected\n");
+
+			if(pb->need_pre_capture[fr]) {
+
+				IDEBUG("PlanB: padding pre-capture sequence\n");
+
+				tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
+						DBDMA_NOP | BR_ALWAYS,
+						virt_to_bus(pb->pre_cmd[fr]));
+				eieio();
+			} else {
+				tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0);
+				tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0);
+				if(pb->gwidth[pb->last_fr] != pb->gwidth[fr]
+					|| pb->gheight[pb->last_fr] !=
+								pb->gheight[fr]
+					|| pb->gfmt[pb->last_fr] !=
+								pb->gfmt[fr])
+					tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
+								DBDMA_NOP, 0);
+				else
+					tab_cmd_dbdma((pb->cap_cmd[fr] + 1),
+					    DBDMA_NOP | BR_ALWAYS,
+					    virt_to_bus(pb->cap_cmd[fr] + 16));
+				tab_cmd_dbdma(pb->last_cmd[pb->last_fr],
+						DBDMA_NOP | BR_ALWAYS,
+						virt_to_bus(pb->cap_cmd[fr]));
+				eieio();
+			}
+			pb->last_fr = fr;
+		}
+		if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) {
+
+			IDEBUG("PlanB: became inactive in the mean time..."
+				"reactivating\n");
+
+			planb_dbdma_stop(&pb->planb_base->ch1);
+			out_le32 (&pb->planb_base->ch1.cmdptr,
+						virt_to_bus(pb->cap_cmd[fr]));
+			planb_dbdma_restart(&pb->planb_base->ch1);
+		}
+	}
+	pb->grabbing++;
+	planb_unlock(pb);
+
+	return 0;
+}
+
+static void planb_pre_capture(int fr, int bpp, struct planb *pb)
+{
+	volatile struct dbdma_cmd *c1 = pb->pre_cmd[fr];
+	int interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0;
+
+	tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
+	if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace,
+						bpp, 0, pb)) == NULL) {
+		printk(KERN_WARNING "PlanB: encountered some problems\n");
+		tab_cmd_dbdma(pb->pre_cmd[fr] + 1, DBDMA_STOP, 0);
+		return;
+	}
+	/* Sync to even field */
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
+		PLANB_SET(FIELD_SYNC));
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+		PLANB_SET(ODD_FIELD));
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
+	tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+		PLANB_SET(DMA_ABORT));
+	/* For non-interlaced, we use even fields only */
+	if (pb->gheight[fr] <= pb->maxlines/2)
+		goto cmd_tab_data_end;
+	/* Sync to odd field */
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+		PLANB_SET(ODD_FIELD));
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+		PLANB_SET(DMA_ABORT));
+cmd_tab_data_end:
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->cap_cmd[fr]));
+
+	eieio();
+}
+
+static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb)
+{
+	int		i, bpp, count, nlines, stepsize, interlace;
+#ifdef PLANB_GSCANLINE
+	int		scanline;
+#else
+	int		nlpp, leftover1;
+	unsigned long	base;
+#endif
+	unsigned long	jump;
+	unsigned char	*vaddr;
+	volatile struct dbdma_cmd *c1;
+	volatile struct dbdma_cmd *jump_addr;
+
+	c1 = pb->cap_cmd[fr];
+	interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0;
+	bpp = pb->gfmt[fr];	/* gfmt = bpp */
+	count = bpp * pb->gwidth[fr];
+	nlines = pb->gheight[fr];
+#ifdef PLANB_GSCANLINE
+	scanline = pb->gbytes_per_line;
+#else
+	pb->lsize[fr] = count;
+	pb->lnum[fr] = 0;
+#endif
+
+	/* Do video in: */
+
+	/* Preamble commands: */
+	tab_cmd_dbdma(c1++, DBDMA_NOP, 0);
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(c1 + 16)); c1++;
+	if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace,
+						bpp, 0, pb)) == NULL) {
+		printk(KERN_WARNING "PlanB: encountered serious problems\n");
+		tab_cmd_dbdma(pb->cap_cmd[fr] + 1, DBDMA_STOP, 0);
+		return (pb->cap_cmd[fr] + 2);
+	}
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel),
+		PLANB_SET(FIELD_SYNC));
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+		PLANB_SET(ODD_FIELD));
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++;
+	tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+		PLANB_SET(DMA_ABORT));
+
+	if (interlace) {
+		stepsize = 2;
+		jump_addr = c1 + TAB_FACTOR * (nlines + 1) / 2;
+	} else {
+		stepsize = 1;
+		jump_addr = c1 + TAB_FACTOR * nlines;
+	}
+	jump = virt_to_bus(jump_addr);
+
+	/* even field data: */
+
+	vaddr = pb->gbuffer[fr];
+#ifdef PLANB_GSCANLINE
+	for (i = 0; i < nlines; i += stepsize) {
+		tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
+				vmalloc_to_bus(vaddr + i * scanline), jump);
+	}
+#else
+	i = 0;
+	leftover1 = 0;
+	do {
+	    int j;
+
+	    base = vmalloc_to_bus((void*)vaddr);
+	    nlpp = (PAGE_SIZE - leftover1) / count / stepsize;
+	    for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++)
+		tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET,
+			  count, base + count * j * stepsize + leftover1, jump);
+	    if(i < nlines) {
+		int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1;
+
+		if(lov0 == 0)
+		    leftover1 = 0;
+		else {
+		    if(lov0 >= count) {
+			tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, base
+				+ count * nlpp * stepsize + leftover1, jump);
+		    } else {
+			pb->l_to_addr[fr][pb->lnum[fr]] = vaddr + count * nlpp
+							* stepsize + leftover1;
+			tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
+				vmalloc_to_bus(pb->l_fr_addr[fr] + PAGE_SIZE
+							* pb->lnum[fr]), jump);
+			if(++pb->lnum[fr] > MAX_LNUM)
+				pb->lnum[fr]--;
+		    }
+		    leftover1 = count * stepsize - lov0;
+		    i += stepsize;
+		}
+	    }
+	    vaddr += PAGE_SIZE;
+	} while(i < nlines);
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump);
+	c1 = jump_addr;
+#endif /* PLANB_GSCANLINE */
+
+	/* For non-interlaced, we use even fields only */
+	if (!interlace)
+		goto cmd_tab_data_end;
+
+	/* Sync to odd field */
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0);
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+		PLANB_SET(ODD_FIELD));
+	tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0);
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++;
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel),
+		PLANB_SET(DMA_ABORT));
+	
+	/* odd field data: */
+	jump_addr = c1 + TAB_FACTOR * nlines / 2;
+	jump = virt_to_bus(jump_addr);
+#ifdef PLANB_GSCANLINE
+	for (i = 1; i < nlines; i += stepsize) {
+		tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
+				vmalloc_to_bus(vaddr + i * scanline), jump);
+	}
+#else
+	i = 1;
+	leftover1 = 0;
+	vaddr = pb->gbuffer[fr];
+	if(nlines <= 1)
+	    goto skip;
+	do {
+	    int j;
+
+	    base = vmalloc_to_bus((void*)vaddr);
+	    nlpp = (PAGE_SIZE - leftover1) / count / stepsize;
+	    if(leftover1 >= count) {
+		tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
+						base + leftover1 - count, jump);
+		i += stepsize;
+	    }
+	    for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++)
+		tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count,
+			base + count * (j * stepsize + 1) + leftover1, jump);
+	    if(i < nlines) {
+		int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1;
+
+		if(lov0 == 0)
+		    leftover1 = 0;
+		else {
+		    if(lov0 > count) {
+			pb->l_to_addr[fr][pb->lnum[fr]] = vaddr + count
+					* (nlpp * stepsize + 1) + leftover1;
+			tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count,
+				vmalloc_to_bus(pb->l_fr_addr[fr] + PAGE_SIZE
+							* pb->lnum[fr]), jump);
+			if(++pb->lnum[fr] > MAX_LNUM)
+				pb->lnum[fr]--;
+			i += stepsize;
+		    }
+		    leftover1 = count * stepsize - lov0;
+		}
+	    }
+	    vaddr += PAGE_SIZE;
+	} while(i < nlines);
+skip:
+	tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump);
+	c1 = jump_addr;
+#endif /* PLANB_GSCANLINE */
+
+cmd_tab_data_end:
+	tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->intr_stat),
+			(fr << 2) | PLANB_FRM_IRQ | PLANB_GEN_IRQ);
+	/* stop it */
+	tab_cmd_dbdma(c1, DBDMA_STOP, 0);
+
+	eieio();
+	return c1;
+}
+
+static void planb_irq(int irq, void *dev_id, struct pt_regs * regs)
+{
+	unsigned int stat, astat;
+	struct planb *pb = (struct planb *)dev_id;
+
+	IDEBUG("PlanB: planb_irq()\n");
+
+	/* get/clear interrupt status bits */
+	stat = in_le32(&pb->planb_base->intr_stat);
+	astat = stat & pb->intr_mask;
+	out_le32(&pb->planb_base->intr_stat, PLANB_IRQ_CMD_MASK
+					& ~astat & stat & ~PLANB_GEN_IRQ);
+
+	if(astat & PLANB_FRM_IRQ) {
+		unsigned int fr = stat >> 2;
+#ifndef PLANB_GSCANLINE
+		int i;
+#endif
+		IDEBUG("PlanB: PLANB_FRM_IRQ\n");
+
+		pb->gcount++;
+
+		IDEBUG("PlanB: grab %d: fr = %d, gcount = %d\n",
+				pb->grabbing, fr, pb->gcount);
+#ifndef PLANB_GSCANLINE
+		IDEBUG("PlanB: %d * %d bytes are being copied over\n",
+				pb->lnum[fr], pb->lsize[fr]);
+		for(i = 0; i < pb->lnum[fr]; i++)
+			memcpy(pb->l_to_addr[fr][i], pb->l_fr_addr[fr]
+					+ PAGE_SIZE * i, pb->lsize[fr]);
+#endif
+		pb->frame_stat[fr] = GBUFFER_DONE;
+		pb->grabbing--;
+		wake_up_interruptible(&pb->capq);
+		return;
+	}
+	/* incorrect interrupts? */
+	pb->intr_mask = PLANB_CLR_IRQ;
+	out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
+	printk(KERN_ERR "PlanB: IRQ lockup, cleared intrrupts"
+							" unconditionally\n");
+}
+
+/*******************************
+ * Device Operations functions *
+ *******************************/
+
+static int planb_open(struct video_device *dev, int mode)
+{
+	struct planb *pb = (struct planb *)dev;
+
+	if (pb->user == 0) {
+		int err;
+		if((err = planb_prepare_open(pb)) != 0)
+			return err;
+	}
+	pb->user++;
+
+	DEBUG("PlanB: device opened\n");
+
+	MOD_INC_USE_COUNT;
+	return 0;   
+}
+
+static void planb_close(struct video_device *dev)
+{
+	struct planb *pb = (struct planb *)dev;
+
+	if(pb->user < 1) /* ??? */
+		return;
+	planb_lock(pb);
+	if (pb->user == 1) {
+		if (pb->overlay) {
+			planb_dbdma_stop(&pb->planb_base->ch2);
+			planb_dbdma_stop(&pb->planb_base->ch1);
+			pb->overlay = 0;
+		}
+		planb_prepare_close(pb);
+	}
+	pb->user--;
+	planb_unlock(pb);
+
+	DEBUG("PlanB: device closed\n");
+
+	MOD_DEC_USE_COUNT;  
+}
+
+static long planb_read(struct video_device *v, char *buf, unsigned long count,
+				int nonblock)
+{
+	DEBUG("planb: read request\n");
+	return -EINVAL;
+}
+
+static long planb_write(struct video_device *v, const char *buf,
+				unsigned long count, int nonblock)
+{
+	DEBUG("planb: write request\n");
+	return -EINVAL;
+}
+
+static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+	struct planb *pb=(struct planb *)dev;
+  	
+	switch (cmd)
+	{	
+		case VIDIOCGCAP:
+		{
+			struct video_capability b;
+
+			DEBUG("PlanB: IOCTL VIDIOCGCAP\n");
+
+			strcpy (b.name, pb->video_dev.name);
+			b.type = VID_TYPE_OVERLAY | VID_TYPE_CLIPPING |
+				 VID_TYPE_FRAMERAM | VID_TYPE_SCALES |
+				 VID_TYPE_CAPTURE;
+			b.channels = 2;	/* composite & svhs */
+			b.audios = 0;
+			b.maxwidth = PLANB_MAXPIXELS;
+                        b.maxheight = PLANB_MAXLINES;
+                        b.minwidth = 32; /* wild guess */
+                        b.minheight = 32;
+                        if (copy_to_user(arg,&b,sizeof(b)))
+                                return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSFBUF:
+		{
+                        struct video_buffer v;
+			unsigned short bpp;
+			unsigned int fmt;
+
+			DEBUG("PlanB: IOCTL VIDIOCSFBUF\n");
+
+                        if (!capable(CAP_SYS_ADMIN))
+                                return -EPERM;
+                        if (copy_from_user(&v, arg,sizeof(v)))
+                                return -EFAULT;
+			planb_lock(pb);
+			switch(v.depth) {
+			case 8:
+				bpp = 1;
+				fmt = PLANB_GRAY;
+				break;
+			case 15:
+			case 16:
+				bpp = 2;
+				fmt = PLANB_COLOUR15;
+				break;
+			case 24:
+			case 32:
+				bpp = 4;
+				fmt = PLANB_COLOUR32;
+				break;
+			default:
+				planb_unlock(pb);
+                                return -EINVAL;
+			}
+			if (bpp * v.width > v.bytesperline) {
+				planb_unlock(pb);
+				return -EINVAL;
+			}
+			pb->win.bpp = bpp;
+			pb->win.color_fmt = fmt;
+			pb->frame_buffer_phys = (unsigned long) v.base;
+			pb->win.sheight = v.height;
+			pb->win.swidth = v.width;
+			pb->picture.depth = pb->win.depth = v.depth;
+			pb->win.bpl = pb->win.bpp * pb->win.swidth;
+			pb->win.pad = v.bytesperline - pb->win.bpl;
+
+                        DEBUG("PlanB: Display at %p is %d by %d, bytedepth %d,"
+				" bpl %d (+ %d)\n", v.base, v.width,v.height,
+				pb->win.bpp, pb->win.bpl, pb->win.pad);
+
+			pb->cmd_buff_inited = 0;
+			if(pb->overlay) {
+				suspend_overlay(pb);
+				fill_cmd_buff(pb);
+				resume_overlay(pb);
+			}
+			planb_unlock(pb);
+			return 0;		
+		}
+		case VIDIOCGFBUF:
+		{
+                        struct video_buffer v;
+
+			DEBUG("PlanB: IOCTL VIDIOCGFBUF\n");
+
+			v.base = (void *)pb->frame_buffer_phys;
+			v.height = pb->win.sheight;
+			v.width = pb->win.swidth;
+			v.depth = pb->win.depth;
+			v.bytesperline = pb->win.bpl + pb->win.pad;
+			if (copy_to_user(arg, &v, sizeof(v)))
+                                return -EFAULT;
+			return 0;
+		}
+		case VIDIOCCAPTURE:
+		{
+			int i;
+
+                        if(copy_from_user(&i, arg, sizeof(i)))
+                                return -EFAULT;
+			if(i==0) {
+				DEBUG("PlanB: IOCTL VIDIOCCAPTURE Stop\n");
+
+				if (!(pb->overlay))
+					return 0;
+				planb_lock(pb);
+				pb->overlay = 0;
+				overlay_stop(pb);
+				planb_unlock(pb);
+			} else {
+				DEBUG("PlanB: IOCTL VIDIOCCAPTURE Start\n");
+
+				if (pb->frame_buffer_phys == 0 ||
+					  pb->win.width == 0 ||
+					  pb->win.height == 0)
+					return -EINVAL;
+				if (pb->overlay)
+					return 0;
+				planb_lock(pb);
+				pb->overlay = 1;
+				if(!(pb->cmd_buff_inited))
+					fill_cmd_buff(pb);
+				overlay_start(pb);
+				planb_unlock(pb);
+			}
+			return 0;
+		}
+		case VIDIOCGCHAN:
+		{
+			struct video_channel v;
+
+			DEBUG("PlanB: IOCTL VIDIOCGCHAN\n");
+
+			if(copy_from_user(&v, arg,sizeof(v)))
+				return -EFAULT;
+			v.flags = 0;
+			v.tuners = 0;
+			v.type = VIDEO_TYPE_CAMERA;
+			v.norm = pb->win.norm;
+			switch(v.channel)
+			{
+			case 0:
+				strcpy(v.name,"Composite");
+				break;
+			case 1:
+				strcpy(v.name,"SVHS");
+				break;
+			default:
+				return -EINVAL;
+				break;
+			}
+			if(copy_to_user(arg,&v,sizeof(v)))
+				return -EFAULT;
+
+			return 0;
+		}
+		case VIDIOCSCHAN:
+		{
+			struct video_channel v;
+
+			DEBUG("PlanB: IOCTL VIDIOCSCHAN\n");
+
+			if(copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+
+			if (v.norm != pb->win.norm) {
+				int i, maxlines;
+
+				switch (v.norm)
+				{
+				case VIDEO_MODE_PAL:
+				case VIDEO_MODE_SECAM:
+					maxlines = PLANB_MAXLINES;
+					break;
+				case VIDEO_MODE_NTSC:
+					maxlines = PLANB_NTSC_MAXLINES;
+					break;
+				default:
+					return -EINVAL;
+					break;
+				}
+				planb_lock(pb);
+				/* empty the grabbing queue */
+				while(pb->grabbing)
+					interruptible_sleep_on(&pb->capq);
+				pb->maxlines = maxlines;
+				pb->win.norm = v.norm;
+				/* Stop overlay if running */
+				suspend_overlay(pb);
+				for(i = 0; i < MAX_GBUFFERS; i++)
+					pb->gnorm_switch[i] = 1;
+				/* I know it's an overkill, but.... */
+				fill_cmd_buff(pb);
+				/* ok, now init it accordingly */
+				saa_init_regs (pb);
+				/* restart overlay if it was running */
+				resume_overlay(pb);
+				planb_unlock(pb);
+			}
+
+			switch(v.channel)
+			{
+			case 0:	/* Composite	*/
+				saa_set (SAA7196_IOCC,
+					((saa_regs[pb->win.norm][SAA7196_IOCC] &
+					  ~7) | 3), pb);
+				break;
+			case 1:	/* SVHS		*/
+				saa_set (SAA7196_IOCC,
+					((saa_regs[pb->win.norm][SAA7196_IOCC] &
+					  ~7) | 4), pb);
+				break;
+			default:
+				return -EINVAL;
+				break;
+			}
+
+			return 0;
+		}
+		case VIDIOCGPICT:
+		{
+			struct video_picture vp = pb->picture;
+
+			DEBUG("PlanB: IOCTL VIDIOCGPICT\n");
+
+			switch(pb->win.color_fmt) {
+			case PLANB_GRAY:
+				vp.palette = VIDEO_PALETTE_GREY;
+			case PLANB_COLOUR15:
+				vp.palette = VIDEO_PALETTE_RGB555;
+				break;
+			case PLANB_COLOUR32:
+				vp.palette = VIDEO_PALETTE_RGB32;
+				break;
+			default:
+				vp.palette = 0;
+				break;
+			}
+
+			if(copy_to_user(arg,&vp,sizeof(vp)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSPICT:
+		{
+			struct video_picture vp;
+
+			DEBUG("PlanB: IOCTL VIDIOCSPICT\n");
+
+			if(copy_from_user(&vp,arg,sizeof(vp)))
+				return -EFAULT;
+			pb->picture = vp;
+			/* Should we do sanity checks here? */
+			saa_set (SAA7196_BRIG, (unsigned char)
+			    ((pb->picture.brightness) >> 8), pb);
+			saa_set (SAA7196_HUEC, (unsigned char)
+			    ((pb->picture.hue) >> 8) ^ 0x80, pb);
+			saa_set (SAA7196_CSAT, (unsigned char)
+			    ((pb->picture.colour) >> 9), pb);
+			saa_set (SAA7196_CONT, (unsigned char)
+			    ((pb->picture.contrast) >> 9), pb);
+
+			return 0;
+		}
+		case VIDIOCSWIN:
+		{
+			struct video_window	vw;
+			struct video_clip	clip;
+			int 			i;
+			
+			DEBUG("PlanB: IOCTL VIDIOCSWIN\n");
+
+			if(copy_from_user(&vw,arg,sizeof(vw)))
+				return -EFAULT;
+
+			planb_lock(pb);
+			/* Stop overlay if running */
+			suspend_overlay(pb);
+			pb->win.interlace = (vw.height > pb->maxlines/2)? 1: 0;
+			if (pb->win.x != vw.x ||
+			    pb->win.y != vw.y ||
+			    pb->win.width != vw.width ||
+			    pb->win.height != vw.height ||
+			    !pb->cmd_buff_inited) {
+				pb->win.x = vw.x;
+				pb->win.y = vw.y;
+				pb->win.width = vw.width;
+				pb->win.height = vw.height;
+				fill_cmd_buff(pb);
+			}
+			/* Reset clip mask */
+			memset ((void *) pb->mask, 0xff, (pb->maxlines
+					* ((PLANB_MAXPIXELS + 7) & ~7)) / 8);
+			/* Add any clip rects */
+			for (i = 0; i < vw.clipcount; i++) {
+				if (copy_from_user(&clip, vw.clips + i,
+						sizeof(struct video_clip)))
+					return -EFAULT;
+				add_clip(pb, &clip);
+			}
+			/* restart overlay if it was running */
+			resume_overlay(pb);
+			planb_unlock(pb);
+			return 0;
+		}
+		case VIDIOCGWIN:
+		{
+			struct video_window vw;
+
+			DEBUG("PlanB: IOCTL VIDIOCGWIN\n");
+
+			vw.x=pb->win.x;
+			vw.y=pb->win.y;
+			vw.width=pb->win.width;
+			vw.height=pb->win.height;
+			vw.chromakey=0;
+			vw.flags=0;
+			if(pb->win.interlace)
+				vw.flags|=VIDEO_WINDOW_INTERLACE;
+			if(copy_to_user(arg,&vw,sizeof(vw)))
+				return -EFAULT;
+			return 0;
+		}
+	        case VIDIOCSYNC: {
+			int i;
+
+			IDEBUG("PlanB: IOCTL VIDIOCSYNC\n");
+
+			if(copy_from_user((void *)&i,arg,sizeof(int)))
+				return -EFAULT;
+
+			IDEBUG("PlanB: sync to frame %d\n", i);
+
+                        if(i > (MAX_GBUFFERS - 1) || i < 0)
+                                return -EINVAL;
+chk_grab:
+                        switch (pb->frame_stat[i]) {
+                        case GBUFFER_UNUSED:
+                                return -EINVAL;
+			case GBUFFER_GRABBING:
+				IDEBUG("PlanB: waiting for grab"
+							" done (%d)\n", i);
+ 			        interruptible_sleep_on(&pb->capq);
+				goto chk_grab;
+                        case GBUFFER_DONE:
+                                pb->frame_stat[i] = GBUFFER_UNUSED;
+                                break;
+                        }
+                        return 0;
+		}
+
+	        case VIDIOCMCAPTURE:
+		{
+                        struct video_mmap vm;
+			volatile unsigned int status;
+
+			IDEBUG("PlanB: IOCTL VIDIOCMCAPTURE\n");
+
+			if(copy_from_user((void *) &vm,(void *)arg,sizeof(vm)))
+				return -EFAULT;
+                        status = pb->frame_stat[vm.frame];
+                        if (status != GBUFFER_UNUSED)
+                                return -EBUSY;
+
+		        return vgrab(pb, &vm);
+		}
+		
+		case VIDIOCGMBUF:
+		{
+			int i;
+			struct video_mbuf vm;
+
+			DEBUG("PlanB: IOCTL VIDIOCGMBUF\n");
+
+			memset(&vm, 0 , sizeof(vm));
+			vm.size = PLANB_MAX_FBUF * MAX_GBUFFERS;
+			vm.frames = MAX_GBUFFERS;
+			for(i = 0; i<MAX_GBUFFERS; i++)
+				vm.offsets[i] = PLANB_MAX_FBUF * i;
+			if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
+				return -EFAULT;
+			return 0;
+		}
+		
+		case PLANBIOCGSAAREGS:
+		{
+			struct planb_saa_regs preg;
+
+			DEBUG("PlanB: IOCTL PLANBIOCGSAAREGS\n");
+
+			if(copy_from_user(&preg, arg, sizeof(preg)))
+				return -EFAULT;
+			if(preg.addr >= SAA7196_NUMREGS)
+				return -EINVAL;
+			preg.val = saa_regs[pb->win.norm][preg.addr];
+			if(copy_to_user((void *)arg, (void *)&preg,
+								sizeof(preg)))
+				return -EFAULT;
+			return 0;
+		}
+		
+		case PLANBIOCSSAAREGS:
+		{
+			struct planb_saa_regs preg;
+
+			DEBUG("PlanB: IOCTL PLANBIOCSSAAREGS\n");
+
+			if(copy_from_user(&preg, arg, sizeof(preg)))
+				return -EFAULT;
+			if(preg.addr >= SAA7196_NUMREGS)
+				return -EINVAL;
+			saa_set (preg.addr, preg.val, pb);
+			return 0;
+		}
+		
+		case PLANBIOCGSTAT:
+		{
+			struct planb_stat_regs pstat;
+
+			DEBUG("PlanB: IOCTL PLANBIOCGSTAT\n");
+
+			pstat.ch1_stat = in_le32(&pb->planb_base->ch1.status);
+			pstat.ch2_stat = in_le32(&pb->planb_base->ch2.status);
+			pstat.saa_stat0 = saa_status(0, pb);
+			pstat.saa_stat1 = saa_status(1, pb);
+
+			if(copy_to_user((void *)arg, (void *)&pstat,
+							sizeof(pstat)))
+				return -EFAULT;
+			return 0;
+		}
+		
+		case PLANBIOCSMODE: {
+			int v;
+
+			DEBUG("PlanB: IOCTL PLANBIOCSMODE\n");
+
+			if(copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+
+			switch(v)
+			{
+			case PLANB_TV_MODE:
+				saa_set (SAA7196_STDC,
+					(saa_regs[pb->win.norm][SAA7196_STDC] &
+					  0x7f), pb);
+				break;
+			case PLANB_VTR_MODE:
+				saa_set (SAA7196_STDC,
+					(saa_regs[pb->win.norm][SAA7196_STDC] |
+					  0x80), pb);
+				break;
+			default:
+				return -EINVAL;
+				break;
+			}
+			pb->win.mode = v;
+			return 0;
+		}
+		case PLANBIOCGMODE: {
+			int v=pb->win.mode;
+
+			DEBUG("PlanB: IOCTL PLANBIOCGMODE\n");
+
+			if(copy_to_user(arg,&v,sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+#ifdef PLANB_GSCANLINE
+		case PLANBG_GRAB_BPL: {
+			int v=pb->gbytes_per_line;
+
+			DEBUG("PlanB: IOCTL PLANBG_GRAB_BPL\n");
+
+			if(copy_to_user(arg,&v,sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+#endif /* PLANB_GSCANLINE */
+		case PLANB_INTR_DEBUG: {
+			int i;
+
+			DEBUG("PlanB: IOCTL PLANB_INTR_DEBUG\n");
+
+			if(copy_from_user(&i, arg, sizeof(i)))
+				return -EFAULT;
+
+			/* avoid hang ups all together */
+			for (i = 0; i < MAX_GBUFFERS; i++) {
+				if(pb->frame_stat[i] == GBUFFER_GRABBING) {
+					pb->frame_stat[i] = GBUFFER_DONE;
+				}
+			}
+			if(pb->grabbing)
+				pb->grabbing--;
+			wake_up_interruptible(&pb->capq);
+			return 0;
+		}
+		case PLANB_INV_REGS: {
+			int i;
+			struct planb_any_regs any;
+
+			DEBUG("PlanB: IOCTL PLANB_INV_REGS\n");
+
+			if(copy_from_user(&any, arg, sizeof(any)))
+				return -EFAULT;
+			if(any.offset < 0 || any.offset + any.bytes > 0x400)
+				return -EINVAL;
+			if(any.bytes > 128)
+				return -EINVAL;
+			for (i = 0; i < any.bytes; i++) {
+				any.data[i] =
+					in_8((unsigned char *)pb->planb_base
+							+ any.offset + i);
+			}
+			if(copy_to_user(arg,&any,sizeof(any)))
+				return -EFAULT;
+			return 0;
+		}
+		default:
+		{
+			DEBUG("PlanB: Unimplemented IOCTL\n");
+			return -ENOIOCTLCMD;
+		}
+	/* Some IOCTLs are currently unsupported on PlanB */
+		case VIDIOCGTUNER: {
+		DEBUG("PlanB: IOCTL VIDIOCGTUNER\n");
+			goto unimplemented; }
+		case VIDIOCSTUNER: {
+		DEBUG("PlanB: IOCTL VIDIOCSTUNER\n");
+			goto unimplemented; }
+		case VIDIOCSFREQ: {
+		DEBUG("PlanB: IOCTL VIDIOCSFREQ\n");
+			goto unimplemented; }
+		case VIDIOCGFREQ: {
+		DEBUG("PlanB: IOCTL VIDIOCGFREQ\n");
+			goto unimplemented; }
+		case VIDIOCKEY: {
+		DEBUG("PlanB: IOCTL VIDIOCKEY\n");
+			goto unimplemented; }
+		case VIDIOCSAUDIO: {
+		DEBUG("PlanB: IOCTL VIDIOCSAUDIO\n");
+			goto unimplemented; }
+		case VIDIOCGAUDIO: {
+		DEBUG("PlanB: IOCTL VIDIOCGAUDIO\n");
+			goto unimplemented; }
+unimplemented:
+		DEBUG("       Unimplemented\n");
+			return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+/*
+ *	This maps the vmalloced and reserved fbuffer to user space.
+ *
+ *  FIXME: 
+ *  - PAGE_READONLY should suffice!?
+ *  - remap_page_range is kind of inefficient for page by page remapping.
+ *    But e.g. pte_alloc() does not work in modules ... :-(
+ */
+ 
+static int planb_mmap(struct video_device *dev, const char *adr, unsigned long size)
+{
+	struct planb *pb=(struct planb *)dev;
+        unsigned long start=(unsigned long) adr;
+	unsigned long page;
+	void *pos;
+
+	if (size>MAX_GBUFFERS*PLANB_MAX_FBUF)
+	        return -EINVAL;
+	if (!pb->fbuffer)
+	{
+		if(fbuffer_alloc(pb))
+			return -EINVAL;
+	}
+	pos = (void *)pb->fbuffer;
+	while (size > 0) 
+	{
+	        page = vmalloc_to_phys(pos);
+		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))
+		        return -EAGAIN;
+		start+=PAGE_SIZE;
+		pos+=PAGE_SIZE;
+		size-=PAGE_SIZE;    
+	}
+	return 0;
+}
+
+/* This gets called upon device registration */
+/* we could do some init here */
+static int planb_init_done(struct video_device *dev)
+{
+	return 0;
+}
+
+static struct video_device planb_template=
+{
+	PLANB_DEVICE_NAME,
+	VID_TYPE_OVERLAY,
+	VID_HARDWARE_PLANB,
+	planb_open,
+	planb_close,
+	planb_read,
+	planb_write,
+#if LINUX_VERSION_CODE >= 0x020100
+	NULL,	/* poll */
+#endif
+	planb_ioctl,
+	planb_mmap,	/* mmap? */
+	planb_init_done,
+	NULL,	/* pointer to private data */
+	0,
+	0
+};
+
+static int init_planb(struct planb *pb)
+{
+	unsigned char saa_rev;
+	int i, result;
+
+	memset ((void *) &pb->win, 0, sizeof (struct planb_window));
+	/* Simple sanity check */
+	if(def_norm >= NUM_SUPPORTED_NORM || def_norm < 0) {
+		printk(KERN_ERR "PlanB: Option(s) invalid\n");
+		return -2;
+	}
+	pb->win.norm = def_norm;
+	pb->win.mode = PLANB_TV_MODE;	/* TV mode */
+	pb->win.interlace=1;
+	pb->win.x=0;
+	pb->win.y=0;
+	pb->win.width=768; /* 640 */
+	pb->win.height=576; /* 480 */
+	pb->maxlines=576;
+#if 0
+	btv->win.cropwidth=768; /* 640 */
+	btv->win.cropheight=576; /* 480 */
+	btv->win.cropx=0;
+	btv->win.cropy=0;
+#endif
+	pb->win.pad=0;
+	pb->win.bpp=4;
+	pb->win.depth=32;
+	pb->win.color_fmt=PLANB_COLOUR32;
+	pb->win.bpl=1024*pb->win.bpp;
+	pb->win.swidth=1024;
+	pb->win.sheight=768;
+#ifdef PLANB_GSCANLINE
+	if((pb->gbytes_per_line = PLANB_MAXPIXELS * 4) > PAGE_SIZE
+				|| (pb->gbytes_per_line <= 0))
+		return -3;
+	else {
+		/* page align pb->gbytes_per_line for DMA purpose */
+		for(i = PAGE_SIZE; pb->gbytes_per_line < (i>>1);)
+			i>>=1;
+		pb->gbytes_per_line = i;
+	}
+#endif
+	pb->tab_size = PLANB_MAXLINES + 40;
+	pb->suspend = 0;
+	pb->lock = 0;
+	pb->lockq = NULL;
+	pb->ch1_cmd = 0;
+	pb->ch2_cmd = 0;
+	pb->mask = 0;
+	pb->priv_space = 0;
+	pb->offset = 0;
+	pb->user = 0;
+	pb->overlay = 0;
+	pb->suspendq = NULL;
+	pb->cmd_buff_inited = 0;
+	pb->frame_buffer_phys = 0;
+
+	/* Reset DMA controllers */
+	planb_dbdma_stop(&pb->planb_base->ch2);
+	planb_dbdma_stop(&pb->planb_base->ch1);
+
+	saa_rev =  (saa_status(0, pb) & 0xf0) >> 4;
+	printk(KERN_INFO "PlanB: SAA7196 video processor rev. %d\n", saa_rev);
+	/* Initialize the SAA registers in memory and on chip */
+	saa_init_regs (pb);
+
+	/* clear interrupt mask */
+	pb->intr_mask = PLANB_CLR_IRQ;
+
+        result = request_irq(pb->irq, planb_irq, 0, "PlanB", (void *)pb);
+        if (result==-EINVAL) {
+                printk(KERN_ERR "PlanB: Bad irq number (%d) or handler\n",
+                       (int)pb->irq);
+                return result;
+        }
+	if (result==-EBUSY) {
+                printk(KERN_ERR "PlanB: I don't know why, but IRQ %d busy\n",
+			(int)pb->irq);
+                return result;
+        }
+        if (result < 0) 
+                return result;
+        
+	/* Now add the template and register the device unit. */
+	memcpy(&pb->video_dev,&planb_template,sizeof(planb_template));
+
+	pb->picture.brightness=0x90<<8;
+	pb->picture.contrast = 0x70 << 8;
+	pb->picture.colour = 0x70<<8;
+	pb->picture.hue = 0x8000;
+	pb->picture.whiteness = 0;
+	pb->picture.depth = pb->win.depth;
+
+	pb->frame_stat=NULL;
+	pb->capq=NULL;
+	for(i=0; i<MAX_GBUFFERS; i++) {
+		pb->gbuffer[i]=NULL;
+		pb->gwidth[i]=0;
+		pb->gheight[i]=0;
+		pb->gfmt[i]=0;
+		pb->cap_cmd[i]=NULL;
+#ifndef PLANB_GSCANLINE
+		pb->l_fr_addr[i]=NULL;
+		pb->lsize[i] = 0;
+		pb->lnum[i] = 0;
+#endif
+	}
+	pb->fbuffer=NULL;
+	pb->grabbing=0;
+
+	/* clear interrupts */
+	out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
+	/* set interrupt mask */
+	pb->intr_mask = PLANB_FRM_IRQ;
+
+	if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER)<0)
+		return -1;
+
+	return 0;
+}
+
+/*
+ *	Scan for a PlanB controller, request the irq and map the io memory 
+ */
+
+static int find_planb(void)
+{
+	struct planb		*pb;
+	struct device_node	*planb_devices;
+	unsigned char		dev_fn, confreg, bus;
+	unsigned int		old_base, new_base;
+	unsigned int		irq;
+
+	if (_machine != _MACH_Pmac)
+		return 0;
+
+	planb_devices = find_devices("planb");
+	if (planb_devices == 0) {
+		planb_num=0;
+		printk(KERN_WARNING "PlanB: no device found!\n");
+		return planb_num;
+	}
+
+	if (planb_devices->next != NULL)
+		printk(KERN_ERR "Warning: only using first PlanB device!\n");
+	pb = &planbs[0];
+	planb_num = 1;
+
+        if (planb_devices->n_addrs != 1) {
+                printk (KERN_WARNING "PlanB: expecting 1 address for planb "
+                	"(got %d)", planb_devices->n_addrs);
+		return 0;
+	}
+
+	if (planb_devices->n_intrs == 0) {
+		printk(KERN_WARNING "PlanB: no intrs for device %s\n",
+		       planb_devices->full_name);
+		return 0;
+	} else {
+		irq = planb_devices->intrs[0].line;
+	}
+
+	/* Initialize PlanB's PCI registers */
+
+	/* There is a bug with the way OF assigns addresses
+	   to the devices behind the chaos bridge.
+	   control needs only 0x1000 of space, but decodes only
+	   the upper 16 bits. It therefore occupies a full 64K.
+	   OF assigns the planb controller memory within this space;
+	   so we need to change that here in order to access planb. */
+
+	/* We remap to 0xf1000000 in hope that nobody uses it ! */
+
+	bus = (planb_devices->addrs[0].space >> 16) & 0xff;
+	dev_fn = (planb_devices->addrs[0].space >> 8) & 0xff;
+	confreg = planb_devices->addrs[0].space & 0xff;
+	old_base = planb_devices->addrs[0].address;
+	new_base = 0xf1000000;
+
+	DEBUG("PlanB: Found on bus %d, dev %d, func %d, "
+		"membase 0x%x (base reg. 0x%x)\n",
+		bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg);
+
+	/* Enable response in memory space, bus mastering,
+	   use memory write and invalidate */
+	pcibios_write_config_word (bus, dev_fn, PCI_COMMAND,
+		PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+		PCI_COMMAND_INVALIDATE);
+	/* Set PCI Cache line size & latency timer */
+	pcibios_write_config_byte (bus, dev_fn, PCI_CACHE_LINE_SIZE, 0x8);
+	pcibios_write_config_byte (bus, dev_fn, PCI_LATENCY_TIMER, 0x40);
+
+	/* Set the new base address */
+	pcibios_write_config_dword (bus, dev_fn, confreg, new_base);
+
+	planb_regs = (volatile struct planb_registers *)
+						ioremap (new_base, 0x400);
+	pb->planb_base = planb_regs;
+	pb->planb_base_phys = (struct planb_registers *)new_base;
+	pb->irq	= irq;
+	
+	return planb_num;
+}
+
+static void release_planb(void)
+{
+	int i;
+	struct planb *pb;
+
+	for (i=0;i<planb_num; i++) 
+	{
+		pb=&planbs[i];
+
+		/* stop and flash DMAs unconditionally */
+		planb_dbdma_stop(&pb->planb_base->ch2);
+		planb_dbdma_stop(&pb->planb_base->ch1);
+
+		/* clear and free interrupts */
+		pb->intr_mask = PLANB_CLR_IRQ;
+		out_le32 (&pb->planb_base->intr_stat, PLANB_CLR_IRQ);
+		free_irq(pb->irq, pb);
+
+		/* make sure all allocated memory are freed */
+		planb_prepare_close(pb);
+
+		printk(KERN_INFO "PlanB: unregistering with v4l\n");
+		video_unregister_device(&pb->video_dev);
+
+		/* note that iounmap() does nothing on the PPC right now */
+		iounmap ((void *)pb->planb_base);
+	}
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+#else
+__initfunc(int init_planbs(struct video_init *unused))
+{
+#endif
+	int i;
+  
+	if (find_planb()<=0)
+		return -EIO;
+
+	for (i=0; i<planb_num; i++) {
+		if (init_planb(&planbs[i])<0) {
+			printk(KERN_ERR "PlanB: error registering device %d"
+							" with v4l\n", i);
+			release_planb();
+			return -EIO;
+		} 
+		printk(KERN_INFO "PlanB: registered device %d with v4l\n", i);
+	}  
+	return 0;
+}
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+	release_planb();
+}
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/drivers/char/planb.h linux/drivers/char/planb.h
--- v2.2.7/linux/drivers/char/planb.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/planb.h	Fri May  7 11:05:30 1999
@@ -0,0 +1,229 @@
+/* 
+    planb - PlanB frame grabber driver
+
+    PlanB is used in the 7x00/8x00 series of PowerMacintosh
+    Computers as video input DMA controller.
+
+    Copyright (C) 1998 Michel Lanners (mlan@cpu.lu)
+
+    Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de)
+
+    Additional debugging and coding by Takashi Oe (toe@unlinfo.unl.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.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* $Id: planb.h,v 1.13 1999/05/03 19:28:56 mlan Exp $ */
+
+#ifndef _PLANB_H_
+#define _PLANB_H_
+
+#ifdef __KERNEL__
+#include <asm/dbdma.h>
+#include "saa7196.h"
+#endif /* __KERNEL__ */
+
+#define PLANB_DEVICE_NAME	"Apple PlanB Video-In"
+#define PLANB_REV		"1.0"
+
+#ifdef __KERNEL__
+//#define PLANB_GSCANLINE	/* use this if apps have the notion of */
+				/* grab buffer scanline */
+/* This should be safe for both PAL and NTSC */
+#define PLANB_MAXPIXELS 768
+#define PLANB_MAXLINES 576
+#define PLANB_NTSC_MAXLINES 480
+
+/* Uncomment your preferred norm ;-) */
+#define PLANB_DEF_NORM VIDEO_MODE_PAL
+//#define PLANB_DEF_NORM VIDEO_MODE_NTSC
+//#define PLANB_DEF_NORM VIDEO_MODE_SECAM
+
+/* fields settings */
+#define PLANB_GRAY	0x1	/*  8-bit mono? */
+#define PLANB_COLOUR15	0x2	/* 16-bit mode */
+#define PLANB_COLOUR32	0x4	/* 32-bit mode */
+#define PLANB_CLIPMASK	0x8	/* hardware clipmasking */
+
+/* misc. flags for PlanB DMA operation */
+#define	CH_SYNC		0x1	/* synchronize channels (set by ch1;
+				   cleared by ch2) */
+#define FIELD_SYNC	0x2     /* used for the start of each field
+				   (0 -> 1 -> 0 for ch1; 0 -> 1 for ch2) */
+#define EVEN_FIELD	0x0	/* even field is detected if unset */
+#define DMA_ABORT	0x2	/* error or just out of sync if set */
+#define ODD_FIELD	0x4	/* odd field is detected if set */
+
+/* for capture operations */
+#define MAX_GBUFFERS	2
+#ifdef PLANB_GSCANLINE
+#define PLANB_MAX_FBUF	0x240000	/* 576 * 1024 * 4 */
+#define TAB_FACTOR	(1)
+#else
+#define PLANB_MAX_FBUF	0x1b0000	/* 576 * 768 * 4 */
+#define TAB_FACTOR	(2)
+#endif
+#endif /* __KERNEL__ */
+
+struct planb_saa_regs {
+	unsigned char addr;
+	unsigned char val;
+};
+
+struct planb_stat_regs {
+	unsigned int ch1_stat;
+	unsigned int ch2_stat;
+	unsigned char saa_stat0;
+	unsigned char saa_stat1;
+};
+
+struct planb_any_regs {
+	unsigned int offset;
+	unsigned int bytes;
+	unsigned char data[128];
+};
+
+/* planb private ioctls */
+#define PLANBIOCGSAAREGS	_IOWR('v', BASE_VIDIOCPRIVATE, struct planb_saa_regs)	/* Read a saa7196 reg value */
+#define PLANBIOCSSAAREGS	_IOW('v', BASE_VIDIOCPRIVATE + 1, struct planb_saa_regs)	/* Set a saa7196 reg value */
+#define PLANBIOCGSTAT		_IOR('v', BASE_VIDIOCPRIVATE + 2, struct planb_stat_regs)	/* Read planb status */
+#define PLANB_TV_MODE		1
+#define PLANB_VTR_MODE		2
+#define PLANBIOCGMODE		_IOR('v', BASE_VIDIOCPRIVATE + 3, int)	/* Get TV/VTR mode */
+#define PLANBIOCSMODE		_IOW('v', BASE_VIDIOCPRIVATE + 4, int)	/* Set TV/VTR mode */
+
+#ifdef PLANB_GSCANLINE
+#define PLANBG_GRAB_BPL		_IOR('v', BASE_VIDIOCPRIVATE + 5, int)	/* # of bytes per scanline in grab buffer */
+#endif
+
+/* call wake_up_interruptible() with appropriate actions */
+#define PLANB_INTR_DEBUG	_IOW('v', BASE_VIDIOCPRIVATE + 20, int)
+/* investigate which reg does what */
+#define PLANB_INV_REGS		_IOWR('v', BASE_VIDIOCPRIVATE + 21, struct planb_any_regs)
+
+#ifdef __KERNEL__
+
+/* Potentially useful macros */
+#define PLANB_SET(x)	((x) << 16 | (x))
+#define PLANB_CLR(x)	((x) << 16)
+
+/* This represents the physical register layout */
+struct planb_registers {
+	volatile struct dbdma_regs	ch1;		/* 0x00: video in */
+	volatile unsigned int		even;		/* 0x40: even field setting */
+	volatile unsigned int		odd;		/* 0x44; odd field setting */
+	unsigned int			pad1[14];	/* empty? */
+	volatile struct dbdma_regs	ch2;		/* 0x80: clipmask out */
+	unsigned int			pad2[16];	/* 0xc0: empty? */
+	volatile unsigned int		reg3;		/* 0x100: ???? */
+	volatile unsigned int		intr_stat;	/* 0x104: irq status */
+#define PLANB_CLR_IRQ		0x00		/* clear Plan B interrupt */
+#define PLANB_GEN_IRQ		0x01		/* assert Plan B interrupt */
+#define PLANB_FRM_IRQ		0x02		/* end of frame */
+#define PLANB_IRQ_CMD_MASK	0x00000003U	/* reserve 2 lsbs for command */
+	unsigned int			pad3[1];	/* empty? */
+	volatile unsigned int		reg5;		/* 0x10c: ??? */
+	unsigned int			pad4[60];	/* empty? */
+	volatile unsigned char		saa_addr;	/* 0x200: SAA subadr */
+	char				pad5[3];
+	volatile unsigned char		saa_regval;	/* SAA7196 write reg. val */
+	char				pad6[3];
+	volatile unsigned char		saa_status;	/* SAA7196 status byte */
+	/* There is more unused stuff here */
+};
+
+struct planb_window {
+	int	x, y;
+	ushort	width, height;
+	ushort	bpp, bpl, depth, pad;
+	ushort	swidth, sheight;
+	int	norm;
+	int	interlace;
+	u32	color_fmt;
+	int	chromakey;
+	int	mode;		/* used to switch between TV/VTR modes */
+};
+
+struct planb_suspend {
+	int overlay;
+	int frame;
+	struct dbdma_cmd cmd;
+};
+
+struct planb {
+	struct	video_device video_dev;
+	struct	video_picture picture;		/* Current picture params */
+	struct	video_audio audio_dev;		/* Current audio params */
+  
+	volatile struct planb_registers *planb_base;	/* virt base of planb */
+	struct planb_registers *planb_base_phys;	/* phys base of planb */
+	void	*priv_space;			/* Org. alloc. mem for kfree */
+	int	user;
+	unsigned int tab_size;
+	int     maxlines;
+	int lock;
+	struct wait_queue *lockq;
+	unsigned int	irq;			/* interrupt number */
+	volatile unsigned int intr_mask;
+
+	int	overlay;			/* overlay running? */
+	struct	planb_window win;
+	unsigned long frame_buffer_phys;	/* We need phys for DMA */
+	int	offset;				/* offset of pixel 1 */
+	volatile struct dbdma_cmd *ch1_cmd;	/* Video In DMA cmd buffer */
+	volatile struct dbdma_cmd *ch2_cmd;	/* Clip Out DMA cmd buffer */
+	volatile struct dbdma_cmd *overlay_last1;
+	volatile struct dbdma_cmd *overlay_last2;
+	unsigned long ch1_cmd_phys;
+	volatile unsigned char *mask;		/* Clipmask buffer */
+	int suspend;
+	struct wait_queue *suspendq;
+	struct planb_suspend suspended;
+	int	cmd_buff_inited;		/* cmd buffer inited? */
+
+	int grabbing;
+	unsigned int gcount;
+	struct wait_queue *capq;
+	int last_fr;
+	int prev_last_fr;
+        unsigned char *fbuffer;
+	unsigned char *gbuffer[MAX_GBUFFERS];
+	volatile struct dbdma_cmd *cap_cmd[MAX_GBUFFERS];
+	volatile struct dbdma_cmd *last_cmd[MAX_GBUFFERS];
+	volatile struct dbdma_cmd *pre_cmd[MAX_GBUFFERS];
+	int need_pre_capture[MAX_GBUFFERS];
+#define PLANB_DUMMY 40	/* # of command buf's allocated for pre-capture seq. */
+	int gwidth[MAX_GBUFFERS], gheight[MAX_GBUFFERS];
+	unsigned int gfmt[MAX_GBUFFERS];
+	int gnorm_switch[MAX_GBUFFERS];
+        volatile unsigned int *frame_stat;
+#define GBUFFER_UNUSED       0x00U
+#define GBUFFER_GRABBING     0x01U
+#define GBUFFER_DONE         0x02U
+#ifdef PLANB_GSCANLINE
+	int gbytes_per_line;
+#else
+#define MAX_LNUM 431	/* change this if PLANB_MAXLINES or */
+			/* PLANB_MAXPIXELS changes */
+	unsigned char *l_fr_addr[MAX_GBUFFERS];
+	unsigned char *l_to_addr[MAX_GBUFFERS][MAX_LNUM];
+	int lsize[MAX_GBUFFERS], lnum[MAX_GBUFFERS];
+#endif
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* _PLANB_H_ */
diff -u --recursive --new-file v2.2.7/linux/drivers/char/saa7196.h linux/drivers/char/saa7196.h
--- v2.2.7/linux/drivers/char/saa7196.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/saa7196.h	Fri May  7 11:05:30 1999
@@ -0,0 +1,117 @@
+/*
+    Definitions for the Philips SAA7196 digital video decoder,
+    scaler, and clock generator circuit (DESCpro), as used in
+    the PlanB video input of the Powermac 7x00/8x00 series.
+  
+    Copyright (C) 1998 Michel Lanners (mlan@cpu.lu)
+
+    The register defines are shamelessly copied from the meteor
+    driver out of NetBSD (with permission),
+    and are copyrighted (c) 1995 Mark Tinguely and Jim Lowe
+    (Thanks !)
+  
+    Additional debugging and coding by Takashi Oe (toe@unlinfo.unl.edu)
+
+    The default values used for PlanB are my mistakes.
+*/
+
+/* $Id: saa7196.h,v 1.5 1999/03/26 23:28:47 mlan Exp $ */
+
+#ifndef _SAA7196_H_
+#define _SAA7196_H_
+
+#define SAA7196_NUMREGS	0x31	/* Number of registers (used)*/
+#define NUM_SUPPORTED_NORM 3	/* Number of supported norms by PlanB */
+
+/* Decoder part: */
+#define SAA7196_IDEL    0x00    /* Increment delay */
+#define SAA7196_HSB5    0x01    /* H-sync begin; 50 hz */
+#define SAA7196_HSS5    0x02    /* H-sync stop; 50 hz */
+#define SAA7196_HCB5    0x03    /* H-clamp begin; 50 hz */
+#define SAA7196_HCS5    0x04    /* H-clamp stop; 50 hz */
+#define SAA7196_HSP5    0x05    /* H-sync after PHI1; 50 hz */
+#define SAA7196_LUMC    0x06    /* Luminance control */
+#define SAA7196_HUEC    0x07    /* Hue control */
+#define SAA7196_CKTQ    0x08    /* Colour Killer Threshold QAM (PAL, NTSC) */
+#define SAA7196_CKTS    0x09    /* Colour Killer Threshold SECAM */
+#define SAA7196_PALS    0x0a    /* PAL switch sensitivity */
+#define SAA7196_SECAMS  0x0b    /* SECAM switch sensitivity */
+#define SAA7196_CGAINC  0x0c    /* Chroma gain control */
+#define SAA7196_STDC    0x0d    /* Standard/Mode control */
+#define SAA7196_IOCC    0x0e    /* I/O and Clock Control */
+#define SAA7196_CTRL1   0x0f    /* Control #1 */
+#define SAA7196_CTRL2   0x10    /* Control #2 */
+#define SAA7196_CGAINR  0x11    /* Chroma Gain Reference */
+#define SAA7196_CSAT    0x12    /* Chroma Saturation */
+#define SAA7196_CONT    0x13    /* Luminance Contrast */
+#define SAA7196_HSB6    0x14    /* H-sync begin; 60 hz */
+#define SAA7196_HSS6    0x15    /* H-sync stop; 60 hz */
+#define SAA7196_HCB6    0x16    /* H-clamp begin; 60 hz */
+#define SAA7196_HCS6    0x17    /* H-clamp stop; 60 hz */
+#define SAA7196_HSP6    0x18    /* H-sync after PHI1; 60 hz */
+#define SAA7196_BRIG    0x19    /* Luminance Brightness */
+
+/* Scaler part: */
+#define SAA7196_FMTS    0x20    /* Formats and sequence */
+#define SAA7196_OUTPIX  0x21    /* Output data pixel/line */
+#define SAA7196_INPIX   0x22    /* Input data pixel/line */
+#define SAA7196_HWS     0x23    /* Horiz. window start */
+#define SAA7196_HFILT   0x24    /* Horiz. filter */
+#define SAA7196_OUTLINE 0x25    /* Output data lines/field */
+#define SAA7196_INLINE  0x26    /* Input data lines/field */
+#define SAA7196_VWS     0x27    /* Vertical window start */
+#define SAA7196_VYP     0x28    /* AFS/vertical Y processing */
+#define SAA7196_VBS     0x29    /* Vertical Bypass start */
+#define SAA7196_VBCNT   0x2a    /* Vertical Bypass count */
+#define SAA7196_VBP     0x2b    /* veritcal Bypass Polarity */
+#define SAA7196_VLOW    0x2c    /* Colour-keying lower V limit */
+#define SAA7196_VHIGH   0x2d    /* Colour-keying upper V limit */
+#define SAA7196_ULOW    0x2e    /* Colour-keying lower U limit */
+#define SAA7196_UHIGH   0x2f    /* Colour-keying upper U limit */
+#define SAA7196_DPATH   0x30    /* Data path setting  */
+
+/* Initialization default values: */
+
+unsigned char saa_regs[NUM_SUPPORTED_NORM][SAA7196_NUMREGS] = {
+
+/* PAL, 768x576 (no scaling), composite video-in */
+/* Decoder: */
+      { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x63, 0xff,
+	0xfe, 0xf0, 0xfe, 0xe0, 0x20, 0x06, 0x3b, 0x98,
+	0x00, 0x59, 0x41, 0x45, 0x34, 0x0a, 0xf4, 0xd2,
+	0xe9, 0xa2,
+/* Padding */
+		    0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+/* Scaler: */
+	0x72, 0x80, 0x00, 0x03, 0x8d, 0x20, 0x20, 0x12,
+	0xa5, 0x12, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00,
+	0x87 },
+
+/* NTSC, 640x480? (no scaling), composite video-in */
+/* Decoder: */
+      { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x50, 0x00,
+	0xf8, 0xf0, 0xfe, 0xe0, 0x00, 0x06, 0x3b, 0x98,
+	0x00, 0x2c, 0x3d, 0x40, 0x34, 0x0a, 0xf4, 0xd2,
+	0xe9, 0x98,
+/* Padding */
+		    0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+/* Scaler: */
+	0x72, 0x80, 0x80, 0x03, 0x89, 0xf0, 0xf0, 0x0d,
+	0xa0, 0x0d, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00,
+	0x87 },
+
+/* SECAM, 768x576 (no scaling), composite video-in */
+/* Decoder: */
+      { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x63, 0xff,
+	0xfe, 0xf0, 0xfe, 0xe0, 0x20, 0x07, 0x3b, 0x98,
+	0x00, 0x59, 0x41, 0x45, 0x34, 0x0a, 0xf4, 0xd2,
+	0xe9, 0xa2,
+/* Padding */
+		    0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+/* Scaler: */
+	0x72, 0x80, 0x00, 0x03, 0x8d, 0x20, 0x20, 0x12,
+	0xa5, 0x12, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00,
+	0x87 }
+	};
+
+#endif /* _SAA7196_H_ */
diff -u --recursive --new-file v2.2.7/linux/drivers/char/specialix.c linux/drivers/char/specialix.c
--- v2.2.7/linux/drivers/char/specialix.c	Thu Dec 31 10:29:00 1998
+++ linux/drivers/char/specialix.c	Sun May  2 09:51:09 1999
@@ -2355,6 +2355,9 @@
 
 int irq [SX_NBOARD] = {0,};
 
+MODULE_PARM(iobase,"1-" __MODULE_STRING(SX_NBOARD) "i");
+MODULE_PARM(irq,"1-" __MODULE_STRING(SX_NBOARD) "i");
+
 /*
  * You can setup up to 4 boards.
  * by specifying "iobase=0xXXX,0xXXX ..." as insmod parameter.
diff -u --recursive --new-file v2.2.7/linux/drivers/macintosh/Makefile linux/drivers/macintosh/Makefile
--- v2.2.7/linux/drivers/macintosh/Makefile	Thu Nov 19 09:56:28 1998
+++ linux/drivers/macintosh/Makefile	Thu Apr 29 12:53:48 1999
@@ -16,7 +16,7 @@
 M_OBJS   :=
 
 ifndef CONFIG_MBX
-L_OBJS   := via-cuda.o nvram.o macio-adb.o via-pmu.o mediabay.o
+L_OBJS   := via-cuda.o macio-adb.o via-pmu.o mediabay.o
 LX_OBJS  := adb.o
 endif
 
@@ -25,6 +25,14 @@
 else
   ifeq ($(CONFIG_MAC_SERIAL),m)
     M_OBJS += macserial.o
+  endif
+endif
+
+ifeq ($(CONFIG_NVRAM),y)
+  L_OBJS += nvram.o
+else
+  ifeq ($(CONFIG_NVRAM),m)
+    M_OBJS += nvram.o
   endif
 endif
 
diff -u --recursive --new-file v2.2.7/linux/drivers/macintosh/adb.c linux/drivers/macintosh/adb.c
--- v2.2.7/linux/drivers/macintosh/adb.c	Fri Apr 16 14:47:30 1999
+++ linux/drivers/macintosh/adb.c	Thu Apr 29 12:53:48 1999
@@ -3,8 +3,19 @@
  * and the /dev/adb device on macintoshes.
  *
  * Copyright (C) 1996 Paul Mackerras.
+ *
+ * Modified to declare controllers as structures, added
+ * client notification of bus reset and handles PowerBook
+ * sleep, by Benjamin Herrenschmidt.
+ *
+ * To do:
+ *
+ * - /proc/adb to list the devices and infos
+ * - more /dev/adb to allow userland to receive the
+ *   flow of auto-polling datas from a given device.
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -21,12 +32,23 @@
 #include <asm/hydra.h>
 #include <asm/init.h>
 
+EXPORT_SYMBOL(adb_controller);
+EXPORT_SYMBOL(adb_client_list);
 EXPORT_SYMBOL(adb_hardware);
 
+struct adb_controller *adb_controller = NULL;
+struct notifier_block *adb_client_list = NULL;
 enum adb_hw adb_hardware = ADB_NONE;
-int (*adb_send_request)(struct adb_request *req, int sync);
-int (*adb_autopoll)(int devs);
-int (*adb_reset_bus)(void);
+
+#ifdef CONFIG_PMAC_PBOOK
+static int adb_notify_sleep(struct notifier_block *, unsigned long, void *);
+static struct notifier_block adb_sleep_notifier = {
+	adb_notify_sleep,
+	NULL,
+	0
+};
+#endif
+
 static int adb_scan_bus(void);
 
 static struct adb_handler {
@@ -35,13 +57,6 @@
 	int handler_id;
 } adb_handler[16];
 
-__openfirmware
-
-static int adb_nodev(void)
-{
-	return -1;
-}
-
 #if 0
 static void printADBreply(struct adb_request *req)
 {
@@ -61,8 +76,6 @@
 	int devmask = 0;
 	struct adb_request req;
 	
-	adb_reset_bus();	/* reset ADB bus */
-
 	/* assumes adb_handler[] is all zeroes at this point */
 	for (i = 1; i < 16; i++) {
 		/* see if there is anything at address i */
@@ -147,22 +160,96 @@
 
 void adb_init(void)
 {
-	adb_send_request = (void *) adb_nodev;
-	adb_autopoll = (void *) adb_nodev;
-	adb_reset_bus = adb_nodev;
 	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
 		return;
+
 	via_cuda_init();
 	via_pmu_init();
 	macio_adb_init();
-	if (adb_hardware == ADB_NONE)
+	
+	if (adb_controller == NULL)
 		printk(KERN_WARNING "Warning: no ADB interface detected\n");
-	else {
-		int devs = adb_scan_bus();
-		adb_autopoll(devs);
+	else
+	{
+		adb_hardware = adb_controller->kind;
+#ifdef CONFIG_PMAC_PBOOK
+		notifier_chain_register(&sleep_notifier_list,
+					&adb_sleep_notifier);
+#endif /* CONFIG_PMAC_PBOOK */
+
+		adb_reset_bus();
+	}
+}
+
+
+#ifdef CONFIG_PMAC_PBOOK
+/*
+ * notify clients before sleep and reset bus afterwards
+ */
+int
+adb_notify_sleep(struct notifier_block *this, unsigned long code, void *x)
+{
+	int ret;
+	
+	switch (code) {
+		case PBOOK_SLEEP:
+			ret = notifier_call_chain(&adb_client_list, ADB_MSG_POWERDOWN, NULL);
+			if (ret & NOTIFY_STOP_MASK)
+				return -EBUSY;
+		case PBOOK_WAKE:
+			adb_reset_bus();
+			break;
+	}
+	return NOTIFY_DONE;
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
+int
+adb_reset_bus(void)
+{
+	int ret, devs;
+	unsigned long flags;
+	
+	if (adb_controller == NULL)
+		return -ENXIO;
+		
+	ret = notifier_call_chain(&adb_client_list, ADB_MSG_PRE_RESET, NULL);
+	if (ret & NOTIFY_STOP_MASK)
+		return -EBUSY;
+
+	save_flags(flags);
+	cli();
+	memset(adb_handler, 0, sizeof(adb_handler));
+	restore_flags(flags);
+	
+	if (adb_controller->reset_bus)
+		ret = adb_controller->reset_bus();
+	else
+		ret = 0;
+
+	if (!ret)
+	{
+		devs = adb_scan_bus();
+		if (adb_controller->autopoll)
+			adb_controller->autopoll(devs);
 	}
+
+	ret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL);
+	if (ret & NOTIFY_STOP_MASK)
+		return -EBUSY;
+	
+	return 1;
+}
+
+void
+adb_poll(void)
+{
+	if ((adb_controller == NULL)||(adb_controller->poll == NULL))
+		return;
+	adb_controller->poll();
 }
 
+
 int
 adb_request(struct adb_request *req, void (*done)(struct adb_request *),
 	    int flags, int nbytes, ...)
@@ -171,18 +258,25 @@
 	int i;
 	struct adb_request sreq;
 
+	if ((adb_controller == NULL) || (adb_controller->send_request == NULL))
+		return -ENXIO;
+	if (nbytes < 1)
+		return -EINVAL;
+	
 	if (req == NULL) {
 		req = &sreq;
 		flags |= ADBREQ_SYNC;
 	}
-	req->nbytes = nbytes;
+	req->nbytes = nbytes+1;
 	req->done = done;
 	req->reply_expected = flags & ADBREQ_REPLY;
+	req->data[0] = ADB_PACKET;
 	va_start(list, nbytes);
 	for (i = 0; i < nbytes; ++i)
-		req->data[i] = va_arg(list, int);
+		req->data[i+1] = va_arg(list, int);
 	va_end(list);
-	return adb_send_request(req, flags & ADBREQ_SYNC);
+
+	return adb_controller->send_request(req, flags & ADBREQ_SYNC);
 }
 
  /* Ultimately this should return the number of devices with
@@ -247,7 +341,7 @@
 	if (req.reply_len < 2)
 	    return 0;
 	adb_request(&req, NULL, ADBREQ_SYNC, 3,
-	    ADB_WRITEREG(address, 3), req.reply[1], new_id);	
+	    ADB_WRITEREG(address, 3), req.reply[1] & 0xF0, new_id);	
 	adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
 	    ADB_READREG(address, 3));
 	if (req.reply_len < 2)
@@ -318,7 +412,7 @@
 {
 	struct adbdev_state *state;
 
-	if (MINOR(inode->i_rdev) > 0 || adb_hardware == ADB_NONE)
+	if (MINOR(inode->i_rdev) > 0 || (adb_controller == NULL)/*adb_hardware == ADB_NONE*/)
 		return -ENXIO;
 	state = kmalloc(sizeof(struct adbdev_state), GFP_KERNEL);
 	if (state == 0)
@@ -420,7 +514,7 @@
 static ssize_t adb_write(struct file *file, const char *buf,
 			 size_t count, loff_t *ppos)
 {
-	int ret, i;
+	int ret/*, i*/;
 	struct adbdev_state *state = file->private_data;
 	struct adb_request *req;
 
@@ -439,36 +533,26 @@
 	req->done = adb_write_done;
 	req->arg = (void *) state;
 	req->complete = 0;
-
+	
 	ret = -EFAULT;
 	if (copy_from_user(req->data, buf, count))
 		goto out;
 
 	atomic_inc(&state->n_pending);
-	switch (adb_hardware) {
-	case ADB_NONE:
-		ret = -ENXIO;
-		break;
-	case ADB_VIACUDA:
-		req->reply_expected = 1;
-		ret = cuda_send_request(req);
-		break;
-	case ADB_VIAPMU:
-		if (req->data[0] != ADB_PACKET) {
-			ret = pmu_send_request(req);
-			break;
-		}
-		/* else fall through */
-	default:
-		ret = -EINVAL;
-		if (req->data[0] != ADB_PACKET)
-			break;
-		for (i = 0; i < req->nbytes-1; ++i)
-			req->data[i] = req->data[i+1];
-		req->nbytes--;
-		req->reply_expected = ((req->data[0] & 0xc) == 0xc);
-		ret = adb_send_request(req, 0);
-		break;
+
+	/* Special case for ADB_BUSRESET request, all others are sent to
+	   the controller */
+	if ((req->data[0] == ADB_PACKET)&&(count > 1)
+		&&(req->data[1] == ADB_BUSRESET))
+		ret = adb_reset_bus();
+	else
+	{	
+		req->reply_expected = ((req->data[1] & 0xc) == 0xc);
+
+		if (adb_controller && adb_controller->send_request)
+			ret = adb_controller->send_request(req, 0);
+		else
+			ret = -ENXIO;
 	}
 
 	if (ret != 0) {
diff -u --recursive --new-file v2.2.7/linux/drivers/macintosh/mac_keyb.c linux/drivers/macintosh/mac_keyb.c
--- v2.2.7/linux/drivers/macintosh/mac_keyb.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/macintosh/mac_keyb.c	Thu Apr 29 12:53:48 1999
@@ -7,6 +7,27 @@
  * (see that file for its authors and contributors).
  *
  * Copyright (C) 1996 Paul Mackerras.
+ *
+ * Adapted to ADB changes and support for more devices by
+ * Benjamin Herrenschmidt. Adapted from code in MkLinux
+ * and reworked.
+ *
+ * Supported devices:
+ *
+ * - Standard 1 button mouse
+ * - All standard Apple Extended protocol (handler ID 4)
+ *   mice & trackballs
+ * - PowerBook Trackpad (default setup: enable tapping)
+ * - MicroSpeed mouse & trackball (needs testing)
+ * - CH Products Trackball Pro (needs testing)
+ * - Contour Design (Contour Mouse)
+ * - Hunter digital (NoHandsMouse)
+ * - Kensignton TurboMouse 5 (needs testing)
+ *
+ * To do:
+ *
+ * Improve Kensignton support, add MacX support as a dynamic
+ * option (not a compile-time option).
  */
 
 #include <linux/sched.h>
@@ -32,6 +53,41 @@
 #define KEYB_LEDREG	2	/* register # for leds on ADB keyboard */
 #define MOUSE_DATAREG	0	/* reg# for movement/button codes from mouse */
 
+static int adb_message_handler(struct notifier_block *, unsigned long, void *);
+static struct notifier_block mackeyb_adb_notifier = {
+	adb_message_handler,
+	NULL,
+	0
+};
+
+/* 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, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* fn, 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,
+};
+
+/* Simple translation table for the SysRq keys */
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char mackbd_sysrq_xlate[128] =
+	"asdfhgzxcv\000bqwer"				/* 0x00 - 0x0f */
+	"yt123465=97-80o]"				/* 0x10 - 0x1f */
+	"u[ip\rlj'k;\\,/nm."				/* 0x20 - 0x2f */
+	"\t `\177\000\033\000\000\000\000\000\000\000\000\000\000"
+							/* 0x30 - 0x3f */
+	"\000\000\000*\000+\000\000\000\000\000/\r\000-\000"
+							/* 0x40 - 0x4f */
+	"\000\0000123456789\000\000\000"		/* 0x50 - 0x5f */
+	"\205\206\207\203\210\211\000\213\000\215\000\000\000\000\000\212\000\214";
+							/* 0x60 - 0x6f */
+#endif
+
 static u_short macplain_map[NR_KEYS] __initdata = {
 	0xfb61,	0xfb73,	0xfb64,	0xfb66,	0xfb68,	0xfb67,	0xfb7a,	0xfb78,
 	0xfb63,	0xfb76,	0xf200,	0xfb62,	0xfb71,	0xfb77,	0xfb65,	0xfb72,
@@ -170,6 +226,8 @@
 static struct timer_list repeat_timer = { NULL, NULL, 0, 0, kbd_repeat };
 static int last_keycode;
 
+static void mackeyb_probe(void);
+
 static void keyboard_input(unsigned char *, int, struct pt_regs *, int);
 static void input_keycode(int, int);
 static void leds_done(struct adb_request *);
@@ -180,6 +238,7 @@
 static void init_trackpad(int id);
 static void init_trackball(int id);
 static void init_turbomouse(int id);
+static void init_microspeed(int id);
 
 #ifdef CONFIG_ADBMOUSE
 /* XXX: Hook for mouse driver */
@@ -207,21 +266,11 @@
 #define ADBMOUSE_TRACKBALL	3	/* TrackBall (handler 4) */
 #define ADBMOUSE_TRACKPAD       4	/* Apple's PowerBook trackpad (handler 4) */
 #define ADBMOUSE_TURBOMOUSE5    5	/* Turbomouse 5 (previously req. mousehack) */
+#define ADBMOUSE_MICROSPEED	6	/* Microspeed mouse (&trackball ?), MacPoint */
+#define ADBMOUSE_TRACKBALLPRO	7	/* Trackball Pro (special buttons) */
 
 static int adb_mouse_kinds[16];
 
-/* 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, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /* fn, 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,
-};
-
 __openfirmware
 
 int mackbd_setkeycode(unsigned int scancode, unsigned int keycode)
@@ -281,6 +330,10 @@
 	/* on the powerbook 3400, the power key gives code 0x7e */
 	if (keycode == 0x7e)
 		keycode = 0x7f;
+	/* remap the "Fn" key of the PowerBook G3 Series to 0x48
+	   to avoid conflict with button emulation */
+	if (keycode == 0x3f)
+		keycode = 0x48;
 
 	if (!repeat)
 		del_timer(&repeat_timer);
@@ -441,9 +494,24 @@
 	         the first (the real) button is released. We could do
 		 this here using async flush requests.
 	*/
-	if (adb_mouse_kinds[(data[0]>>4) & 0xf] == ADBMOUSE_TRACKPAD) {
+	switch (adb_mouse_kinds[(data[0]>>4) & 0xf])
+	{
+	    case ADBMOUSE_TRACKPAD:
 		data[1] = (data[1] & 0x7f) | ((data[1] & data[2]) & 0x80);
-		data[2] = (data[2] & 0x7f) | 0x80;
+		data[2] = data[2] | 0x80;
+		break;
+	    case ADBMOUSE_MICROSPEED:
+		data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7);
+		data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6);
+		data[3] = (data[3] & 0x77) | ((data[3] & 0x04) << 5)
+			| (data[3] & 0x08);
+		break;
+	    case ADBMOUSE_TRACKBALLPRO:
+		data[1] = (data[1] & 0x7f) | (((data[3] & 0x04) << 5)
+			& ((data[3] & 0x08) << 4));
+		data[2] = (data[2] & 0x7f) | ((data[3] & 0x01) << 7);
+		data[3] = (data[3] & 0x77) | ((data[3] & 0x02) << 6);
+		break;
 	}
 
 	if (adb_mouse_interrupt_hook)
@@ -473,7 +541,7 @@
 		}
 
 		/* Macintosh 3-button mouse (handler 4). */
-		if (nb == 4) {
+		if (nb >= 4) {
 			static unsigned char uch_ButtonStateThird = 0x80;
 			unsigned char uchButtonThird;
 
@@ -608,9 +676,6 @@
 
 __initfunc(void mackbd_init_hw(void))
 {
-	struct adb_request req;
-	int i;
-
 	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
 	    return;
 
@@ -626,71 +691,127 @@
 #ifdef CONFIG_ADBMOUSE
 	/* initialize mouse interrupt hook */
 	adb_mouse_interrupt_hook = NULL;
+#endif
+
+	led_request.complete = 1;
+
+	mackeyb_probe();
+	
+	notifier_chain_register(&adb_client_list, &mackeyb_adb_notifier);
+}
+
+static int
+adb_message_handler(struct notifier_block *this, unsigned long code, void *x)
+{
+	switch (code) {
+	case ADB_MSG_PRE_RESET:
+	case ADB_MSG_POWERDOWN:
+		/* Add unregister_keyboard when merging with Paul Mackerras */
+		while(!led_request.complete)
+			adb_poll();
+		break;
+			
+	case ADB_MSG_POST_RESET:
+		mackeyb_probe();
+		break;
+	}
+	return NOTIFY_DONE;
+}
 
+static void
+mackeyb_probe(void)
+{
+	struct adb_request req;
+	int i;
+
+#ifdef CONFIG_ADBMOUSE
 	adb_register(ADB_MOUSE, 0, &mouse_ids, mouse_input);
 #endif /* CONFIG_ADBMOUSE */
 
 	adb_register(ADB_KEYBOARD, 0, &keyboard_ids, keyboard_input);
 	adb_register(0x07, 0x1F, &buttons_ids, buttons_input);
 
-	for(i = 0; i < keyboard_ids.nids; i++) {
-	    /* turn off all leds */
-	    adb_request(&req, NULL, ADBREQ_SYNC, 3,
-	    ADB_WRITEREG(keyboard_ids.id[i], KEYB_LEDREG), 0xff, 0xff);
-	}
+	for (i = 0; i < keyboard_ids.nids; i++) {
+		int id = keyboard_ids.id[i];
 
-	/* Enable full feature set of the keyboard
-	   ->get it to send separate codes for left and right shift,
-	   control, option keys */
-	for(i = 0;i < keyboard_ids.nids; i++) {
-	    if (adb_try_handler_change(keyboard_ids.id[i], 5))
-	    	printk("ADB keyboard at %d, handler set to 5\n", keyboard_ids.id[i]);
-	    else if (adb_try_handler_change(keyboard_ids.id[i], 3))
-	    	printk("ADB keyboard at %d, handler set to 3\n", keyboard_ids.id[i]);
-	    else
-	    	printk("ADB keyboard at %d, handler 1\n", keyboard_ids.id[i]);
+		/* turn off all leds */
+		adb_request(&req, NULL, ADBREQ_SYNC, 3,
+			    ADB_WRITEREG(id, KEYB_LEDREG), 0xff, 0xff);
+
+		/* Enable full feature set of the keyboard
+		   ->get it to send separate codes for left and right shift,
+		   control, option keys */
+		if (adb_try_handler_change(id, 5))
+			printk("ADB keyboard at %d, handler set to 5\n", id);
+		else if (adb_try_handler_change(id, 3))
+			printk("ADB keyboard at %d, handler set to 3\n", id);
+		else
+			printk("ADB keyboard at %d, handler 1\n", id);
 	}
 
-	led_request.complete = 1;
-
 	/* Try to switch all mice to handler 4, or 2 for three-button
 	   mode and full resolution. */
-	for(i = 0; i < mouse_ids.nids; i++) {
-            if (adb_try_handler_change(mouse_ids.id[i], 4)) {
-                printk("ADB mouse at %d, handler set to 4", mouse_ids.id[i]);
-	        adb_mouse_kinds[mouse_ids.id[i]] = ADBMOUSE_EXTENDED;
-            }
-	    else if (adb_try_handler_change(mouse_ids.id[i], 2)) {
-	        printk("ADB mouse at %d, handler set to 2", mouse_ids.id[i]);
-	        adb_mouse_kinds[mouse_ids.id[i]] = ADBMOUSE_STANDARD_200;
-	    }
-	    else {
-                printk("ADB mouse at %d, handler 1", mouse_ids.id[i]);
-                adb_mouse_kinds[mouse_ids.id[i]] = ADBMOUSE_STANDARD_100;
-            }
-
-	    /* Register 1 is usually used for device identification.
-	       Here, we try to identify a known device and call the
-	       appropriate init function */
-	    adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
-			ADB_READREG(mouse_ids.id[i], 1));
-
-            if ((req.reply_len) &&
-                (req.reply[1] == 0x9a) && (req.reply[2] == 0x21))
-                init_trackball(mouse_ids.id[i]);
-            else if ((req.reply_len >= 4) &&
-		(req.reply[1] == 0x74) && (req.reply[2] == 0x70) &&
-		(req.reply[3] == 0x61) && (req.reply[4] == 0x64))
-		init_trackpad(mouse_ids.id[i]);
-	    else if ((req.reply_len >= 4) &&
-		(req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) &&
-		(req.reply[3] == 0x4c) && (req.reply[4] == 0x31))
-		init_turbomouse(mouse_ids.id[i]);
-            printk("\n");
+	for (i = 0; i < mouse_ids.nids; i++) {
+		int id = mouse_ids.id[i];
+		if (adb_try_handler_change(id, 4)) {
+			printk("ADB mouse at %d, handler set to 4", id);
+			adb_mouse_kinds[id] = ADBMOUSE_EXTENDED;
+		}
+		else if (adb_try_handler_change(id, 2)) {
+			printk("ADB mouse at %d, handler set to 2", id);
+			adb_mouse_kinds[id] = ADBMOUSE_STANDARD_200;
+		}
+		else if (adb_try_handler_change(id, 0x2F)) {
+			printk("ADB mouse at %d, handler set to 0x2F", id);
+			adb_mouse_kinds[id] = ADBMOUSE_MICROSPEED;
+		}
+		else if (adb_try_handler_change(id, 0x42)) {
+			printk("ADB mouse at %d, handler set to 0x42", id);
+			adb_mouse_kinds[id] = ADBMOUSE_TRACKBALLPRO;
+		}
+		else if (adb_try_handler_change(id, 0x66)) {
+			printk("ADB mouse at %d, handler set to 0x66", id);
+			adb_mouse_kinds[id] = ADBMOUSE_MICROSPEED;
+		}
+		else if (adb_try_handler_change(id, 0x5F)) {
+			printk("ADB mouse at %d, handler set to 0x5F", id);
+			adb_mouse_kinds[id] = ADBMOUSE_MICROSPEED;
+		}
+		else {
+			printk("ADB mouse at %d, handler 1", id);
+			adb_mouse_kinds[id] = ADBMOUSE_STANDARD_100;
+		}
+
+		if ((adb_mouse_kinds[id] == ADBMOUSE_TRACKBALLPRO)
+		    || (adb_mouse_kinds[id] == ADBMOUSE_MICROSPEED)) {
+			init_microspeed(id);
+		}  else if (adb_mouse_kinds[id] ==  ADBMOUSE_EXTENDED) {
+			/*
+			 * Register 1 is usually used for device
+			 * identification.  Here, we try to identify
+			 * a known device and call the appropriate
+			 * init function.
+			 */
+			adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
+				    ADB_READREG(id, 1));
+
+			if ((req.reply_len) &&
+			    (req.reply[1] == 0x9a) && (req.reply[2] == 0x21))
+				init_trackball(id);
+			else if ((req.reply_len >= 4) &&
+			    (req.reply[1] == 0x74) && (req.reply[2] == 0x70) &&
+			    (req.reply[3] == 0x61) && (req.reply[4] == 0x64))
+				init_trackpad(id);
+			else if ((req.reply_len >= 4) &&
+			    (req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) &&
+			    (req.reply[3] == 0x4c) && (req.reply[4] == 0x31))
+				init_turbomouse(id);
+		}
+		printk("\n");
         }
 }
 
-__init static void 
+static void 
 init_trackpad(int id)
 {
 	struct adb_request req;	
@@ -716,7 +837,7 @@
 	            r1_buffer[4],
 	            r1_buffer[5],
 	            0x0d, /*r1_buffer[6],*/
-	           r1_buffer[7]);
+	            r1_buffer[7]);
 
             adb_request(&req, NULL, ADBREQ_SYNC, 9,
 	        ADB_WRITEREG(id,2),
@@ -742,7 +863,7 @@
         }
 }
 
-__init static void 
+static void 
 init_trackball(int id)
 {
 	struct adb_request req;
@@ -776,7 +897,7 @@
 	ADB_WRITEREG(id,1), 03,0x38);
 }
 
-__init static void
+static void
 init_turbomouse(int id)
 {
 	struct adb_request req;
@@ -785,6 +906,13 @@
 
 	adb_mouse_kinds[id] = ADBMOUSE_TURBOMOUSE5;
 	
+	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 3,
+		ADB_WRITEREG(id,3), 0x20 | id, 4);
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+
 	adb_request(&req, NULL, ADBREQ_SYNC, 9,
 	ADB_WRITEREG(id,2),
 	    0xe7,
@@ -809,3 +937,44 @@
 	    0xff,
 	    0x27);
 }
+
+static void
+init_microspeed(int id)
+{
+	struct adb_request req;
+
+        printk(" (Microspeed/MacPoint or compatible)");
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+
+	/* This will initialize mice using the Microspeed, MacPoint and
+	   other compatible firmware. Bit 12 enables extended protocol.
+	   
+	   Register 1 Listen (4 Bytes)
+            0 -  3     Button is mouse (set also for double clicking!!!)
+            4 -  7     Button is locking (affects change speed also)
+            8 - 11     Button changes speed
+           12          1 = Extended mouse mode, 0 = normal mouse mode
+           13 - 15     unused 0
+           16 - 23     normal speed
+           24 - 31     changed speed
+
+       Register 1 talk holds version and product identification information.
+       Register 1 Talk (4 Bytes):
+            0 -  7     Product code
+            8 - 23     undefined, reserved
+           24 - 31     Version number
+        
+       Speed 0 is max. 1 to 255 set speed in increments of 1/256 of max.
+ */
+	adb_request(&req, NULL, ADBREQ_SYNC, 5,
+	ADB_WRITEREG(id,1),
+	    0x20,	/* alt speed = 0x20 (rather slow) */
+	    0x00,	/* norm speed = 0x00 (fastest) */
+	    0x10,	/* extended protocol, no speed change */
+	    0x07);	/* all buttons enabled as mouse buttons, no locking */
+
+
+	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
+}
+
diff -u --recursive --new-file v2.2.7/linux/drivers/macintosh/macio-adb.c linux/drivers/macintosh/macio-adb.c
--- v2.2.7/linux/drivers/macintosh/macio-adb.c	Thu Nov 19 09:56:28 1998
+++ linux/drivers/macintosh/macio-adb.c	Thu Apr 29 12:53:48 1999
@@ -63,9 +63,17 @@
 static int macio_adb_send_request(struct adb_request *req, int sync);
 static int macio_adb_autopoll(int devs);
 static void macio_adb_poll(void);
-static int macio_reset_bus(void);
+static int macio_adb_reset_bus(void);
 static void completed(void);
 
+static struct adb_controller	macio_controller = {
+	ADB_MACIO,
+	macio_adb_send_request,
+	macio_adb_autopoll,
+	macio_adb_reset_bus,
+	macio_adb_poll
+};
+
 __openfirmware
 
 void macio_adb_init(void)
@@ -106,10 +114,12 @@
 	out_8(&adb->autopoll.r, APE);
 	out_8(&adb->intr_enb.r, DFB | TAG);
 
-	adb_hardware = ADB_MACIO;
-	adb_send_request = macio_adb_send_request;
-	adb_autopoll = macio_adb_autopoll;
-	adb_reset_bus = macio_reset_bus;
+	adb_controller = &macio_controller;
+//	adb_hardware = ADB_MACIO;
+
+//	adb_send_request = macio_adb_send_request;
+//	adb_autopoll = macio_adb_autopoll;
+//	adb_reset_bus = macio_reset_bus;
 }
 
 static int macio_adb_autopoll(int devs)
@@ -120,7 +130,7 @@
 	return 0;
 }
 
-static int macio_reset_bus(void)
+static int macio_adb_reset_bus(void)
 {
 	int timeout = 1000000;
 
@@ -138,7 +148,15 @@
 static int macio_adb_send_request(struct adb_request *req, int sync)
 {
 	unsigned long mflags;
-
+	int i;
+	
+	if (req->data[0] != ADB_PACKET)
+		return -EINVAL;
+	
+	for (i = 0; i < req->nbytes - 1; ++i)
+		req->data[i] = req->data[i+1];
+	--req->nbytes;
+	
 	req->next = 0;
 	req->sent = 0;
 	req->complete = 0;
diff -u --recursive --new-file v2.2.7/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
--- v2.2.7/linux/drivers/macintosh/macserial.c	Tue Mar 23 14:35:47 1999
+++ linux/drivers/macintosh/macserial.c	Thu Apr 29 12:53:48 1999
@@ -1986,6 +1986,7 @@
 		info->line = i;
 		info->tty = 0;
 		info->custom_divisor = 16;
+		info->timeout = 0;
 		info->close_delay = 50;
 		info->closing_wait = 3000;
 		info->x_char = 0;
@@ -2058,6 +2059,32 @@
 static void serial_console_write(struct console *co, const char *s,
 				 unsigned count)
 {
+	struct mac_serial *info = zs_soft + co->index;
+	int i;
+
+	/* Turn of interrupts and enable the transmitter. */
+	write_zsreg(info->zs_channel, R1, info->curregs[1] & ~TxINT_ENAB);
+	write_zsreg(info->zs_channel, R5, info->curregs[5] | TxENAB | RTS | DTR);
+
+	for (i=0; i<count; i++) {
+		/* Wait for the transmit buffer to empty. */
+		while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0) {
+			eieio();
+		}
+
+		write_zsdata(info->zs_channel, s[i]);
+		if (s[i] == 10) {
+			while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP)
+                                == 0)
+				eieio();
+			
+			write_zsdata(info->zs_channel, 13);
+		}
+	}
+
+	/* Restore the values in the registers. */
+	write_zsreg(info->zs_channel, R1, info->curregs[1]);
+	/* Don't disable the transmitter. */
 }
 
 /*
@@ -2065,7 +2092,23 @@
  */
 static int serial_console_wait_key(struct console *co)
 {
-	return 0;
+	struct mac_serial *info = zs_soft + co->index;
+	int           val;
+
+	/* Turn of interrupts and enable the transmitter. */
+	write_zsreg(info->zs_channel, R1, info->curregs[1] & ~INT_ALL_Rx);
+	write_zsreg(info->zs_channel, R3, info->curregs[3] | RxENABLE);
+
+	/* Wait for something in the receive buffer. */
+	while((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0)
+		eieio();
+	val = read_zsdata(info->zs_channel);
+
+	/* Restore the values in the registers. */
+	write_zsreg(info->zs_channel, R1, info->curregs[1]);
+	write_zsreg(info->zs_channel, R3, info->curregs[3]);
+
+	return val;
 }
 
 static kdev_t serial_console_device(struct console *c)
@@ -2081,14 +2124,24 @@
  */
 __initfunc(static int serial_console_setup(struct console *co, char *options))
 {
-	struct serial_state *ser;
-	unsigned cval;
-	int	baud = 9600;
+	struct mac_serial *info = zs_soft + co->index;
+	int	baud = 38400;
 	int	bits = 8;
 	int	parity = 'n';
 	int	cflag = CREAD | HUPCL | CLOCAL;
-	int	quot = 0;
+	int	brg;
 	char	*s;
+	long	flags;
+
+	/* Find out how many Z8530 SCCs we have */
+	if (zs_chain == 0)
+		probe_sccs();
+
+	if (zs_chain == 0)
+		return -1;
+
+	/* Reset the channel */
+	write_zsreg(info->zs_channel, R9, CHRA);
 
 	if (options) {
 		baud = simple_strtoul(options, NULL, 10);
@@ -2114,21 +2167,21 @@
 	case 4800:
 		cflag |= B4800;
 		break;
+	case 9600:
+		cflag |= B9600;
+		break;
 	case 19200:
 		cflag |= B19200;
 		break;
-	case 38400:
-		cflag |= B38400;
-		break;
 	case 57600:
 		cflag |= B57600;
 		break;
 	case 115200:
 		cflag |= B115200;
 		break;
-	case 9600:
+	case 38400:
 	default:
-		cflag |= B9600;
+		cflag |= B38400;
 		break;
 	}
 	switch(bits) {
@@ -2142,7 +2195,7 @@
 	}
 	switch(parity) {
 	case 'o': case 'O':
-		cflag |= PARODD;
+		cflag |= PARENB | PARODD;
 		break;
 	case 'e': case 'E':
 		cflag |= PARENB;
@@ -2150,6 +2203,90 @@
 	}
 	co->cflag = cflag;
 
+	save_flags(flags); cli();
+        memset(info->curregs, 0, sizeof(info->curregs));
+
+	info->zs_baud = baud;
+	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->curregs[5] |= TxENAB | RTS | DTR;
+	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);
+
 	return 0;
 }
 
@@ -2170,9 +2307,10 @@
 /*
  *	Register console.
  */
-__initfunc (void serial_console_init(void))
+__initfunc (long serial_console_init(long kmem_start, long kmem_end))
 {
 	register_console(&sercons);
+	return kmem_start;
 }
 #endif /* ifdef CONFIG_SERIAL_CONSOLE */
 
diff -u --recursive --new-file v2.2.7/linux/drivers/macintosh/nvram.c linux/drivers/macintosh/nvram.c
--- v2.2.7/linux/drivers/macintosh/nvram.c	Wed Aug 26 11:37:38 1998
+++ linux/drivers/macintosh/nvram.c	Thu Apr 29 12:53:48 1999
@@ -1,6 +1,11 @@
 /*
  * /dev/nvram driver for Power Macintosh.
  */
+
+#define NVRAM_VERSION "1.0"
+
+#include <linux/module.h>
+
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -9,11 +14,14 @@
 #include <linux/nvram.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
-#include <asm/init.h>
 
 #define NVRAM_SIZE	8192
 
+/* when building as a module, __openfirmware is both unavailable
+ * and unnecessary. */
+#ifndef MODULE
 __openfirmware
+#endif
 
 static long long nvram_llseek(struct file *file, loff_t offset, int origin)
 {
@@ -70,6 +78,13 @@
 
 static int nvram_open(struct inode *inode, struct file *file)
 {
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int nvram_release(struct inode *inode, struct file *file)
+{
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -83,7 +98,7 @@
 	NULL,		/* nvram_mmap */
 	nvram_open,
 	NULL,		/* flush */
-	NULL,		/* no special release code */
+	nvram_release,
 	NULL		/* fsync */
 };
 
@@ -95,6 +110,19 @@
 
 __initfunc(int nvram_init(void))
 {
+	printk(KERN_INFO "Macintosh non-volatile memory driver v%s\n",
+		NVRAM_VERSION);
 	misc_register(&nvram_dev);
 	return 0;
 }
+#ifdef MODULE
+int init_module (void)
+{
+        return( nvram_init() );
+}
+
+void cleanup_module (void)
+{
+        misc_deregister( &nvram_dev );
+}
+#endif
diff -u --recursive --new-file v2.2.7/linux/drivers/macintosh/via-cuda.c linux/drivers/macintosh/via-cuda.c
--- v2.2.7/linux/drivers/macintosh/via-cuda.c	Thu Nov 19 09:56:28 1998
+++ linux/drivers/macintosh/via-cuda.c	Thu Apr 29 12:53:48 1999
@@ -74,6 +74,7 @@
 static int reading_reply;
 static int data_index;
 static struct device_node *vias;
+static int cuda_fully_inited = 0;
 
 static int init_via(void);
 static void cuda_start(void);
@@ -81,7 +82,17 @@
 static void cuda_input(unsigned char *buf, int nb, struct pt_regs *regs);
 static int cuda_adb_send_request(struct adb_request *req, int sync);
 static int cuda_adb_autopoll(int devs);
-static int cuda_reset_bus(void);
+static int cuda_adb_reset_bus(void);
+static int cuda_send_request(struct adb_request *req);
+
+
+static struct adb_controller	cuda_controller = {
+	ADB_VIACUDA,
+	cuda_adb_send_request,
+	cuda_adb_autopoll,
+	cuda_adb_reset_bus,
+	cuda_poll
+};
 
 __openfirmware
 
@@ -121,7 +132,7 @@
 	via = NULL;
     }
 
-    adb_hardware = ADB_VIACUDA;
+   adb_controller = &cuda_controller;
 }
 
 void
@@ -139,10 +150,7 @@
     via[IFR] = 0x7f; eieio();	/* clear interrupts by writing 1s */
     via[IER] = IER_SET|SR_INT; eieio();	/* enable interrupt from SR */
 
-    /* Set function pointers */
-    adb_send_request = cuda_adb_send_request;
-    adb_autopoll = cuda_adb_autopoll;
-    adb_reset_bus = cuda_reset_bus;
+    cuda_fully_inited = 1;
 }
 
 #define WAIT_FOR(cond, what)				\
@@ -201,14 +209,17 @@
 {
     int i;
 
-    for (i = req->nbytes; i > 0; --i)
-	req->data[i] = req->data[i-1];
-    req->data[0] = ADB_PACKET;
-    ++req->nbytes;
+    if ((via == NULL) || !cuda_fully_inited) {
+	req->complete = 1;
+	return -ENXIO;
+    }
+  
     req->reply_expected = 1;
+
     i = cuda_send_request(req);
     if (i)
 	return i;
+
     if (sync) {
 	while (!req->complete)
 	    cuda_poll();
@@ -216,12 +227,16 @@
     return 0;
 }
 
+
 /* Enable/disable autopolling */
 static int
 cuda_adb_autopoll(int devs)
 {
     struct adb_request req;
 
+    if ((via == NULL) || !cuda_fully_inited)
+	return -ENXIO;
+
     cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, (devs? 1: 0));
     while (!req.complete)
 	cuda_poll();
@@ -230,10 +245,13 @@
 
 /* Reset adb bus - how do we do this?? */
 static int
-cuda_reset_bus(void)
+cuda_adb_reset_bus(void)
 {
     struct adb_request req;
 
+    if ((via == NULL) || !cuda_fully_inited)
+	return -ENXIO;
+
     cuda_request(&req, NULL, 2, ADB_PACKET, 0);		/* maybe? */
     while (!req.complete)
 	cuda_poll();
@@ -248,6 +266,11 @@
     va_list list;
     int i;
 
+    if (via == NULL) {
+	req->complete = 1;
+	return -ENXIO;
+    }
+
     req->nbytes = nbytes;
     req->done = done;
     va_start(list, nbytes);
@@ -258,15 +281,11 @@
     return cuda_send_request(req);
 }
 
-int
+static int
 cuda_send_request(struct adb_request *req)
 {
     unsigned long flags;
 
-    if (via == NULL) {
-	req->complete = 1;
-	return -ENXIO;
-    }
     if (req->nbytes < 2 || req->data[0] > CUDA_PACKET) {
 	req->complete = 1;
 	return -EINVAL;
@@ -472,3 +491,9 @@
 	printk("\n");
     }
 }
+
+int
+cuda_present(void)
+{
+	return (adb_controller && (adb_controller->kind == ADB_VIACUDA) && via);
+}
\ No newline at end of file
diff -u --recursive --new-file v2.2.7/linux/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c
--- v2.2.7/linux/drivers/macintosh/via-pmu.c	Tue Mar 23 14:35:47 1999
+++ linux/drivers/macintosh/via-pmu.c	Thu Apr 29 12:53:48 1999
@@ -93,6 +93,7 @@
 static struct adb_request bright_req_1, bright_req_2, bright_req_3;
 static struct device_node *vias;
 static int pmu_kind = PMU_UNKNOWN;
+static int pmu_fully_inited = 0;
 
 int asleep;
 struct notifier_block *sleep_notifier_list;
@@ -103,7 +104,7 @@
 static void via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
 static int pmu_adb_send_request(struct adb_request *req, int sync);
 static int pmu_adb_autopoll(int devs);
-static int pmu_reset_bus(void);
+static int pmu_adb_reset_bus(void);
 static void send_byte(int x);
 static void recv_byte(void);
 static void pmu_sr_intr(struct pt_regs *regs);
@@ -112,6 +113,14 @@
 			    struct pt_regs *regs);
 static void set_volume(int level);
 
+static struct adb_controller	pmu_controller = {
+	ADB_VIAPMU,
+	pmu_adb_send_request,
+	pmu_adb_autopoll,
+	pmu_adb_reset_bus,
+	pmu_poll
+};
+
 /*
  * This table indicates for each PMU opcode:
  * - the number of data bytes to be sent with the command, or -1
@@ -126,17 +135,17 @@
 /*10*/	{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
 /*18*/	{ 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0, 0},
 /*20*/	{-1, 0},{ 0, 0},{ 2, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*28*/	{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
-/*30*/	{ 4, 0},{20, 0},{ 2, 0},{ 3, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*38*/	{ 0, 4},{ 0,20},{ 1, 1},{ 2, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
+/*28*/	{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0,-1},
+/*30*/	{ 4, 0},{20, 0},{-1, 0},{ 3, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*38*/	{ 0, 4},{ 0,20},{ 2,-1},{ 2, 1},{ 3,-1},{-1,-1},{-1,-1},{ 4, 0},
 /*40*/	{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*48*/	{ 0, 1},{ 0, 1},{-1,-1},{-1,-1},{ 1, 0},{-1,-1},{-1,-1},{-1,-1},
+/*48*/	{ 0, 1},{ 0, 1},{-1,-1},{ 1, 0},{ 1, 0},{-1,-1},{-1,-1},{-1,-1},
 /*50*/	{ 1, 0},{ 0, 0},{ 2, 0},{ 2, 0},{-1, 0},{ 1, 0},{ 3, 0},{ 1, 0},
 /*58*/	{ 0, 1},{ 1, 0},{ 0, 2},{ 0, 2},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},
-/*60*/	{ 2, 0},{-1, 0},{ 2, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*60*/	{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
 /*68*/	{ 0, 3},{ 0, 3},{ 0, 2},{ 0, 8},{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},
 /*70*/	{ 1, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
-/*78*/	{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 4, 1},{ 4, 1},
+/*78*/	{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{ 5, 1},{ 4, 1},{ 4, 1},
 /*80*/	{ 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
 /*88*/	{ 0, 5},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
 /*90*/	{ 1, 0},{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
@@ -149,7 +158,7 @@
 /*c8*/	{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
 /*d0*/	{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
 /*d8*/	{ 1, 1},{ 1, 1},{-1,-1},{-1,-1},{ 0, 1},{ 0,-1},{-1,-1},{-1,-1},
-/*e0*/	{-1, 0},{ 4, 0},{ 0, 1},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
+/*e0*/	{-1, 0},{ 4, 0},{ 0, 1},{-1, 0},{-1, 0},{ 4, 0},{-1, 0},{-1, 0},
 /*e8*/	{ 3,-1},{-1,-1},{ 0, 1},{-1,-1},{ 0,-1},{-1,-1},{-1,-1},{ 0, 0},
 /*f0*/	{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
 /*f8*/	{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
@@ -186,8 +195,8 @@
 			return;
 	}
 
-	if (vias->parent->name && strcmp(vias->parent->name, "ohare") == 0
-	    || device_is_compatible(vias->parent, "ohare"))
+	if (vias->parent->name && ((strcmp(vias->parent->name, "ohare") == 0)
+	    || device_is_compatible(vias->parent, "ohare")))
 		pmu_kind = PMU_OHARE_BASED;
 	else if (device_is_compatible(vias->parent, "heathrow"))
 		pmu_kind = PMU_HEATHROW_BASED;
@@ -203,13 +212,13 @@
 	if (!init_pmu())
 		via = NULL;
 
-	adb_hardware = ADB_VIAPMU;
-	
+	adb_controller = &pmu_controller;
+
 	if (via)
 		printk(KERN_INFO "PMU driver initialized for %s\n",
-		(pmu_kind == PMU_OHARE_BASED) ? "PowerBook 2400/3400/3500(G3)" :
-		((pmu_kind == PMU_HEATHROW_BASED) ? "PowerBook G3 Series" :
-		"Unknown PowerBook"));
+		    (pmu_kind == PMU_OHARE_BASED) ? "PowerBook 2400/3400/3500(G3)" :
+		    ((pmu_kind == PMU_HEATHROW_BASED) ? "PowerBook G3 Series" :
+		    "Unknown PowerBook"));
 }
 
 void __openfirmware
@@ -232,11 +241,8 @@
 	/* Enable interrupts */
 	out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
 
-	/* Set function pointers */
-	adb_send_request = pmu_adb_send_request;
-	adb_autopoll = pmu_adb_autopoll;
-	adb_reset_bus = pmu_reset_bus;
-
+	pmu_fully_inited = 1;
+	
 	/* Enable backlight */
 	pmu_enable_backlight(1);
 }
@@ -288,25 +294,81 @@
 static int __openfirmware
 pmu_adb_send_request(struct adb_request *req, int sync)
 {
-	int i;
+    int i, ret;
 
-	for (i = req->nbytes - 1; i > 0; --i)
-		req->data[i+3] = req->data[i];
-	req->data[3] = req->nbytes - 1;
-	req->data[2] = pmu_adb_flags;
-	req->data[1] = req->data[0];
-	req->data[0] = PMU_ADB_CMD;
-	req->nbytes += 3;
-	req->reply_expected = 1;
-	req->reply_len = 0;
-	i = pmu_queue_request(req);
-	if (i)
-		return i;
-	if (sync) {
-		while (!req->complete)
-			pmu_poll();
-	}
-	return 0;
+    if ((vias == NULL) || (!pmu_fully_inited))
+    {
+ 	req->complete = 1;
+   	return -ENXIO;
+   }
+
+    ret = -EINVAL;
+	
+    switch (req->data[0]) {
+    case PMU_PACKET:
+		for (i = 0; i < req->nbytes - 1; ++i)
+			req->data[i] = req->data[i+1];
+		--req->nbytes;
+		if (pmu_data_len[req->data[0]][1] != 0) {
+			req->reply[0] = ADB_RET_OK;
+			req->reply_len = 1;
+		} else
+			req->reply_len = 0;
+		ret = pmu_queue_request(req);
+		break;
+    case CUDA_PACKET:
+		switch (req->data[1]) {
+		case CUDA_GET_TIME:
+			if (req->nbytes != 2)
+				break;
+			req->data[0] = PMU_READ_RTC;
+			req->nbytes = 1;
+			req->reply_len = 3;
+			req->reply[0] = CUDA_PACKET;
+			req->reply[1] = 0;
+			req->reply[2] = CUDA_GET_TIME;
+			ret = pmu_queue_request(req);
+			break;
+		case CUDA_SET_TIME:
+			if (req->nbytes != 6)
+				break;
+			req->data[0] = PMU_SET_RTC;
+			req->nbytes = 5;
+			for (i = 1; i <= 4; ++i)
+				req->data[i] = req->data[i+1];
+			req->reply_len = 3;
+			req->reply[0] = CUDA_PACKET;
+			req->reply[1] = 0;
+			req->reply[2] = CUDA_SET_TIME;
+			ret = pmu_queue_request(req);
+			break;
+		}
+		break;
+    case ADB_PACKET:
+		for (i = req->nbytes - 1; i > 1; --i)
+			req->data[i+2] = req->data[i];
+		req->data[3] = req->nbytes - 2;
+		req->data[2] = pmu_adb_flags;
+		/*req->data[1] = req->data[1];*/
+		req->data[0] = PMU_ADB_CMD;
+		req->nbytes += 2;
+		req->reply_expected = 1;
+		req->reply_len = 0;
+		ret = pmu_queue_request(req);
+		break;
+    }
+    if (ret)
+    {
+    	req->complete = 1;
+    	return ret;
+    }
+    	
+    if (sync) {
+	while (!req->complete)
+		pmu_poll();
+    }
+
+    return 0;
 }
 
 /* Enable/disable autopolling */
@@ -315,6 +377,9 @@
 {
 	struct adb_request req;
 
+	if ((vias == NULL) || (!pmu_fully_inited))
+		return -ENXIO;
+
 	if (devs) {
 		adb_dev_map = devs;
 		pmu_request(&req, NULL, 5, PMU_ADB_CMD, 0, 0x86,
@@ -331,12 +396,15 @@
 
 /* Reset the ADB bus */
 static int __openfirmware
-pmu_reset_bus(void)
+pmu_adb_reset_bus(void)
 {
 	struct adb_request req;
 	long timeout;
 	int save_autopoll = adb_dev_map;
 
+	if ((vias == NULL) || (!pmu_fully_inited))
+		return -ENXIO;
+
 	/* anyone got a better idea?? */
 	pmu_adb_autopoll(0);
 
@@ -344,23 +412,23 @@
 	req.done = NULL;
 	req.data[0] = PMU_ADB_CMD;
 	req.data[1] = 0;
-	req.data[2] = 3;
+	req.data[2] = 3; /* ADB_BUSRESET ??? */
 	req.data[3] = 0;
 	req.data[4] = 0;
 	req.reply_len = 0;
 	req.reply_expected = 1;
 	if (pmu_queue_request(&req) != 0)
 	{
-		printk(KERN_ERR "pmu_reset_bus: pmu_queue_request failed\n");
-		return 0;
+		printk(KERN_ERR "pmu_adb_reset_bus: pmu_queue_request failed\n");
+		return -EIO;
 	}
 	while (!req.complete)
 		pmu_poll();
 	timeout = 100000;
 	while (!req.complete) {
 		if (--timeout < 0) {
-			printk(KERN_ERR "pmu_reset_bus (reset): no response from PMU\n");
-			return 0;
+			printk(KERN_ERR "pmu_adb_reset_bus (reset): no response from PMU\n");
+			return -EIO;
 		}
 		udelay(10);
 		pmu_poll();
@@ -369,7 +437,7 @@
 	if (save_autopoll != 0)
 		pmu_adb_autopoll(save_autopoll);
 		
-	return 1;
+	return 0;
 }
 
 /* Construct and send a pmu request */
@@ -380,6 +448,9 @@
 	va_list list;
 	int i;
 
+	if (vias == NULL)
+		return -ENXIO;
+
 	if (nbytes < 0 || nbytes > 32) {
 		printk(KERN_ERR "pmu_request: bad nbytes (%d)\n", nbytes);
 		req->complete = 1;
@@ -400,57 +471,6 @@
 	return pmu_queue_request(req);
 }
 
-/*
- * This procedure handles requests written to /dev/adb where the
- * first byte is CUDA_PACKET or PMU_PACKET.  For CUDA_PACKET, we
- * emulate a few CUDA requests.
- */
-int __openfirmware
-pmu_send_request(struct adb_request *req)
-{
-	int i;
-
-	switch (req->data[0]) {
-	case PMU_PACKET:
-		for (i = 0; i < req->nbytes - 1; ++i)
-			req->data[i] = req->data[i+1];
-		--req->nbytes;
-		if (pmu_data_len[req->data[0]][1] != 0) {
-			req->reply[0] = ADB_RET_OK;
-			req->reply_len = 1;
-		} else
-			req->reply_len = 0;
-		return pmu_queue_request(req);
-	case CUDA_PACKET:
-		switch (req->data[1]) {
-		case CUDA_GET_TIME:
-			if (req->nbytes != 2)
-				break;
-			req->data[0] = PMU_READ_RTC;
-			req->nbytes = 1;
-			req->reply_len = 3;
-			req->reply[0] = CUDA_PACKET;
-			req->reply[1] = 0;
-			req->reply[2] = CUDA_GET_TIME;
-			return pmu_queue_request(req);
-		case CUDA_SET_TIME:
-			if (req->nbytes != 6)
-				break;
-			req->data[0] = PMU_SET_RTC;
-			req->nbytes = 5;
-			for (i = 1; i <= 4; ++i)
-				req->data[i] = req->data[i+1];
-			req->reply_len = 3;
-			req->reply[0] = CUDA_PACKET;
-			req->reply[1] = 0;
-			req->reply[2] = CUDA_SET_TIME;
-			return pmu_queue_request(req);
-		}
-		break;
-	}
-	return -EINVAL;
-}
-
 int __openfirmware
 pmu_queue_request(struct adb_request *req)
 {
@@ -737,7 +757,7 @@
 {
 	struct adb_request req;
 
-	if (adb_hardware != ADB_VIAPMU)
+	if (vias == NULL)
 		return ;
 		
 	if (on) {
@@ -780,7 +800,7 @@
 {
 	int bright;
 
-	if (adb_hardware != ADB_VIAPMU)
+	if (vias == NULL)
 		return ;
 
 	backlight_level = level;
@@ -807,7 +827,7 @@
 {
 	struct adb_request req;
 
-	if (adb_hardware != ADB_VIAPMU)
+	if (vias == NULL)
 		return ;
 
 	pmu_request(&req, NULL, 2, PMU_POWER_CTRL, PMU_POW_IRLED |
@@ -860,6 +880,11 @@
 		;
 }
 
+int
+pmu_present(void)
+{
+	return (adb_controller && (adb_controller->kind == ADB_VIAPMU) && vias);
+}
 
 #ifdef CONFIG_PMAC_PBOOK
 
@@ -1104,3 +1129,4 @@
 		misc_register(&pmu_device);
 }
 #endif /* CONFIG_PMAC_PBOOK */
+
diff -u --recursive --new-file v2.2.7/linux/drivers/misc/parport_ieee1284.c linux/drivers/misc/parport_ieee1284.c
--- v2.2.7/linux/drivers/misc/parport_ieee1284.c	Tue Mar 23 14:35:47 1999
+++ linux/drivers/misc/parport_ieee1284.c	Mon May 10 10:26:31 1999
@@ -48,25 +48,22 @@
 int parport_ieee1284_nibble_mode_ok(struct parport *port, unsigned char mode) 
 {
 	/* make sure it's a valid state, set nStrobe & nAutoFeed high */
-	parport_write_control(port, (parport_read_control(port) \
-		& ~1 ) & ~2);
+	parport_frob_control (port, (1|2), 0);
 	udelay(1);
 	parport_write_data(port, mode);
 	udelay(400);
 	/* nSelectIn high, nAutoFd low */
-	parport_write_control(port, (parport_read_control(port) & ~8) | 2);
+	parport_frob_control(port, (2|8), 2);
 	if (parport_wait_peripheral(port, 0x78, 0x38)) {
-		parport_write_control(port, 
-				      (parport_read_control(port) & ~2) | 8);
+		parport_frob_control(port, (2|8), 8);
 		return 0; 
 	}
 	/* nStrobe low */
-	parport_write_control(port, parport_read_control(port) | 1);
+	parport_frob_control (port, 1, 1);
 	udelay(1);				     /* Strobe wait */
 	/* nStrobe high, nAutoFeed low, last step before transferring 
 	 *  reverse data */
-	parport_write_control(port, (parport_read_control(port) \
-		& ~1) & ~2);
+	parport_frob_control (port, (1|2), 0);
 	udelay(1);
 	/* Data available? */
 	parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK);
diff -u --recursive --new-file v2.2.7/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c
--- v2.2.7/linux/drivers/misc/parport_pc.c	Tue Mar 23 14:35:47 1999
+++ linux/drivers/misc/parport_pc.c	Mon May 10 10:26:31 1999
@@ -53,6 +53,8 @@
    than PARPORT_MAX (in <linux/parport.h>).  */
 #define PARPORT_PC_MAX_PORTS  8
 
+static int user_specified = 0;
+
 static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	parport_generic_irq(irq, (struct parport *) dev_id, regs);
@@ -103,19 +105,24 @@
 
 void parport_pc_write_control(struct parport *p, unsigned char d)
 {
+	struct parport_pc_private *priv = p->private_data;
+	priv->ctr = d;/* update soft copy */
 	outb(d, p->base+CONTROL);
 }
 
 unsigned char parport_pc_read_control(struct parport *p)
 {
-	return inb(p->base+CONTROL);
+	struct parport_pc_private *priv = p->private_data;
+	return priv->ctr;
 }
 
 unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask,  unsigned char val)
 {
-	unsigned char old = inb(p->base+CONTROL);
-	outb(((old & ~mask) ^ val), p->base+CONTROL);
-	return old;
+	struct parport_pc_private *priv = p->private_data;
+	unsigned char ctr = priv->ctr;
+	ctr = (ctr & ~mask) ^ val;
+	outb (ctr, p->base+CONTROL);
+	return priv->ctr = ctr; /* update soft copy */
 }
 
 void parport_pc_write_status(struct parport *p, unsigned char d)
@@ -345,6 +352,8 @@
  */
 static int parport_SPP_supported(struct parport *pb)
 {
+	unsigned char r, w;
+
 	/*
 	 * first clear an eventually pending EPP timeout 
 	 * I (sailer@ife.ee.ethz.ch) have an SMSC chipset
@@ -354,14 +363,54 @@
 	parport_pc_epp_clear_timeout(pb);
 
 	/* Do a simple read-write test to make sure the port exists. */
-	parport_pc_write_control(pb, 0xc);
-	parport_pc_write_data(pb, 0xaa);
-	if (parport_pc_read_data(pb) != 0xaa) return 0;
-	
-	parport_pc_write_data(pb, 0x55);
-	if (parport_pc_read_data(pb) != 0x55) return 0;
+	w = 0xc;
+	parport_pc_write_control(pb, w);
+
+	/* Can we read from the control register?  Some ports don't
+	 * allow reads, so read_control just returns a software
+	 * copy. Some ports _do_ allow reads, so bypass the software
+	 * copy here.  In addition, some bits aren't writable. */
+	r = inb (pb->base+CONTROL);
+	if ((r & 0x3f) == w) {
+		w = 0xe;
+		parport_pc_write_control (pb, w);
+		r = inb (pb->base+CONTROL);
+		parport_pc_write_control (pb, 0xc);
+		if ((r & 0x3f) == w)
+			return PARPORT_MODE_PCSPP;
+	}
+
+	if (user_specified)
+		/* That didn't work, but the user thinks there's a
+		 * port here. */
+		printk (KERN_DEBUG "0x%lx: CTR: wrote 0x%02x, read 0x%02x\n",
+			pb->base, w, r);
+
+	/* Try the data register.  The data lines aren't tri-stated at
+	 * this stage, so we expect back what we wrote. */
+	w = 0xaa;
+	parport_pc_write_data (pb, w);
+	r = parport_pc_read_data (pb);
+	if (r == w) {
+		w = 0x55;
+		parport_pc_write_data (pb, w);
+		r = parport_pc_read_data (pb);
+		if (r == w)
+			return PARPORT_MODE_PCSPP;
+	}
+
+	if (user_specified)
+		/* Didn't work with 0xaa, but the user is convinced
+		 * this is the place. */
+		printk (KERN_DEBUG "0x%lx: DATA: wrote 0x%02x, read 0x%02x\n",
+			pb->base, w, r);
+
+	/* It's possible that we can't read the control register or
+	   the data register.  In that case just believe the user. */
+	if (user_specified)
+		return PARPORT_MODE_PCSPP;
 
-	return PARPORT_MODE_PCSPP;
+	return 0;
 }
 
 /* Check for ECP
@@ -712,6 +761,15 @@
 	if (check_region(base, 3)) return 0;
 	if (!(p = parport_register_port(base, irq, dma, &parport_pc_ops)))
 		return 0;
+	p->private_data = kmalloc (sizeof (struct parport_pc_private),
+				   GFP_KERNEL);
+	if (!p->private_data) {
+		/* Not enough memory. */
+		printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base);
+		parport_unregister_port (p);
+		return 0;
+	}
+	((struct parport_pc_private *) (p->private_data))->ctr = 0xc;
 	if (p->base != 0x3bc) {
 		if (!check_region(base+0x400,3)) {
 			p->modes |= parport_ECR_present(p);	
@@ -725,6 +783,7 @@
 	}
 	if (!parport_SPP_supported(p)) {
 		/* No port. */
+		kfree (p->private_data);
 		parport_unregister_port (p);
 		return 0;
 	}
@@ -787,6 +846,7 @@
 	int count = 0, i = 0;
 	if (io && *io) {
 		/* Only probe the ports we were given. */
+		user_specified = 1;
 		do {
 			count += probe_one_port(*(io++), *(irq++), *(dma++));
 		} while (*io && (++i < PARPORT_PC_MAX_PORTS));
@@ -829,6 +889,7 @@
 			if (!(p->flags & PARPORT_FLAG_COMA)) 
 				parport_quiesce(p);
 			parport_proc_unregister(p);
+			kfree (p->private_data);
 			parport_unregister_port(p);
 		}
 		p = tmp;
diff -u --recursive --new-file v2.2.7/linux/drivers/net/3c507.c linux/drivers/net/3c507.c
--- v2.2.7/linux/drivers/net/3c507.c	Thu Feb 12 20:56:07 1998
+++ linux/drivers/net/3c507.c	Thu May  6 23:14:36 1999
@@ -40,6 +40,7 @@
 	info that the casual reader might think that it documents the i82586 :-<.
 */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/types.h>
@@ -53,6 +54,7 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
+#include <asm/spinlock.h>
 #include <linux/errno.h>
 
 #include <linux/netdevice.h>
@@ -123,6 +125,7 @@
 	ushort tx_head;
 	ushort tx_cmd_link;
 	ushort tx_reap;
+	spinlock_t lock;
 };
 
 /*
@@ -448,6 +451,7 @@
 	struct net_local *lp = (struct net_local *)dev->priv;
 	int ioaddr = dev->base_addr;
 	unsigned long shmem = dev->mem_start;
+	unsigned long flags;
 
 	if (dev->tbusy) 
 	{
@@ -487,7 +491,13 @@
 		lp->stats.tx_bytes+=length;
 		/* Disable the 82586's input to the interrupt line. */
 		outb(0x80, ioaddr + MISC_CTRL);
+#ifdef CONFIG_SMP
+		spin_lock_irqsave(&lp->lock, flags);
 		hardware_send_packet(dev, buf, length);
+		spin_unlock_irqrestore(&lp->lock, flags);
+#else
+		hardware_send_packet(dev, buf, length);
+#endif		
 		dev->trans_start = jiffies;
 		/* Enable the 82586 interrupt input. */
 		outb(0x84, ioaddr + MISC_CTRL);
@@ -515,11 +525,14 @@
 		return;
 	}
 	dev->interrupt = 1;
+	
 
 	ioaddr = dev->base_addr;
 	lp = (struct net_local *)dev->priv;
 	shmem = dev->mem_start;
 
+	spin_lock(&lp->lock);
+
 	status = readw(shmem+iSCB_STATUS);
 
 	if (net_debug > 4) {
@@ -598,6 +611,7 @@
 
 	/* Enable the 82586's interrupt input. */
 	outb(0x84, ioaddr + MISC_CTRL);
+	spin_unlock(&lp->lock);
 
 	return;
 }
diff -u --recursive --new-file v2.2.7/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- v2.2.7/linux/drivers/net/3c509.c	Tue Mar 23 14:35:47 1999
+++ linux/drivers/net/3c509.c	Thu May  6 14:02:34 1999
@@ -568,7 +568,7 @@
 		 */
 
 #ifdef __SMP__
-		disable_irq(dev->irq);
+		disable_irq_nosync(dev->irq);
 	    	spin_lock(&lp->lock);
 #endif	    	
 	    
diff -u --recursive --new-file v2.2.7/linux/drivers/net/8390.c linux/drivers/net/8390.c
--- v2.2.7/linux/drivers/net/8390.c	Wed Mar 10 15:29:46 1999
+++ linux/drivers/net/8390.c	Thu May  6 14:02:34 1999
@@ -257,8 +257,7 @@
 
 		/* Ugly but a reset can be slow, yet must be protected */
 		
-		disable_irq(dev->irq);
-		synchronize_irq();
+		disable_irq_nosync(dev->irq);
 		spin_lock(&ei_local->page_lock);
 		
 		/* Try to restart the card.  Perhaps the user has fixed something. */
@@ -286,8 +285,7 @@
 	 *	Slow phase with lock held.
 	 */
 	 
-	disable_irq(dev->irq);
-	synchronize_irq();
+	disable_irq_nosync(dev->irq);
 	
 	spin_lock(&ei_local->page_lock);
 	
diff -u --recursive --new-file v2.2.7/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- v2.2.7/linux/drivers/net/de4x5.c	Thu Dec 31 10:29:00 1998
+++ linux/drivers/net/de4x5.c	Sat May  8 19:46:44 1999
@@ -225,11 +225,18 @@
     to  determine this in  advance other than by  trial and error and common
     sense, e.g. call a BNC connectored port 'BNC', not '10Mb'.
 
-    TO DO:
-    ------
+    Changed the bus probing.  EISA used to be  done first,  followed by PCI.
+    Most people probably don't even know  what a de425 is today and the EISA
+    probe has messed  up some SCSI cards  in the past,  so now PCI is always
+    probed  first  followed by  EISA if  a) the architecture allows EISA and
+    either  b) there have been no PCI cards detected or  c) an EISA probe is
+    forced by  the user.  To force  a probe  include  "force_eisa"  in  your
+    insmod "args" line;  for built-in kernels either change the driver to do
+    this  automatically  or include  #define DE4X5_FORCE_EISA  on or  before
+    line 1040 in the driver.
 
-    o check what revision numbers the 21142 and 21143 have
-    o
+    TO DO: 
+    ------
 
     Revision History
     ----------------
@@ -416,11 +423,14 @@
 			   access traps. This flag is merely for log messages:
 			   should do something more definitive though...
       0.543  30-Dec-98    Add SMP spin locking.
-
+      0.544   8-May-99    Fix for buggy SROM in Motorola embedded boards using
+                           a 21143 by <mmporter@home.com>.
+			  Change PCI/EISA bus probing order.
+ 
     =========================================================================
 */
 
-static const char *version = "de4x5.c:V0.543 1998/12/30 davies@maniac.ultranet.com\n";
+static const char *version = "de4x5.c:V0.544 1999/5/8 davies@maniac.ultranet.com\n";
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -1027,8 +1037,11 @@
 #if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
 static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
 static int lastEISA = 0;
-#else
-static int lastEISA = MAX_EISA_SLOTS;           /* Only PCI probes */
+#  ifdef DE4X5_FORCE_EISA                 /* Force an EISA bus probe or not */
+static int forceEISA = 1;
+#  else
+static int forceEISA = 0;
+#  endif
 #endif
 static int num_de4x5s = 0;
 static int cfrv = 0, useSROM = 0;
@@ -1098,12 +1111,12 @@
 {
     u_long iobase = dev->base_addr;
 
+    pci_probe(dev, iobase);
 #if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
-    eisa_probe(dev, iobase);
-#endif
-    if (lastEISA == MAX_EISA_SLOTS) {
-	pci_probe(dev, iobase);
+    if ((lastPCI == NO_MORE_PCI) && ((num_de4x5s == 0) || forceEISA)) {
+        eisa_probe(dev, iobase);
     }
+#endif
     
     return (dev->priv ? 0 : -ENODEV);
 }
@@ -1230,6 +1243,7 @@
 	if ((tmp = (void *)kmalloc(RX_BUFF_SZ * NUM_RX_DESC + ALIGN, 
 				   GFP_KERNEL)) == NULL) {
 	    kfree(lp->cache.priv);
+	    lp->cache.priv = NULL;
 	    return -ENOMEM;
 	}
 
@@ -2066,38 +2080,36 @@
     }
     
     for (status = -ENODEV; (i<maxSlots) && (dev!=NULL); i++, iobase+=EISA_SLOT_INC) {
-	if (EISA_signature(name, EISA_ID)) {
-	    cfid = (u32) inl(PCI_CFID);
-	    cfrv = (u_short) inl(PCI_CFRV);
-	    device = (cfid >> 8) & 0x00ffff00;
-	    vendor = (u_short) cfid;
+	if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE)) continue;
+	if (!EISA_signature(name, EISA_ID)) continue;
+
+	cfid = (u32) inl(PCI_CFID);
+	cfrv = (u_short) inl(PCI_CFRV);
+	device = (cfid >> 8) & 0x00ffff00;
+	vendor = (u_short) cfid;
 	    
-	    /* Read the EISA Configuration Registers */
-	    irq = inb(EISA_REG0);
-	    irq = de4x5_irq[(irq >> 1) & 0x03];
-
-	    if (is_DC2114x) {
-		device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
-	    }
-	    lp->chipset = device;
-
-	    /* Write the PCI Configuration Registers */
-	    outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
-	    outl(0x00006000, PCI_CFLT);
-	    outl(iobase, PCI_CBIO);
+	/* Read the EISA Configuration Registers */
+	irq = inb(EISA_REG0);
+	irq = de4x5_irq[(irq >> 1) & 0x03];
+
+	if (is_DC2114x) {
+	    device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
+	}
+	lp->chipset = device;
+
+	/* Write the PCI Configuration Registers */
+	outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
+	outl(0x00006000, PCI_CFLT);
+	outl(iobase, PCI_CBIO);
 	    
-	    DevicePresent(EISA_APROM);
-	    if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) {
-		dev->irq = irq;
-		if ((status = de4x5_hw_init(dev, iobase)) == 0) {
-		    num_de4x5s++;
-		    if (loading_module) link_modules(lastModule, dev);
-		    lastEISA = i;
-		    return;
-		}
-	    } else if (ioaddr != 0) {
-		printk("%s: region already allocated at 0x%04lx.\n", dev->name,iobase);
-	    }
+	DevicePresent(EISA_APROM);
+
+	dev->irq = irq;
+	if ((status = de4x5_hw_init(dev, iobase)) == 0) {
+	    num_de4x5s++;
+	    if (loading_module) link_modules(lastModule, dev);
+	    lastEISA = i;
+	    return;
 	}
     }
 
@@ -4794,6 +4806,7 @@
     if (lp->state == INITIALISED) {
         lp->ibn = 3;
         lp->active = *p++;
+	if (MOTO_SROM_BUG) lp->active = 0;
 	lp->phy[lp->active].gep = (*p ? p : 0); p += (2 * (*p) + 1);
 	lp->phy[lp->active].rst = (*p ? p : 0); p += (2 * (*p) + 1);
 	lp->phy[lp->active].mc  = TWIDDLE(p); p += 2;
@@ -5326,6 +5339,9 @@
 	t = *q;
 	*q = '\0';
 
+#if !defined(__sparc_v9__) && !defined(__powerpc__) && !defined(__alpha__)
+	if (strstr(p, "force_eisa") || strstr(p, "FORCE_EISA")) forceEISA = 1;
+#endif
 	if (strstr(p, "fdx") || strstr(p, "FDX")) lp->params.fdx = 1;
 
 	if (strstr(p, "autosense") || strstr(p, "AUTOSENSE")) {
@@ -5766,6 +5782,12 @@
 		release_region(p->base_addr, (lp->bus == PCI ? 
 					      DE4X5_PCI_TOTAL_SIZE :
 					      DE4X5_EISA_TOTAL_SIZE));
+		if (lp->cache.buf) {        /* MAC buffers allocated?    */
+		    kfree(lp->cache.buf);   /* Free the MAC buffers      */
+		}
+		if (lp->cache.priv) {       /* Private area allocated?   */
+		    kfree(lp->cache.priv);  /* Free the private area     */
+		}
 	    }
 	    kfree(p);
 	} else {
@@ -5799,10 +5821,10 @@
 	if (lp->cache.buf) {                /* MAC buffers allocated?    */
 	    kfree(lp->cache.buf);           /* Free the MAC buffers      */
 	}
-	kfree(lp->cache.priv);              /* Free the private area     */
 	release_region(p->base_addr, (lp->bus == PCI ? 
 				      DE4X5_PCI_TOTAL_SIZE :
 				      DE4X5_EISA_TOTAL_SIZE));
+	kfree(lp->cache.priv);              /* Free the private area     */
     }
     unregister_netdev(p);
     kfree(p);                               /* Free the device structure */
@@ -5867,6 +5889,9 @@
  * Local variables:
  *  compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c"
  *
- *  compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c"
+ * Delete -D__SMP__ below if you didn't define this in your kernel
+ * Delete -DMODVERSIONS below if you didn't define this in your kernel
+ *
+ *  compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -DMODVERSIONS -include /linux/include/linux/modversions.h -c de4x5.c"
  * End:
  */
diff -u --recursive --new-file v2.2.7/linux/drivers/net/de4x5.h linux/drivers/net/de4x5.h
--- v2.2.7/linux/drivers/net/de4x5.h	Thu Dec 31 10:29:00 1998
+++ linux/drivers/net/de4x5.h	Sat May  8 19:46:44 1999
@@ -1027,3 +1027,5 @@
 #define DE4X5_GET_REG           0x0e /* Get the DE4X5 Registers */
 
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
+#define MOTO_SROM_BUG    ((lp->active == 8) && ((*((s32 *)le32_to_cpu(get_unaligned(dev->dev_addr)))&0x00ffffff)==0x3e0008))
diff -u --recursive --new-file v2.2.7/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c
--- v2.2.7/linux/drivers/net/eexpress.c	Tue Jan 19 11:32:51 1999
+++ linux/drivers/net/eexpress.c	Thu May  6 23:14:36 1999
@@ -83,6 +83,7 @@
  * practice.
  */
   
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -107,6 +108,8 @@
 #include <linux/skbuff.h>
 #include <linux/malloc.h>
 
+#include <asm/spinlock.h>
+
 #ifndef NET_DEBUG
 #define NET_DEBUG 4
 #endif
@@ -141,6 +144,7 @@
 	unsigned char width;         /* 0 for 16bit, 1 for 8bit */
 	unsigned char was_promisc;
 	unsigned char old_mc_count;
+	spinlock_t lock;
 };
 
 /* This is the code and data that is downloaded to the EtherExpress card's
@@ -502,6 +506,7 @@
 static int eexp_xmit(struct sk_buff *buf, struct device *dev)
 {
 	struct net_local *lp = (struct net_local *)dev->priv;
+	unsigned long flags;
 
 #if NET_DEBUG > 6
 	printk(KERN_DEBUG "%s: eexp_xmit()\n", dev->name);
@@ -509,6 +514,15 @@
 
 	disable_irq(dev->irq);
 
+	/*
+	 *	Best would be to use synchronize_irq(); spin_lock() here
+	 *	lets make it work first..
+	 */
+	 
+#ifdef CONFIG_SMP
+	spin_lock_irqsave(&lp->lock, flags);
+#endif
+
 	/* If dev->tbusy is set, all our tx buffers are full but the kernel
 	 * is calling us anyway.  Check that nothing bad is happening.
 	 */
@@ -516,7 +530,13 @@
 		int status = scb_status(dev);
   		unstick_cu(dev);
 		if ((jiffies - lp->last_tx) < HZ)
+		{
+#ifdef CONFIG_SMP
+			spin_unlock_irqrestore(&lp->lock, flags);
+#endif
+
 			return 1;
+		}
 		printk(KERN_INFO "%s: transmit timed out, %s?", dev->name,
 		       (SCB_complete(status)?"lost interrupt":
 			"board on fire"));
@@ -544,6 +564,9 @@
 	        eexp_hw_tx_pio(dev,data,length);
 	}
 	dev_kfree_skb(buf);
+#ifdef CONFIG_SMP
+	spin_unlock_irqrestore(&lp->lock, flags);
+#endif
 	enable_irq(dev->irq);
 	return 0;
 }
@@ -646,11 +669,14 @@
 	lp = (struct net_local *)dev->priv;
 	ioaddr = dev->base_addr;
 
+	spin_lock(&lp->lock);
+
 	old_read_ptr = inw(ioaddr+READ_PTR);
 	old_write_ptr = inw(ioaddr+WRITE_PTR);
 
 	outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
 
+	
 	dev->interrupt = 1;
 
 	status = scb_status(dev);
@@ -726,6 +752,8 @@
 #endif
 	outw(old_read_ptr, ioaddr+READ_PTR);
 	outw(old_write_ptr, ioaddr+WRITE_PTR);
+	
+	spin_unlock(&lp->lock);
 	return;
 }
 
diff -u --recursive --new-file v2.2.7/linux/drivers/net/epic100.c linux/drivers/net/epic100.c
--- v2.2.7/linux/drivers/net/epic100.c	Wed Jan 13 15:00:42 1999
+++ linux/drivers/net/epic100.c	Thu Apr 29 11:53:41 1999
@@ -1106,6 +1106,7 @@
 				memcpy(skb_put(skb, pkt_len),
 					   bus_to_virt(ep->rx_ring[entry].bufaddr), pkt_len);
 #endif
+				ep->rx_ring[entry].status = 0x8000;
 			} else {
 				skb_put(skb = ep->rx_skbuff[entry], pkt_len);
 				ep->rx_skbuff[entry] = NULL;
diff -u --recursive --new-file v2.2.7/linux/drivers/net/ethertap.c linux/drivers/net/ethertap.c
--- v2.2.7/linux/drivers/net/ethertap.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/net/ethertap.c	Mon May 10 09:55:25 1999
@@ -98,6 +98,7 @@
 
 	ether_setup(dev);
 
+	dev->hard_header_len = 16;
 	dev->tx_queue_len = 0;
 	dev->flags|=IFF_NOARP;
 	tap_map[dev->base_addr]=dev;
diff -u --recursive --new-file v2.2.7/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c
--- v2.2.7/linux/drivers/net/ibmtr.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/net/ibmtr.c	Fri May  7 10:57:42 1999
@@ -513,6 +513,7 @@
 	/* How much shared RAM is on adapter ? */
 #ifdef PCMCIA
 	ti->avail_shared_ram = pcmcia_reality_check(get_sram_size(ti));
+	ibmtr_mem_base = ti->sram_base ; 
 #else
 	ti->avail_shared_ram = get_sram_size(ti);
 #endif
@@ -1498,6 +1499,7 @@
 	       ti->asb + offsetof(struct asb_rec, rec_buf_addr));
 
 	lan_hdr_len=readb(ti->arb + offsetof(struct arb_rec_req, lan_hdr_len));
+	hdr_len = lan_hdr_len + sizeof(struct trllc) + sizeof(struct iphdr);
 	
 	llc=(rbuffer + offsetof(struct rec_buf, data) + lan_hdr_len);
 
@@ -1524,8 +1526,10 @@
 		return;
 	}
 
+	length = ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len)));
        	if ((readb(llc + offsetof(struct trllc, dsap))==EXTENDED_SAP) &&
-       	    (readb(llc + offsetof(struct trllc, ssap))==EXTENDED_SAP)) {
+       	    (readb(llc + offsetof(struct trllc, ssap))==EXTENDED_SAP) &&
+		(length>=hdr_len)) {
        		IPv4_p = 1;
        	}
 
@@ -1556,7 +1560,6 @@
        	}
 #endif
 
-       	length = ntohs(readw(ti->arb+offsetof(struct arb_rec_req, frame_len)));
        	skb_size = length-lan_hdr_len+sizeof(struct trh_hdr)+sizeof(struct trllc);
  
        	if (!(skb=dev_alloc_skb(skb_size))) {
@@ -1576,7 +1579,6 @@
 
 	if (IPv4_p) {
                 /* Copy the headers without checksumming */
-		hdr_len = lan_hdr_len + sizeof(struct trllc) + sizeof(struct iphdr);
 		memcpy_fromio(data, rbufdata, hdr_len);
 
 		/* Watch for padded packets and bogons */
diff -u --recursive --new-file v2.2.7/linux/drivers/net/ppp.c linux/drivers/net/ppp.c
--- v2.2.7/linux/drivers/net/ppp.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/net/ppp.c	Thu May  6 23:14:37 1999
@@ -241,6 +241,7 @@
 	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
 	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
 };
+EXPORT_SYMBOL(ppp_crc16_table);
 
 #ifdef CHECK_CHARACTERS
 static __u32 paritytab[8] =
diff -u --recursive --new-file v2.2.7/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c
--- v2.2.7/linux/drivers/net/via-rhine.c	Mon Dec 28 15:00:52 1998
+++ linux/drivers/net/via-rhine.c	Thu Apr 29 13:13:17 1999
@@ -1053,6 +1053,7 @@
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
 			dev->last_rx = jiffies;
+			np->stats.rx_bytes += pkt_len;
 			np->stats.rx_packets++;
 		}
 		entry = (++np->cur_rx) % RX_RING_SIZE;
diff -u --recursive --new-file v2.2.7/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c
--- v2.2.7/linux/drivers/net/wavelan.c	Tue Mar 23 14:35:48 1999
+++ linux/drivers/net/wavelan.c	Thu Apr 29 11:53:41 1999
@@ -324,6 +324,7 @@
 
   return crc_bytes;
 } /* psa_crc */
+#endif	/* SET_PSA_CRC */
 
 /*------------------------------------------------------------------*/
 /*
@@ -334,6 +335,7 @@
 		    u_long	ioaddr,
 		    u_short	hacr)
 {
+#ifdef SET_PSA_CRC
   psa_t		psa;
   u_short	crc;
 
@@ -363,8 +365,8 @@
   if(crc != 0)
     printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name);
 #endif /* DEBUG_IOCTL_INFO */
-} /* update_psa_checksum */
 #endif	/* SET_PSA_CRC */
+} /* update_psa_checksum */
 
 /*------------------------------------------------------------------*/
 /*
@@ -748,23 +750,23 @@
       unsigned short	ias_addr;
 
       /* Check mc_config command */
-      if((status & AC_SFLD_OK) != 0)
-	printk(KERN_INFO "wv_config_complete(): set_multicast_address failed; status = 0x%x\n",
-	       dev->name, str, status);
+      if((status & AC_SFLD_OK) != AC_SFLD_OK)
+	printk(KERN_INFO "%s: wv_config_complete(): set_multicast_address failed; status = 0x%x\n",
+	       dev->name, status);
 
       /* check ia-config command */
       ias_addr = mcs_addr - sizeof(ac_ias_t);
       obram_read(ioaddr, acoff(ias_addr, ac_status), (unsigned char *)&status, sizeof(status));
-      if((status & AC_SFLD_OK) != 0)
-	printk(KERN_INFO "wv_config_complete(): set_MAC_address; status = 0x%x\n",
-	       dev->name, str, status);
+      if((status & AC_SFLD_OK) != AC_SFLD_OK)
+	printk(KERN_INFO "%s: wv_config_complete(): set_MAC_address failed; status = 0x%x\n",
+	       dev->name, status);
 
       /* Check config command. */
       cfg_addr = ias_addr - sizeof(ac_cfg_t);
       obram_read(ioaddr, acoff(cfg_addr, ac_status), (unsigned char *)&status, sizeof(status));
-      if((status & AC_SFLD_OK) != 0)
-	printk(KERN_INFO "wv_config_complete(): configure; status = 0x%x\n",
-	       dev->name, str, status);
+      if((status & AC_SFLD_OK) != AC_SFLD_OK)
+	printk(KERN_INFO "%s: wv_config_complete(): configure failed; status = 0x%x\n",
+	       dev->name, status);
 #endif	/* DEBUG_CONFIG_ERROR */
 
       ret = 1;		/* Ready to be scrapped */
@@ -800,15 +802,15 @@
       /* Read the first transmit buffer */
       obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), (unsigned char *)&tx_status, sizeof(tx_status));
 
+      /* If not completed -> exit */
+      if((tx_status & AC_SFLD_C) == 0)
+	break;
+
       /* Hack for reconfiguration */
       if(tx_status == 0xFFFF)
 	if(!wv_config_complete(dev, ioaddr, lp))
 	  break;	/* Not completed */
 
-      /* If not completed -> exit */
-      if((tx_status & AC_SFLD_C) == 0)
-	break;
-
       /* We now remove this buffer */
       nreaped++;
       --lp->tx_n_in_use;
@@ -841,7 +843,7 @@
 	  lp->stats.tx_packets++;
 	  ncollisions = tx_status & AC_SFLD_MAXCOL;
 	  lp->stats.collisions += ncollisions;
-#ifdef DEBUG_INTERRUPT_INFO
+#ifdef DEBUG_TX_INFO
 	  if(ncollisions > 0)
 	    printk(KERN_DEBUG "%s: wv_complete(): tx completed after %d collisions.\n",
 		   dev->name, ncollisions);
@@ -850,53 +852,49 @@
       else
 	{
 	  lp->stats.tx_errors++;
-#ifndef IGNORE_NORMAL_XMIT_ERRS
 	  if(tx_status & AC_SFLD_S10)
 	    {
 	      lp->stats.tx_carrier_errors++;
-#ifdef DEBUG_INTERRUPT_ERROR
-	      printk(KERN_INFO "%s: wv_complete(): tx error: no CS.\n",
+#ifdef DEBUG_TX_FAIL
+	      printk(KERN_DEBUG "%s: wv_complete(): tx error: no CS.\n",
 		     dev->name);
 #endif
 	    }
-#endif	/* IGNORE_NORMAL_XMIT_ERRS */
 	  if(tx_status & AC_SFLD_S9)
 	    {
 	      lp->stats.tx_carrier_errors++;
-#ifdef DEBUG_INTERRUPT_ERROR
-	      printk(KERN_INFO "%s: wv_complete(): tx error: lost CTS.\n",
+#ifdef DEBUG_TX_FAIL
+	      printk(KERN_DEBUG "%s: wv_complete(): tx error: lost CTS.\n",
 		     dev->name);
 #endif
 	    }
 	  if(tx_status & AC_SFLD_S8)
 	    {
 	      lp->stats.tx_fifo_errors++;
-#ifdef DEBUG_INTERRUPT_ERROR
-	      printk(KERN_INFO "%s: wv_complete(): tx error: slow DMA.\n",
+#ifdef DEBUG_TX_FAIL
+	      printk(KERN_DEBUG "%s: wv_complete(): tx error: slow DMA.\n",
 		     dev->name);
 #endif
 	    }
-#ifndef IGNORE_NORMAL_XMIT_ERRS
 	  if(tx_status & AC_SFLD_S6)
 	    {
 	      lp->stats.tx_heartbeat_errors++;
-#ifdef DEBUG_INTERRUPT_ERROR
-	      printk(KERN_INFO "%s: wv_complete(): tx error: heart beat.\n",
+#ifdef DEBUG_TX_FAIL
+	      printk(KERN_DEBUG "%s: wv_complete(): tx error: heart beat.\n",
 		     dev->name);
 #endif
 	    }
 	  if(tx_status & AC_SFLD_S5)
 	    {
 	      lp->stats.tx_aborted_errors++;
-#ifdef DEBUG_INTERRUPT_ERROR
-	      printk(KERN_INFO "%s: wv_complete(): tx error: too many collisions.\n",
+#ifdef DEBUG_TX_FAIL
+	      printk(KERN_DEBUG "%s: wv_complete(): tx error: too many collisions.\n",
 		     dev->name);
 #endif
 	    }
-#endif	/* IGNORE_NORMAL_XMIT_ERRS */
 	}
 
-#ifdef DEBUG_INTERRUPT_INFO
+#ifdef DEBUG_TX_INFO
       printk(KERN_DEBUG "%s: wv_complete(): tx completed, tx_status 0x%04x\n",
 	     dev->name, tx_status);
 #endif
@@ -1323,21 +1321,21 @@
 	       char *		msg1,		/* Name of the device */
 	       char *		msg2)		/* Name of the function */
 {
-#ifndef DEBUG_PACKET_DUMP
+  int		i;
+  int		maxi;
+
   printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n",
 	 msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length);
   printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n",
 	 msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]);
 
-#else	/* DEBUG_PACKET_DUMP */
-  int		i;
-  int		maxi;
+#ifdef DEBUG_PACKET_DUMP
 
-  printk(KERN_DEBUG "%s: %s(): len=%d, data=\"", msg1, msg2, length);
+  printk(KERN_DEBUG "data=\"");
 
   if((maxi = length) > DEBUG_PACKET_DUMP)
     maxi = DEBUG_PACKET_DUMP;
-  for(i = 0; i < maxi; i++)
+  for(i = 14; i < maxi; i++)
     if(p[i] >= ' ' && p[i] <= '~')
       printk(" %c", p[i]);
     else
@@ -1564,7 +1562,9 @@
 /*------------------------------------------------------------------*/
 /*
  * This function doesn't exist.
+ * (Note : it was a nice way to test the reconfigure stuff...)
  */
+#ifdef SET_MAC_ADDRESS
 static int
 wavelan_set_mac_address(device *	dev,
 			void *		addr)
@@ -1579,6 +1579,7 @@
 
   return 0;
 }
+#endif	/* SET_MAC_ADDRESS */
 
 #ifdef WIRELESS_EXT	/* if wireless extensions exist in the kernel */
 
@@ -1932,10 +1933,8 @@
 	  /* Disable NWID in the mmc (no filtering). */
 	  mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID);
 	}
-#ifdef SET_PSA_CRC
       /* update the Wavelan checksum */
       update_psa_checksum(dev, ioaddr, lp->hacr);
-#endif
       break;
 
     case SIOCGIWNWID:
@@ -1992,10 +1991,8 @@
       psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F;
       psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa,
 	       (unsigned char *) &psa.psa_thr_pre_set, 1);
-#ifdef SET_PSA_CRC
       /* update the Wavelan checksum */
       update_psa_checksum(dev, ioaddr, lp->hacr);
-#endif
       mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set);
       break;
 
@@ -2043,10 +2040,8 @@
 
 	   mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0);
 	 }
-#ifdef SET_PSA_CRC
        /* update the Wavelan checksum */
        update_psa_checksum(dev, ioaddr, lp->hacr);
-#endif
        break;
 
      case SIOCGIWENCODE:
@@ -2260,10 +2255,8 @@
       psa.psa_quality_thr = *(wrq->u.name) & 0x0F;
       psa_write(ioaddr, lp->hacr, (char *)&psa.psa_quality_thr - (char *)&psa,
 	       (unsigned char *)&psa.psa_quality_thr, 1);
-#ifdef SET_PSA_CRC
       /* update the Wavelan checksum */
       update_psa_checksum(dev, ioaddr, lp->hacr);
-#endif
       mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr);
       break;
 
@@ -2426,7 +2419,7 @@
 
 #ifdef DEBUG_RX_TRACE
   printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n",
-	 dev->name, fd_p, sksize);
+	 dev->name, buf_off, sksize);
 #endif
 
   /* Allocate buffer for the data */
@@ -2514,6 +2507,8 @@
 {
   u_long	ioaddr = dev->base_addr;
   net_local *	lp = (net_local *)dev->priv;
+  fd_t		fd;
+  rbd_t		rbd;
   int		nreaped = 0;
 
 #ifdef DEBUG_RX_TRACE
@@ -2523,12 +2518,17 @@
   /* Loop on each received packet. */
   for(;;)
     {
-      fd_t		fd;
-      rbd_t		rbd;
-      ushort		pkt_len;
-
       obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd, sizeof(fd));
 
+      /* Note about the status :
+       * It start up to be 0 (the value we set). Then, when the RU
+       * grab the buffer to prepare for reception, it sets the
+       * FD_STATUS_B flag. When the RU has finished receiving the
+       * frame, it clears FD_STATUS_B, set FD_STATUS_C to indicate
+       * completion and set the other flags to indicate the eventual
+       * errors. FD_STATUS_OK indicates that the reception was OK.
+       */
+
       /* If the current frame is not complete, we have reached the end. */
       if((fd.fd_status & FD_STATUS_C) != FD_STATUS_C)
 	break;		/* This is how we exit the loop. */
@@ -2536,35 +2536,44 @@
       nreaped++;
 
       /* Check whether frame was correctly received. */
-      if((fd.fd_status & (FD_STATUS_B | FD_STATUS_OK)) !=
-	 (FD_STATUS_B | FD_STATUS_OK))
+      if((fd.fd_status & FD_STATUS_OK) == FD_STATUS_OK)
 	{
-	  /*
-	   * Not sure about this one -- it does not seem
-	   * to be an error so we will keep quiet about it.
-	   */
-#ifndef IGNORE_NORMAL_XMIT_ERRS
-#ifdef DEBUG_RX_ERROR
-	  if((fd.fd_status & FD_STATUS_B) != FD_STATUS_B)
-	    printk(KERN_INFO "%s: wv_receive(): frame not consumed by RU.\n",
-		   dev->name);
-#endif
-#endif	/* IGNORE_NORMAL_XMIT_ERRS */
+	  /* Does the frame contain a pointer to the data?  Let's check. */
+	  if(fd.fd_rbd_offset != I82586NULL)
+	    {
+	      /* Read the receive buffer descriptor */
+	      obram_read(ioaddr, fd.fd_rbd_offset,
+			 (unsigned char *) &rbd, sizeof(rbd));
 
 #ifdef DEBUG_RX_ERROR
-	  if((fd.fd_status & FD_STATUS_OK) != FD_STATUS_OK)
-	    printk(KERN_INFO "%s: wv_receive(): frame not received successfully.\n",
+	      if((rbd.rbd_status & RBD_STATUS_EOF) != RBD_STATUS_EOF)
+		printk(KERN_INFO "%s: wv_receive(): missing EOF flag.\n",
+		       dev->name);
+
+	      if((rbd.rbd_status & RBD_STATUS_F) != RBD_STATUS_F)
+		printk(KERN_INFO "%s: wv_receive(): missing F flag.\n",
+		       dev->name);
+#endif	/* DEBUG_RX_ERROR */
+
+	      /* Read the packet and transmit to Linux */
+	      wv_packet_read(dev, rbd.rbd_bufl,
+			     rbd.rbd_status & RBD_STATUS_ACNT);
+	    }
+#ifdef DEBUG_RX_ERROR
+	  else	/* if frame has no data */
+	    printk(KERN_INFO "%s: wv_receive(): frame has no data.\n",
 		   dev->name);
 #endif
 	}
-
-      /* Were there problems in processing the frame?  Let's check. */
-      if((fd.fd_status & (FD_STATUS_S6 | FD_STATUS_S7 | FD_STATUS_S8 |
-			  FD_STATUS_S9 | FD_STATUS_S10 | FD_STATUS_S11))
-	 != 0)
+      else	/* If reception was no successful */
 	{
 	  lp->stats.rx_errors++;
 
+#ifdef DEBUG_RX_INFO
+	  printk(KERN_DEBUG "%s: wv_receive(): frame not received successfully (%X).\n",
+		 dev->name, fd.fd_status);
+#endif
+
 #ifdef DEBUG_RX_ERROR
 	  if((fd.fd_status & FD_STATUS_S6) != 0)
 	    printk(KERN_INFO "%s: wv_receive(): no EOF flag.\n", dev->name);
@@ -2573,8 +2582,8 @@
 	  if((fd.fd_status & FD_STATUS_S7) != 0)
 	    {
 	      lp->stats.rx_length_errors++;
-#ifdef DEBUG_RX_ERROR
-	      printk(KERN_INFO "%s: wv_receive(): frame too short.\n",
+#ifdef DEBUG_RX_FAIL
+	      printk(KERN_DEBUG "%s: wv_receive(): frame too short.\n",
 		     dev->name);
 #endif
 	    }
@@ -2582,8 +2591,8 @@
 	  if((fd.fd_status & FD_STATUS_S8) != 0)
 	    {
 	      lp->stats.rx_over_errors++;
-#ifdef DEBUG_RX_ERROR
-	      printk(KERN_INFO "%s: wv_receive(): rx DMA overrun.\n",
+#ifdef DEBUG_RX_FAIL
+	      printk(KERN_DEBUG "%s: wv_receive(): rx DMA overrun.\n",
 		     dev->name);
 #endif
 	    }
@@ -2591,8 +2600,8 @@
 	  if((fd.fd_status & FD_STATUS_S9) != 0)
 	    {
 	      lp->stats.rx_fifo_errors++;
-#ifdef DEBUG_RX_ERROR
-	      printk(KERN_INFO "%s: wv_receive(): ran out of resources.\n",
+#ifdef DEBUG_RX_FAIL
+	      printk(KERN_DEBUG "%s: wv_receive(): ran out of resources.\n",
 		     dev->name);
 #endif
 	    }
@@ -2600,8 +2609,8 @@
 	  if((fd.fd_status & FD_STATUS_S10) != 0)
 	    {
 	      lp->stats.rx_frame_errors++;
-#ifdef DEBUG_RX_ERROR
-	      printk(KERN_INFO "%s: wv_receive(): alignment error.\n",
+#ifdef DEBUG_RX_FAIL
+	      printk(KERN_DEBUG "%s: wv_receive(): alignment error.\n",
 		     dev->name);
 #endif
 	    }
@@ -2609,38 +2618,12 @@
 	  if((fd.fd_status & FD_STATUS_S11) != 0)
 	    {
 	      lp->stats.rx_crc_errors++;
-#ifdef DEBUG_RX_ERROR
-	      printk(KERN_INFO "%s: wv_receive(): CRC error.\n", dev->name);
+#ifdef DEBUG_RX_FAIL
+	      printk(KERN_DEBUG "%s: wv_receive(): CRC error.\n", dev->name);
 #endif
 	    }
 	}
 
-      /* Does the frame contain a pointer to the data?  Let's check. */
-      if(fd.fd_rbd_offset == I82586NULL)
-#ifdef DEBUG_RX_ERROR
-	printk(KERN_INFO "%s: wv_receive(): frame has no data.\n", dev->name);
-#endif
-      else
-	{
-	  obram_read(ioaddr, fd.fd_rbd_offset,
-		     (unsigned char *) &rbd, sizeof(rbd));
-
-#ifdef DEBUG_RX_ERROR
-	  if((rbd.rbd_status & RBD_STATUS_EOF) != RBD_STATUS_EOF)
-	    printk(KERN_INFO "%s: wv_receive(): missing EOF flag.\n",
-		   dev->name);
-
-	  if((rbd.rbd_status & RBD_STATUS_F) != RBD_STATUS_F)
-	    printk(KERN_INFO "%s: wv_receive(): missing F flag.\n",
-		   dev->name);
-#endif
-
-	  pkt_len = rbd.rbd_status & RBD_STATUS_ACNT;
-
-	  /* Read the packet and transmit to Linux */
-	  wv_packet_read(dev, rbd.rbd_bufl, pkt_len);
-	}	/* if frame has data */
-
       fd.fd_status = 0;
       obram_write(ioaddr, fdoff(lp->rx_head, fd_status),
 		  (unsigned char *) &fd.fd_status, sizeof(fd.fd_status));
@@ -2775,7 +2758,7 @@
   /*
    * Data
    */
-  obram_write(ioaddr, buf_addr, buf, clen);
+  obram_write(ioaddr, buf_addr, buf, length);
 
   /*
    * Overwrite the predecessor NOP link
@@ -2950,11 +2933,9 @@
 		(unsigned char *)&psa.psa_quality_thr, 1);
       psa_write(ioaddr, lp->hacr, (char *)&psa.psa_conf_status - (char *)&psa,
 		(unsigned char *)&psa.psa_conf_status, 1);
-#ifdef SET_PSA_CRC
       /* update the Wavelan checksum */
       update_psa_checksum(dev, ioaddr, lp->hacr);
 #endif
-#endif
     }
 
   /* Zero the mmc structure. */
@@ -3125,7 +3106,7 @@
 
   if(i <= 0)
     {
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
       printk(KERN_INFO "%s: wavelan_ru_start(): board not accepting command.\n",
 	     dev->name);
 #endif
@@ -3229,7 +3210,7 @@
 
   if(i <= 0)
     {
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
       printk(KERN_INFO "%s: wavelan_cu_start(): board not accepting command.\n",
 	     dev->name);
 #endif
@@ -3316,7 +3297,7 @@
 
   if(i <= 0)
     {
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
       printk(KERN_INFO "%s: wv_82586_start(): iscp_busy timeout.\n",
 	     dev->name);
 #endif
@@ -3336,7 +3317,7 @@
 
   if (i <= 0)
     {
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
       printk(KERN_INFO "%s: wv_82586_start(): status: expected 0x%02x, got 0x%02x.\n",
 	     dev->name, SCB_ST_CX | SCB_ST_CNA, scb.scb_status);
 #endif
@@ -3357,7 +3338,7 @@
   obram_read(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb));
   if(cb.ac_status & AC_SFLD_FAIL)
     {
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
       printk(KERN_INFO "%s: wv_82586_start(): i82586 Self Test failed.\n",
 	     dev->name);
 #endif
@@ -3638,13 +3619,16 @@
   wv_ints_on(dev);
 
   /* Start card functions */
-  if((wv_ru_start(dev) < 0) ||
-     (wv_cu_start(dev) < 0))
+  if(wv_cu_start(dev) < 0)
     return -1;
 
-  /* Finish configuration. */
+  /* Setup the controller and parameters */
   wv_82586_config(dev);
 
+  /* Finish configuration with the receive unit */
+  if(wv_ru_start(dev) < 0)
+    return -1;
+
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name);
 #endif
@@ -3945,7 +3929,7 @@
   /* Check irq */
   if(dev->irq == 0)
     {
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
       printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n", dev->name);
 #endif
       return -ENXIO;
@@ -3953,7 +3937,7 @@
 
   if(request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", dev) != 0)
     {
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
       printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n", dev->name);
 #endif
       return -EAGAIN;
@@ -3968,7 +3952,7 @@
   else
     {
       free_irq(dev->irq, dev);
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
       printk(KERN_INFO "%s: wavelan_open(): impossible to start the card\n",
 	     dev->name);
 #endif
@@ -4065,10 +4049,8 @@
 #endif
 	  psa_write(ioaddr, HACR_DEFAULT,
 		    psaoff(0, psa_int_req_no), &irq_mask, 1);
-#ifdef SET_PSA_CRC
 	  /* update the Wavelan checksum */
 	  update_psa_checksum(dev, ioaddr, HACR_DEFAULT);
-#endif
 	  wv_hacr_reset(ioaddr);
 	}
     }
@@ -4122,7 +4104,9 @@
   dev->hard_start_xmit = wavelan_packet_xmit;
   dev->get_stats = wavelan_get_stats;
   dev->set_multicast_list = &wavelan_set_multicast_list;
+#ifdef SET_MAC_ADDRESS
   dev->set_mac_address = &wavelan_set_mac_address;
+#endif	/* SET_MAC_ADDRESS */
 
 #ifdef WIRELESS_EXT	/* if wireless extension exists in the kernel */
   dev->do_ioctl = wavelan_ioctl;
@@ -4176,7 +4160,7 @@
   /* Don't probe at all. */
   if(base_addr < 0)
     {
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
       printk(KERN_WARNING "%s: wavelan_probe(): invalid base address\n",
 	     dev->name);
 #endif
@@ -4259,7 +4243,7 @@
   /* If probing is asked */
   if(io[0] == 0)
     {
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
       printk(KERN_WARNING "WaveLAN init_module(): doing device probing (bad !)\n");
       printk(KERN_WARNING "Specify base addresses while loading module to correct the problem\n");
 #endif
@@ -4303,7 +4287,7 @@
 	}	/* if there is something at the address */
     }		/* Loop on all addresses. */
 
-#ifdef DEBUG_CONFIG_ERRORS
+#ifdef DEBUG_CONFIG_ERROR
   if(wavelan_list == (net_local *) NULL)
     printk(KERN_WARNING "WaveLAN init_module(): no device found\n");
 #endif
diff -u --recursive --new-file v2.2.7/linux/drivers/net/wavelan.p.h linux/drivers/net/wavelan.p.h
--- v2.2.7/linux/drivers/net/wavelan.p.h	Tue Mar 23 14:35:48 1999
+++ linux/drivers/net/wavelan.p.h	Thu Apr 29 11:53:41 1999
@@ -34,16 +34,22 @@
  *	I try to maintain a web page with the Wireless LAN Howto at :
  *		http://www-uk.hpl.hp.com/people/jt/Linux/Wavelan.html
  *
+ * Debugging and options
+ * ---------------------
+ *	You will find below a set of '#define" allowing a very fine control
+ *	on the driver behaviour and the debug messages printed.
+ *	The main options are :
+ *	o SET_PSA_CRC, to have your card correctly recognised by
+ *	  an access point and the Point-to-Point diagnostic tool.
+ *	o USE_PSA_CONFIG, to read configuration from the PSA (EEprom)
+ *	  (otherwise we always start afresh with some defaults)
+ *
  * wavelan.o is too darned big
  * ---------------------------
  *	That's true!  There is a very simple way to reduce the driver
  *	object by 33%!  Comment out the following line:
  *		#include <linux/wireless.h>
- *
- * Debugging and options
- * ---------------------
- *	You will find below a set of '#define" allowing a very fine control
- *	on the driver behaviour and the debug messages printed.
+ *	Other compile options can also reduce the size of it...
  *
  * MAC address and hardware detection:
  * -----------------------------------
@@ -274,7 +280,17 @@
  *	- Correct i82586 configuration parameters
  *	- Encryption initialisation bug (Robert McCormack)
  *	- New mac addresses detected in the probe
- *	- Increase watchdog for busy envirnoments
+ *	- Increase watchdog for busy environments
+ *
+ * Changes made for release in 2.0.38 & 2.2.7 :
+ * ------------------------------------------
+ *	- Correct the reception logic to better report errors and avoid
+ *	  sending bogus packet up the stack
+ *	- Delay RU config to avoid corrupting first received packet
+ *	- Change config completion code (to actually check something)
+ *	- Avoid reading out of bound in skbuf to transmit
+ *	- Rectify a lot of (useless) debugging code
+ *	- Change the way to `#ifdef SET_PSA_CRC'
  *
  * Wishes & dreams:
  * ----------------
@@ -315,6 +331,24 @@
 #include	"i82586.h"
 #include	"wavelan.h"
 
+/************************** DRIVER OPTIONS **************************/
+/*
+ * `#define' or `#undef' the following constant to change the behaviour
+ * of the driver...
+ */
+#undef SET_PSA_CRC		/* Calculate and set the CRC on PSA (slower) */
+#define USE_PSA_CONFIG		/* Use info from the PSA. */
+#undef STRUCT_CHECK		/* Verify padding of structures. */
+#undef EEPROM_IS_PROTECTED	/* doesn't seem to be necessary */
+#define MULTICAST_AVOID		/* Avoid extra multicast (I'm sceptical). */
+#undef SET_MAC_ADDRESS		/* Experimental */
+
+#ifdef WIRELESS_EXT	/* If wireless extensions exist in the kernel */
+/* Warning:  this stuff will slow down the driver. */
+#define WIRELESS_SPY		/* Enable spying addresses. */
+#undef HISTOGRAM		/* Enable histogram of signal level. */
+#endif
+
 /****************************** DEBUG ******************************/
 
 #undef DEBUG_MODULE_TRACE	/* module insertion/removal */
@@ -324,14 +358,16 @@
 #define DEBUG_INTERRUPT_ERROR	/* problems */
 #undef DEBUG_CONFIG_TRACE	/* Trace the config functions. */
 #undef DEBUG_CONFIG_INFO	/* what's going on */
-#define DEBUG_CONFIG_ERRORS	/* errors on configuration */
+#define DEBUG_CONFIG_ERROR	/* errors on configuration */
 #undef DEBUG_TX_TRACE		/* transmission calls */
 #undef DEBUG_TX_INFO		/* header of the transmitted packet */
-#define DEBUG_TX_ERROR		/* unexpected conditions */
+#undef DEBUG_TX_FAIL		/* Normal failure conditions */
+#define DEBUG_TX_ERROR		/* Unexpected conditions */
 #undef DEBUG_RX_TRACE		/* transmission calls */
-#undef DEBUG_RX_INFO		/* header of the transmitted packet */
-#define DEBUG_RX_ERROR		/* unexpected conditions */
-#undef DEBUG_PACKET_DUMP	16	/* Dump packet on the screen. */
+#undef DEBUG_RX_INFO		/* header of the received packet */
+#undef DEBUG_RX_FAIL		/* Normal failure conditions */
+#define DEBUG_RX_ERROR		/* Unexpected conditions */
+#undef DEBUG_PACKET_DUMP	32	/* Dump packet on the screen. */
 #undef DEBUG_IOCTL_TRACE	/* misc. call by Linux */
 #undef DEBUG_IOCTL_INFO		/* various debugging info */
 #define DEBUG_IOCTL_ERROR	/* what's going wrong */
@@ -343,26 +379,10 @@
 #undef DEBUG_I82586_SHOW	/* Show i82586 status. */
 #undef DEBUG_DEVICE_SHOW	/* Show device parameters. */
 
-/* Options */
-#define USE_PSA_CONFIG		/* Use info from the PSA. */
-#define SET_PSA_CRC		/* Calculate and set the CRC on PSA */
-#define IGNORE_NORMAL_XMIT_ERRS	/* Don't bother with normal conditions. */
-#undef STRUCT_CHECK		/* Verify padding of structures. */
-#undef OLDIES			/* old code (to redo) */
-#undef RECORD_SNR		/* to redo */
-#undef EEPROM_IS_PROTECTED	/* doesn't seem to be necessary */
-#define MULTICAST_AVOID		/* Avoid extra multicast (I'm sceptical). */
-
-#ifdef WIRELESS_EXT	/* If wireless extensions exist in the kernel */
-/* Warning:  this stuff will slow down the driver. */
-#define WIRELESS_SPY		/* Enable spying addresses. */
-#undef HISTOGRAM		/* Enable histogram of signal level. */
-#endif
-
 /************************ CONSTANTS & MACROS ************************/
 
 #ifdef DEBUG_VERSION_SHOW
-static const char	*version	= "wavelan.c : v18 (wireless extensions) 18/2/99\n";
+static const char	*version	= "wavelan.c : v19 (wireless extensions) 20/4/99\n";
 #endif
 
 /* Watchdog temporisation */
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in
--- v2.2.7/linux/drivers/scsi/Config.in	Fri Apr 16 14:47:30 1999
+++ linux/drivers/scsi/Config.in	Thu Apr 29 11:53:41 1999
@@ -55,9 +55,7 @@
 dep_tristate 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO $CONFIG_SCSI
 dep_tristate 'Future Domain 16xx SCSI/AHA-2920A support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI
 if [ "$CONFIG_MCA" = "y" ]; then
-  if [ "$CONFIG_SCSI" = "y" ]; then
-    bool 'Future Domain MCS-600/700 SCSI support' CONFIG_SCSI_FD_MCS
-  fi
+    dep_tristate 'Future Domain MCS-600/700 SCSI support' CONFIG_SCSI_FD_MCS $CONFIG_SCSI
 fi
 dep_tristate 'GDT SCSI Disk Array Controller support' CONFIG_SCSI_GDTH $CONFIG_SCSI
 dep_tristate 'Generic NCR5380/53c400 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 $CONFIG_SCSI
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- v2.2.7/linux/drivers/scsi/Makefile	Fri Apr 16 14:47:30 1999
+++ linux/drivers/scsi/Makefile	Thu Apr 29 11:53:41 1999
@@ -533,8 +533,11 @@
 
 ifeq ($(CONFIG_SCSI_FD_MCS),y)
 L_OBJS += fd_mcs.o
+else
+  ifeq ($(CONFIG_SCSI_FD_MCS),m)
+  M_OBJS += fd_mcs.o
+  endif
 endif
-
 
 ifeq ($(CONFIG_SCSI_T128),y)
 L_OBJS += t128.o
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/imm.c linux/drivers/scsi/imm.c
--- v2.2.7/linux/drivers/scsi/imm.c	Tue Feb 23 15:21:33 1999
+++ linux/drivers/scsi/imm.c	Fri May  7 10:57:42 1999
@@ -881,6 +881,7 @@
 {
     imm_struct *tmp = (imm_struct *) data;
     Scsi_Cmnd *cmd = tmp->cur_cmd;
+    unsigned long flags;
 
     if (!cmd) {
 	printk("IMM: bug in imm_interrupt\n");
@@ -931,8 +932,10 @@
     if (cmd->SCp.phase > 0)
 	imm_pb_release(cmd->host->unique_id);
 
+    spin_lock_irqsave(&io_request_lock, flags);
     tmp->cur_cmd = 0;
     cmd->scsi_done(cmd);
+    spin_unlock_irqrestore(&io_request_lock, flags);
     return;
 }
 
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
--- v2.2.7/linux/drivers/scsi/megaraid.c	Fri Apr 16 14:47:31 1999
+++ linux/drivers/scsi/megaraid.c	Thu May  6 23:14:37 1999
@@ -9,7 +9,7 @@
  *              as published by the Free Software Foundation; either version
  *              2 of the License, or (at your option) any later version.
  *
- * Version : 0.96
+ * Version : 1.00
  * 
  * Description: Linux device driver for AMI MegaRAID controller
  *
@@ -73,19 +73,37 @@
  *
  * Version 0.96:
  *     762 fully supported.
+ * Version 0.97:
+ *     Changed megaraid_command to use wait_queue.
+ *     Fixed bug of undesirably detecting HP onboard controllers which
+ *      are disabled.
+ *     
+ * Version 1.00:
+ *     Checks to see if an irq ocurred while in isr, and runs through
+ *        routine again.
+ *     Copies mailbox to temp area before processing in isr
+ *     Added barrier() in busy wait to fix volatility bug
+ *     Uses separate list for freed Scbs, keeps track of cmd state
+ *     Put spinlocks around entire queue function for now...
+ *     Full multi-io commands working stablely without previous problems
+ *     Added skipXX LILO option for Madrona motherboard support
+ *
  *
  * BUGS:
  *     Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
  *     fails to detect the controller as a pci device on the system.
  *
+ *     Timeout period for mid scsi layer is too short for
+ *     this controller.  Must be increased or Aborts will occur.
+ *
  *===================================================================*/
 
 #define CRLFSTR "\n"
 
-#include <linux/config.h>
 #include <linux/version.h>
 
 #ifdef MODULE
+#include <linux/modversions.h>
 #include <linux/module.h>
 
 #if LINUX_VERSION_CODE >= 0x20100
@@ -213,14 +231,15 @@
  *
  *================================================================
  */
-static int MegaIssueCmd (mega_host_config * megaCfg,
+static int megaIssueCmd (mega_host_config * megaCfg,
 			 u_char * mboxData,
 			 mega_scb * scb,
 			 int intr);
 static int build_sglist (mega_host_config * megaCfg, mega_scb * scb,
 			 u_long * buffer, u_long * length);
 
-static void mega_runque (void *);
+static int mega_busyWaitMbox(mega_host_config *);
+static void mega_runpendq (mega_host_config *);
 static void mega_rundoneq (void);
 static void mega_cmd_done (mega_host_config *, mega_scb *, int);
 static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt);
@@ -241,15 +260,34 @@
  *
  *================================================================
  */
+
+/*  Use "megaraid=skipXX" to prohibit driver from scanning XX scsi id
+     on each channel.  Used for Madrona motherboard, where SAF_TE
+     processor id cannot be scanned */
+static char *megaraid;
+#if LINUX_VERSION_CODE > 0x20100
+#ifdef MODULE
+MODULE_PARM(megaraid, "s");
+#endif
+#endif
+static int skip_id;
+
 static int numCtlrs = 0;
 static mega_host_config *megaCtlrs[12] = {0};
 
+#if DEBUG
+static u_long maxCmdTime = 0;
+#endif
+
+static mega_scb *pLastScb = NULL;
+
 /* Queue of pending/completed SCBs */
-static mega_scb *qPending = NULL;
 static Scsi_Cmnd *qCompleted = NULL;
 
+#if SERDEBUG
+volatile static spinlock_t serial_lock;
+#endif
 volatile static spinlock_t mega_lock;
-static struct tq_struct runq = {0, 0, mega_runque, NULL};
 
 struct proc_dir_entry proc_scsi_megaraid =
 {
@@ -299,10 +337,12 @@
   int i;
   long flags;
 
+  spin_lock_irqsave(&serial_lock,flags);
   va_start (args, fmt);
   i = vsprintf (strbuf, fmt, args);
   ser_puts (strbuf);
   va_end (args);
+  spin_unlock_irqrestore(&serial_lock,flags);
 
   return i;
 }
@@ -329,27 +369,28 @@
  *
  *-------------------------------------------------------------------------*/
 
-/*================================================
- * Initialize SCB structures
- *================================================
+/*=======================
+ * Free a SCB structure
+ *=======================
  */
-static int initSCB (mega_host_config * megaCfg)
+static void freeSCB (mega_host_config *megaCfg, mega_scb * pScb)
 {
-  int idx;
+  mega_scb **ppScb;
 
-  for (idx = 0; idx < megaCfg->max_cmds; idx++) {
-    megaCfg->scbList[idx].idx = -1;
-    megaCfg->scbList[idx].flag = 0;
-    megaCfg->scbList[idx].sgList = kmalloc(sizeof(mega_sglist) * MAX_SGLIST,
-				GFP_ATOMIC | GFP_DMA);
-    if (megaCfg->scbList[idx].sgList == NULL) {
-        printk(KERN_WARNING "Can't allocate sglist for id %d\n",idx);
-        freeSgList(megaCfg);
-        return -1;
+  /* Unlink from pending queue */
+  for(ppScb=&megaCfg->qPending; *ppScb; ppScb=&(*ppScb)->next) {
+    if (*ppScb == pScb) {
+	*ppScb = pScb->next;
+	break;
     }
-    megaCfg->scbList[idx].SCpnt = NULL;
   }
-  return 0;
+
+  /* Link back into list */
+  pScb->state = SCB_FREE;
+  pScb->SCpnt = NULL;
+
+  pScb->next     = megaCfg->qFree;
+  megaCfg->qFree = pScb;
 }
 
 /*===========================
@@ -358,138 +399,134 @@
  */
 static mega_scb * allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
 {
-  int idx;
-  long flags;
-
-  spin_lock_irqsave (&mega_lock, flags);
-  for (idx = 0; idx < megaCfg->max_cmds; idx++) {
-    if (megaCfg->scbList[idx].idx < 0) {
+  mega_scb *pScb;
 
-      /* Set Index and SCB pointer */
-      megaCfg->scbList[idx].idx = idx;
-      spin_unlock_irqrestore (&mega_lock, flags);
-      megaCfg->scbList[idx].flag = 0;
-      megaCfg->scbList[idx].SCpnt = SCpnt;
-      megaCfg->scbList[idx].next = NULL;
+  /* Unlink command from Free List */
+  if ((pScb = megaCfg->qFree) != NULL) {
+    megaCfg->qFree = pScb->next;
+    
+    pScb->isrcount = jiffies;
+    pScb->next  = NULL;
+    pScb->state = SCB_ACTIVE;
+    pScb->SCpnt = SCpnt;
 
-      return &megaCfg->scbList[idx];
-    }
+    return pScb;
   }
-  spin_unlock_irqrestore (&mega_lock, flags);
 
   printk (KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n");
 
   return NULL;
 }
 
-/*=======================
- * Free a SCB structure
- *=======================
+/*================================================
+ * Initialize SCB structures
+ *================================================
  */
-static void freeSCB (mega_scb * scb)
+static int initSCB (mega_host_config * megaCfg)
 {
-  scb->flag = 0;
-  scb->next = NULL;
-  scb->SCpnt = NULL;
-    scb->idx = -1;
+  int idx;
+
+  megaCfg->qFree = NULL;
+  for (idx = megaCfg->max_cmds-1; idx >= 0; idx--) {
+    megaCfg->scbList[idx].idx    = idx;
+    megaCfg->scbList[idx].sgList = kmalloc(sizeof(mega_sglist) * MAX_SGLIST,
+					   GFP_ATOMIC | GFP_DMA);
+    if (megaCfg->scbList[idx].sgList == NULL) {
+      printk(KERN_WARNING "Can't allocate sglist for id %d\n",idx);
+      freeSgList(megaCfg);
+      return -1;
+    }
+    
+    if (idx < MAX_COMMANDS) {
+      /* Link to free list */
+      freeSCB(megaCfg, &megaCfg->scbList[idx]);
+    }
+  }
+  return 0;
 }
 
 /* Run through the list of completed requests */
 static void mega_rundoneq ()
 {
-  mega_host_config *megaCfg;
   Scsi_Cmnd *SCpnt;
-  char islogical;
 
   while (1) {
     DEQUEUE (SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
     if (SCpnt == NULL)
       return;
 
-    megaCfg = (mega_host_config *) SCpnt->host->hostdata;
-
-    islogical = (SCpnt->channel == megaCfg->host->max_channel &&
-                 SCpnt->target == 0);
-    if (SCpnt->cmnd[0] == INQUIRY &&
-	((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) &&
-	!islogical) {
-      SCpnt->result = 0xF0;
-    }
-
-    /* Convert result to error */
-    switch (SCpnt->result) {
-    case 0x00:
-    case 0x02:
-      SCpnt->result |= (DID_OK << 16);
-      break;
-    case 0x8:
-      SCpnt->result |= (DID_BUS_BUSY << 16);
-      break;
-    default:
-      SCpnt->result |= (DID_BAD_TARGET << 16);
-      break;
-    }
-
     /* Callback */
     callDone (SCpnt);
   }
 }
 
-/* Add command to the list of completed requests */
-static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, int status)
-{
-  pScb->SCpnt->result = status;
-  ENQUEUE (pScb->SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
-  freeSCB (pScb);
-}
-
-/*----------------------------------------------------
- * Process pending queue list
- *
- * Run as a scheduled task 
- *----------------------------------------------------*/
-static void mega_runque (void *dummy)
+/*
+  Runs through the list of pending requests
+  Assumes that mega_lock spin_lock has been acquired.
+*/
+static void mega_runpendq(mega_host_config *megaCfg)
 {
-  mega_host_config *megaCfg;
   mega_scb *pScb;
-  long flags;
 
-  /* Take care of any completed requests */
-  mega_rundoneq ();
+  /* Issue any pending commands to the card */
+  for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) {
+    if (pScb->state == SCB_ACTIVE) {
+      megaIssueCmd(megaCfg, pScb->mboxData, pScb, 1);
+    }
+  }
+}
 
-  DEQUEUE (pScb, mega_scb, qPending, next);
+/* Add command to the list of completed requests */
+static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, 
+			   int status)
+{
+  int islogical;
+  Scsi_Cmnd *SCpnt;
 
-  if (pScb) {
-    if (pScb->SCpnt) {
-        TRACE(("NULL SCpnt for idx %d!\n",pScb->idx));
-    }
-    megaCfg = (mega_host_config *) pScb->SCpnt->host->hostdata;
-
-    if (megaCfg->mbox->busy || megaCfg->flag & (IN_ISR | PENDING)) {
-      TRACE (("%.08lx %.02x <%d.%d.%d> busy%d isr%d pending%d\n",
-	      pScb->SCpnt->serial_number,
-	      pScb->SCpnt->cmnd[0],
-	      pScb->SCpnt->channel,
-	      pScb->SCpnt->target,
-	      pScb->SCpnt->lun,
-	      megaCfg->mbox->busy,
-	      (megaCfg->flag & IN_ISR) ? 1 : 0,
-	      (megaCfg->flag & PENDING) ? 1 : 0));
-    }
-
-    if (MegaIssueCmd (megaCfg, pScb->mboxData, pScb, 1)) {
-      /* We're BUSY... come back later */
-      spin_lock_irqsave (&mega_lock, flags);
-      pScb->next = qPending;
-      qPending = pScb;
-      spin_unlock_irqrestore (&mega_lock, flags);
-
-      if (!(megaCfg->flag & PENDING)) {
-	/* If PENDING, irq will schedule task */
-	queue_task (&runq, &tq_scheduler);
-      }
-    }
+  if (pScb == NULL) {
+	TRACE(("NULL pScb in mega_cmd_done!"));
+	printk("NULL pScb in mega_cmd_done!");
+  }
+
+  SCpnt = pScb->SCpnt;
+  freeSCB(megaCfg, pScb);
+
+  if (SCpnt == NULL) {
+	TRACE(("NULL SCpnt in mega_cmd_done!"));
+	TRACE(("pScb->idx = ",pScb->idx));
+	TRACE(("pScb->state = ",pScb->state));
+	TRACE(("pScb->state = ",pScb->state));
+	printk("Problem...!\n");
+	while(1);
+  }
+
+  islogical = (SCpnt->channel == megaCfg->host->max_channel &&
+	       SCpnt->target == 0);
+  if (SCpnt->cmnd[0] == INQUIRY &&
+      ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) &&
+      !islogical) {
+    status = 0xF0;
+  }
+ 
+  SCpnt->result = 0;  /* clear result; otherwise, success returns corrupt
+                         value */
+
+  /* Convert MegaRAID status to Linux error code */
+  switch (status) {
+  case 0x00: /* SUCCESS */
+  case 0x02: /* ERROR_ABORTED */
+    SCpnt->result |= (DID_OK << 16);
+    break;
+  case 0x8:  /* ERR_DEST_DRIVE_FAILED */
+    SCpnt->result |= (DID_BUS_BUSY << 16);
+    break;
+  default:
+    SCpnt->result |= (DID_BAD_TARGET << 16);
+    break;
   }
+
+  /* Add Scsi_Command to end of completed queue */
+  ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
 }
 
 /*-------------------------------------------------------------------
@@ -500,7 +537,8 @@
  * If NULL is returned, the scsi_done function MUST have been called
  *
  *-------------------------------------------------------------------*/
-static mega_scb * mega_build_cmd (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+static mega_scb * mega_build_cmd (mega_host_config * megaCfg, 
+				  Scsi_Cmnd * SCpnt)
 {
   mega_scb *pScb;
   mega_mailbox *mbox;
@@ -508,6 +546,11 @@
   long seg;
   char islogical;
 
+  if (SCpnt == NULL) {
+	printk("NULL SCpnt in mega_build_cmd!\n");
+	while(1);
+  }
+
   if (SCpnt->cmnd[0] & 0x80)	/* ioctl from megamgr */
     return mega_ioctl (megaCfg, SCpnt);
 
@@ -519,6 +562,12 @@
     return NULL;
   }
 
+  if (!islogical && SCpnt->target == skip_id) {
+	SCpnt->result = (DID_BAD_TARGET << 16);
+	callDone (SCpnt);
+	return NULL;
+  }
+
   /*-----------------------------------------------------
    *
    *               Logical drive commands
@@ -738,6 +787,21 @@
   return (pScb);
 }
 
+#if DEBUG
+static void showMbox(mega_scb *pScb)
+{
+  mega_mailbox *mbox;
+
+  if (pScb == NULL) return;
+
+  mbox = (mega_mailbox *)pScb->mboxData;
+  printk("%u cmd:%x id:%x #scts:%x lba:%x addr:%x logdrv:%x #sg:%x\n",
+	 pScb->SCpnt->pid, 
+	 mbox->cmd, mbox->cmdid, mbox->numsectors,
+	 mbox->lba, mbox->xferaddr, mbox->logdrv,
+	 mbox->numsgelements);
+}
+#endif
 
 /*--------------------------------------------------------------------
  * Interrupt service routine
@@ -745,7 +809,7 @@
 static void megaraid_isr (int irq, void *devp, struct pt_regs *regs)
 {
   mega_host_config    *megaCfg;
-  u_char byte, idx, sIdx;
+  u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE];
   u_long dword;
   mega_mailbox *mbox;
   mega_scb *pScb;
@@ -753,14 +817,14 @@
   int qCnt, qStatus;
 
   megaCfg = (mega_host_config *) devp;
-  mbox = (mega_mailbox *) megaCfg->mbox;
-
-  if (megaCfg->host->irq == irq) {
+  mbox = (mega_mailbox *)tmpBox;
 
 #if LINUX_VERSION_CODE >= 0x20100
-    spin_lock_irqsave (&io_request_lock, flags);
+  spin_lock_irqsave (&io_request_lock, flags);
 #endif
 
+  while (megaCfg->host->irq == irq) {
+
     spin_lock_irqsave (&mega_lock, flags);
 
     if (megaCfg->flag & IN_ISR) {
@@ -769,6 +833,11 @@
 
     megaCfg->flag |= IN_ISR;
 
+    if (mega_busyWaitMbox(megaCfg)) {
+	printk(KERN_WARNING "Error: mailbox busy in isr!\n");
+    }
+
+
     /* Check if a valid interrupt is pending */
     if (megaCfg->flag & BOARD_QUARTZ) {
       dword = RDOUTDOOR (megaCfg);
@@ -776,12 +845,16 @@
 	/* Spurious interrupt */
 	megaCfg->flag &= ~IN_ISR;
 	spin_unlock_irqrestore (&mega_lock, flags);
-#if LINUX_VERSION_CODE >= 0x20100
-        spin_unlock_irqrestore (&io_request_lock, flags);
-#endif
-	return;
+	break;
       }
       WROUTDOOR (megaCfg, dword);
+
+      /* Copy to temp location */
+      memcpy(tmpBox, (mega_mailbox *)megaCfg->mbox, MAILBOX_SIZE);
+
+      /* Acknowledge interrupt */
+      WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
+      while (RDINDOOR (megaCfg) & 0x02);
     }
     else {
       byte = READ_PORT (megaCfg->host->io_port, INTR_PORT);
@@ -789,71 +862,74 @@
 	/* Spurious interrupt */
 	megaCfg->flag &= ~IN_ISR;
 	spin_unlock_irqrestore (&mega_lock, flags);
-#if LINUX_VERSION_CODE >= 0x20100
-        spin_unlock_irqrestore (&io_request_lock, flags);
-#endif
-	return;
+	break;
       }
       WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
+
+      /* Copy to temp location */
+      memcpy(tmpBox, (mega_mailbox *)megaCfg->mbox, MAILBOX_SIZE);
+
+      /* Acknowledge interrupt */
+      CLEAR_INTR (megaCfg->host->io_port);
     }
 
     qCnt = mbox->numstatus;
     qStatus = mbox->status;
 
-    if (qCnt > 1) {
-      TRACE (("ISR: Received %d status\n", qCnt))
-	printk (KERN_DEBUG "Got numstatus = %d\n", qCnt);
-    }
-
     for (idx = 0; idx < qCnt; idx++) {
       sIdx = mbox->completed[idx];
       if (sIdx > 0) {
 	pScb = &megaCfg->scbList[sIdx - 1];
-        /* FVF: let's try to avoid un/locking for no good reason */
-        pScb->SCpnt->result = qStatus;
-        ENQUEUE_NL (pScb->SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
-        freeSCB (pScb);
+
+	/* ASSERT(pScb->state == SCB_ISSUED); */
+
+#if DEBUG
+	if (((jiffies) - pScb->isrcount) > maxCmdTime) {
+	  maxCmdTime = (jiffies) - pScb->isrcount;
+	  printk("cmd time = %u\n", maxCmdTime);
+	}
+#endif
+
+	if (pScb->state == SCB_ABORTED) {
+	  printk("Received aborted SCB! %u\n", (int)((jiffies)-pScb->isrcount));
+	}
+
+	/* Mark command as completed */
+	mega_cmd_done(megaCfg, pScb, qStatus);
       }
+
     }
-    if (megaCfg->flag & BOARD_QUARTZ) {
-      WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
-      while (RDINDOOR (megaCfg) & 0x02);
-    }
-    else {
-      CLEAR_INTR (megaCfg->host->io_port);
-    }
+    spin_unlock_irqrestore (&mega_lock, flags);
 
     megaCfg->flag &= ~IN_ISR;
-    megaCfg->flag &= ~PENDING;
 
-    spin_unlock_irqrestore (&mega_lock, flags);
-    mega_runque (NULL);
+    mega_rundoneq();
 
-#if LINUX_VERSION_CODE >= 0x20100
-    spin_unlock_irqrestore (&io_request_lock, flags);
-#endif
+    /* Loop through any pending requests */
+    spin_lock_irqsave(&mega_lock, flags);
+    mega_runpendq(megaCfg);
+    spin_unlock_irqrestore(&mega_lock,flags);
+  }
 
-#if 0
-    /* Queue as a delayed ISR routine */
-    queue_task_irq_off (&runq, &tq_immediate);
-    mark_bh (IMMEDIATE_BH);
+#if LINUX_VERSION_CODE >= 0x20100
+  spin_unlock_irqrestore (&io_request_lock, flags);
 #endif
-
-  }
 }
 
 /*==================================================*/
 /* Wait until the controller's mailbox is available */
 /*==================================================*/
-static int busyWaitMbox (mega_host_config * megaCfg)
+static int mega_busyWaitMbox (mega_host_config * megaCfg)
 {
   mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
   long counter;
 
   for (counter = 0; counter < 10000; counter++) {
-    udelay (100);
-    if (!mbox->busy)
+    if (!mbox->busy) {
       return 0;
+    }
+    udelay (100);
+    barrier();
   }
   return -1;			/* give up after 1 second */
 }
@@ -868,47 +944,55 @@
  *   int intr         - if 1, interrupt, 0 is blocking
  *=====================================================
  */
-static int MegaIssueCmd (mega_host_config * megaCfg,
+static int megaIssueCmd (mega_host_config * megaCfg,
 	      u_char * mboxData,
 	      mega_scb * pScb,
 	      int intr)
 {
   mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
-  long flags;
   u_char byte;
   u_long cmdDone;
-
-  mboxData[0x1] = (pScb ? pScb->idx + 1 : 0x00);	/* Set cmdid */
+  Scsi_Cmnd *SCpnt;
+  
+  mboxData[0x1] = (pScb ? pScb->idx + 1: 0x0);   /* Set cmdid */
   mboxData[0xF] = 1;		/* Set busy */
 
-  spin_lock_irqsave(&mega_lock,flags);
-
-#ifndef CONFIG_MEGARAID_MULTI_IO
-  if (megaCfg->flag & PENDING) {
-     spin_unlock_irqrestore(&mega_lock,flags);
-     return -1;
+#if 0
+  if (intr && mbox->busy) {
+    return 0;
   }
 #endif
 
   /* Wait until mailbox is free */
-  if (busyWaitMbox (megaCfg)) {
-    if (pScb) {
-      TRACE (("Mailbox busy %.08lx <%d.%d.%d>\n", pScb->SCpnt->serial_number,
-	      pScb->SCpnt->channel, pScb->SCpnt->target, pScb->SCpnt->lun));
-    } else {
-	TRACE(("pScb NULL in MegaIssueCmd!\n"));
+  while (mega_busyWaitMbox (megaCfg)) {
+    printk("Blocked mailbox!!\n");
+    udelay(1000);
+
+#if DEBUG
+    showMbox(pLastScb);
+#endif
+    
+    /* Abort command */
+    if (pScb == NULL) {
+	printk("NULL pScb in megaIssue\n");
+	TRACE(("NULL pScb in megaIssue\n"));
     }
-    spin_unlock_irqrestore(&mega_lock,flags);
-    return -1;
+    SCpnt = pScb->SCpnt;
+    freeSCB(megaCfg, pScb);
+
+    SCpnt->result = (DID_ABORT << 16);
+    callDone(SCpnt);
+    return 0;
   }
+  pLastScb = pScb;
 
+  
   /* Copy mailbox data into host structure */
-  memset (mbox, 0, 16);
   memcpy (mbox, mboxData, 16);
 
   /* Kick IO */
-  megaCfg->flag |= PENDING;
   if (intr) {
+
     /* Issue interrupt (non-blocking) command */
     if (megaCfg->flag & BOARD_QUARTZ) {
       mbox->mraid_poll = 0;
@@ -919,12 +1003,11 @@
       ENABLE_INTR (megaCfg->host->io_port);
       ISSUE_COMMAND (megaCfg->host->io_port);
     }
-    spin_unlock_irqrestore(&mega_lock,flags);
+    pScb->state = SCB_ISSUED;
   }
   else {			/* Issue non-ISR (blocking) command */
-
+    disable_irq(megaCfg->host->irq);
     if (megaCfg->flag & BOARD_QUARTZ) {
-
       mbox->mraid_poll = 0;
       mbox->mraid_ack = 0;
       WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x1);
@@ -932,7 +1015,6 @@
       while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234);
       WROUTDOOR (megaCfg, cmdDone);
 
-      spin_unlock_irqrestore(&mega_lock,flags);
       if (pScb) {
 	mega_cmd_done (megaCfg, pScb, mbox->status);
 	mega_rundoneq ();
@@ -941,8 +1023,6 @@
       WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
       while (RDINDOOR (megaCfg) & 0x2);
 
-      megaCfg->flag &= ~PENDING;
-
     }
     else {
       DISABLE_INTR (megaCfg->host->io_port);
@@ -954,8 +1034,6 @@
 
       ENABLE_INTR (megaCfg->host->io_port);
       CLEAR_INTR (megaCfg->host->io_port);
-      megaCfg->flag &= ~PENDING;
-      spin_unlock_irqrestore(&mega_lock,flags);
 
       if (pScb) {
 	mega_cmd_done (megaCfg, pScb, mbox->status);
@@ -966,6 +1044,11 @@
       }
 
     }
+    enable_irq(megaCfg->host->irq);
+  }
+  while (mega_busyWaitMbox (megaCfg)) {
+    printk("Blocked mailbox on exit!\n");
+    udelay(1000);
   }
 
   return 0;
@@ -1058,6 +1141,7 @@
   u_long paddr;
 
   spin_lock_init (&mega_lock);
+
   /* Initialize adapter inquiry */
   paddr = virt_to_bus (megaCfg->mega_buffer);
   mbox = (mega_mailbox *) mboxData;
@@ -1070,7 +1154,7 @@
   mbox->xferaddr = paddr;
 
   /* Issue a blocking command to the card */
-  MegaIssueCmd (megaCfg, mboxData, NULL, 0);
+  megaIssueCmd (megaCfg, mboxData, NULL, 0);
 
   /* Initialize host/local structures with Adapter info */
   adapterInfo = (mega_RAIDINQ *) megaCfg->mega_buffer;
@@ -1136,7 +1220,7 @@
  * Returns data to be displayed in /proc/scsi/megaraid/X
  *----------------------------------------------------------*/
 int megaraid_proc_info (char *buffer, char **start, off_t offset,
-		    int length, int inode, int inout)
+		    int length, int host_no, int inout)
 {
   *start = buffer;
   return 0;
@@ -1150,35 +1234,33 @@
   struct Scsi_Host *host;
   u_char pciBus, pciDevFun, megaIrq;
   u_long megaBase;
-  u_short pciIdx = 0;
+  u_short jdx,pciIdx = 0;
   u_short numFound = 0;
 
 #if LINUX_VERSION_CODE < 0x20100
   while (!pcibios_find_device (pciVendor, pciDev, pciIdx, &pciBus, &pciDevFun)) {
-#if 0
-    if (flag & BOARD_QUARTZ) {
-      u_int magic;
-      pcibios_read_config_dword (pciBus, pciDevFun,
-				 PCI_CONF_AMISIG,
-				 &magic);
-      if (magic != AMI_SIGNATURE) {
-        pciIdx++;
-	continue;		/* not an AMI board */
-      }
-    }
-#endif
 
 #if 0
-    } /* keep auto-indenters happy */
+  } /* keep auto-indenters happy */
 #endif
-
 #else
+  
   struct pci_dev *pdev = pci_devices;
-
+  
   while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) {
     pciBus = pdev->bus->number;
     pciDevFun = pdev->devfn;
 #endif
+    if (flag & BOARD_QUARTZ) {
+      u_short magic;
+      pcibios_read_config_word (pciBus, pciDevFun,
+				PCI_CONF_AMISIG,
+				&magic);
+      if (magic != AMI_SIGNATURE) {
+        pciIdx++;
+	continue;		/* not an AMI board */
+      }
+    }
     printk (KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:fun %d\n",
 	    pciVendor,
 	    pciDev,
@@ -1196,7 +1278,7 @@
 			      &megaIrq);
 #else
     megaBase = pdev->base_address[0];
-    megaIrq = pdev->irq;
+    megaIrq  = pdev->irq;
 #endif
     pciIdx++;
 
@@ -1214,10 +1296,12 @@
     megaCfg = (mega_host_config *) host->hostdata;
     memset (megaCfg, 0, sizeof (mega_host_config));
 
-    printk (KERN_INFO " scsi%d: Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR,
+    printk (" scsi%d: Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR,
 	    host->host_no, (u_int) megaBase, megaIrq);
 
     /* Copy resource info into structure */
+    megaCfg->qPending = NULL;
+    megaCfg->qFree    = NULL;
     megaCfg->flag = flag;
     megaCfg->host = host;
     megaCfg->base = megaBase;
@@ -1248,11 +1332,16 @@
 
     mega_register_mailbox (megaCfg, virt_to_bus ((void *) &megaCfg->mailbox));
     mega_i_query_adapter (megaCfg);
+    
+    for(jdx=0; jdx<MAX_LOGICAL_DRIVES; jdx++) {
+      megaCfg->nReads[jdx] = 0;
+      megaCfg->nWrites[jdx] = 0;
+    }
 
     /* Initialize SCBs */
     if (initSCB (megaCfg)) {
-	scsi_unregister (host);
-	continue;
+      scsi_unregister (host);
+      continue;
     }
 
     numFound++;
@@ -1275,6 +1364,16 @@
     return 0;
   }
 #endif
+  skip_id = -1;
+  if (megaraid && !strncmp(megaraid,"skip",strlen("skip"))) {
+      if (megaraid[4] != '\0') {
+          skip_id = megaraid[4] - '0';
+          if (megaraid[5] != '\0') {
+              skip_id = (skip_id * 10) + (megaraid[5] - '0');
+          }
+      }
+      skip_id = (skip_id > 15) ? -1 : skip_id;
+  }
 
   count += findCard (pHostTmpl, 0x101E, 0x9010, 0);
   count += findCard (pHostTmpl, 0x101E, 0x9060, 0);
@@ -1299,10 +1398,11 @@
   memset (mbox, 0, 16);
   mboxData[0] = 0xA;
 
-  /* Issue a blocking (interrupts disabled) command to the card */
-  MegaIssueCmd (megaCfg, mboxData, NULL, 0);
+  free_irq (megaCfg->host->irq, megaCfg);/* Must be freed first, otherwise
+					   extra interrupt is generated */
 
-  schedule ();
+  /* Issue a blocking (interrupts disabled) command to the card */
+  megaIssueCmd (megaCfg, mboxData, NULL, 0);
 
   /* Free our resources */
   if (megaCfg->flag & BOARD_QUARTZ) {
@@ -1311,9 +1411,7 @@
   else {
     release_region (megaCfg->host->io_port, 16);
   }
-  free_irq (megaCfg->host->irq, megaCfg);	/* Must be freed first, otherwise
 
-						   extra interrupt is generated */
   freeSgList(megaCfg);
   scsi_unregister (pSHost);
 
@@ -1369,6 +1467,9 @@
 {
   mega_host_config *megaCfg;
   mega_scb *pScb;
+  long flags;
+
+  spin_lock_irqsave(&mega_lock,flags);
 
   megaCfg = (mega_host_config *) SCpnt->host->hostdata;
 
@@ -1381,15 +1482,38 @@
 
   SCpnt->scsi_done = pktComp;
 
+  /* If driver in abort or reset.. cancel this command */
+  if (megaCfg->flag & IN_ABORT) {
+    SCpnt->result = (DID_ABORT << 16);
+    ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+
+    spin_unlock_irqrestore(&mega_lock,flags);
+    return 0;
+  }
+  else if (megaCfg->flag & IN_RESET) {
+    SCpnt->result = (DID_RESET << 16);
+    ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+
+    spin_unlock_irqrestore(&mega_lock,flags);
+    return 0;
+  }
+
   /* Allocate and build a SCB request */
   if ((pScb = mega_build_cmd (megaCfg, SCpnt)) != NULL) {
     /* Add SCB to the head of the pending queue */
-    ENQUEUE (pScb, mega_scb, qPending, next);
+    ENQUEUE_NL (pScb, mega_scb, megaCfg->qPending, next);
 
-    /* Issue the command to the card */
-    mega_runque (NULL);
+    /* Issue any pending command to the card if not in ISR */
+    if (!(megaCfg->flag & IN_ISR)) {
+      mega_runpendq(megaCfg);
+    }
+    else {
+      printk("IRQ pend...\n");
+    }
   }
 
+  spin_unlock_irqrestore(&mega_lock,flags);
+
   return 0;
 }
 
@@ -1398,31 +1522,16 @@
  *----------------------------------------------------------------------*/
 volatile static int internal_done_flag = 0;
 volatile static int internal_done_errcode = 0;
+static struct wait_queue *internal_wait = NULL;
 
 static void internal_done (Scsi_Cmnd * SCpnt)
 {
   internal_done_errcode = SCpnt->result;
   internal_done_flag++;
+  wake_up(&internal_wait);
 }
 
-/*
- *      This seems dangerous in an SMP environment because
- *      while spinning on internal_done_flag in 2.0.x SMP
- *      no IRQ's will be taken, including those that might
- *      be needed to clear this.
- *
- *      I think this should be using a wait queue ?
- *                              -- AC
- */      
-
-/*
- *      I'll probably fix this in the next version, but
- *      megaraid_command() will never get called since can_queue is set,
- *      except maybe in a *really* old kernel in which case it's very
- *      unlikely they'd be using SMP anyway.  Really this function is
- *      just here for completeness.
- *                              - JLJ
- */
+/* shouldn't be used, but included for completeness */
 
 int megaraid_command (Scsi_Cmnd * SCpnt)
 {
@@ -1431,8 +1540,9 @@
   /* Queue command, and wait until it has completed */
   megaraid_queue (SCpnt, internal_done);
 
-  while (!internal_done_flag)
-    barrier ();
+  while (!internal_done_flag) {
+	interruptible_sleep_on(&internal_wait);
+  }
 
   return internal_done_errcode;
 }
@@ -1443,31 +1553,77 @@
 int megaraid_abort (Scsi_Cmnd * SCpnt)
 {
   mega_host_config *megaCfg;
-  int idx;
-  long flags;
+  int   rc, idx;
+  long  flags;
+  mega_scb *pScb;
+
+  rc = SCSI_ABORT_SUCCESS;
 
   spin_lock_irqsave (&mega_lock, flags);
 
   megaCfg = (mega_host_config *) SCpnt->host->hostdata;
 
+  megaCfg->flag |= IN_ABORT;
+
+  for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) {
+    if (pScb->SCpnt == SCpnt) {
+      /* Found an aborting command */
+#if DEBUG
+      showMbox(pScb);
+#endif
+
+      printk("Abort: %d %u\n", 
+	     SCpnt->timeout_per_command,
+	     (uint)((jiffies) - pScb->isrcount));
+
+      switch(pScb->state) {
+      case SCB_ABORTED: /* Already aborted */
+	rc = SCSI_ABORT_SNOOZE;
+	break;
+      case SCB_ISSUED: /* Waiting on ISR result */
+	rc = SCSI_ABORT_PENDING;
+	pScb->state = SCB_ABORTED;
+	break;
+      }
+    }
+  }
+
+#if 0
   TRACE (("ABORT!!! %.08lx %.02x <%d.%d.%d>\n",
-	SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
+	  SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
 	  SCpnt->lun));
+  for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) {
+    if (pScb->SCpnt == SCpnt) { 
+      ser_printk("** %d<%x>  %c\n", pScb->SCpnt->pid, pScb->idx+1,
+		 pScb->state == SCB_ACTIVE ? 'A' : 'I');
+#if DEBUG
+      showMbox(pScb);
+#endif
+    }
+  }
+#endif
+
   /*
    * Walk list of SCBs for any that are still outstanding
    */
   for (idx = 0; idx < megaCfg->max_cmds; idx++) {
-    if (megaCfg->scbList[idx].idx >= 0) {
+    if (megaCfg->scbList[idx].state != SCB_FREE) {
       if (megaCfg->scbList[idx].SCpnt == SCpnt) {
-	freeSCB (&megaCfg->scbList[idx]);
+	freeSCB (megaCfg, &megaCfg->scbList[idx]);
 
-	SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24);
-	callDone (SCpnt);
+	SCpnt->result = (DID_ABORT << 16) | (SUGGEST_RETRY << 24);
+	ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
       }
     }
   }
+  
+  megaCfg->flag &= ~IN_ABORT;
+
   spin_unlock_irqrestore (&mega_lock, flags);
-  return SCSI_ABORT_SNOOZE;
+
+  mega_rundoneq();
+
+  return rc;
 }
 
 /*---------------------------------------------------------------------
@@ -1483,6 +1639,8 @@
 
   megaCfg = (mega_host_config *) SCpnt->host->hostdata;
 
+  megaCfg->flag |= IN_RESET;
+
   TRACE (("RESET: %.08lx %.02x <%d.%d.%d>\n",
 	SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target,
 	  SCpnt->lun));
@@ -1491,14 +1649,21 @@
    * Walk list of SCBs for any that are still outstanding
    */
   for (idx = 0; idx < megaCfg->max_cmds; idx++) {
-    if (megaCfg->scbList[idx].idx >= 0) {
+    if (megaCfg->scbList[idx].state != SCB_FREE) {
       SCpnt = megaCfg->scbList[idx].SCpnt;
-      freeSCB (&megaCfg->scbList[idx]);
-      SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24);
-      callDone (SCpnt);
+      if (SCpnt != NULL) {
+	freeSCB (megaCfg, &megaCfg->scbList[idx]);
+	SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24);
+	ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble);
+      }
     }
   }
+
+  megaCfg->flag &= ~IN_RESET;
+
   spin_unlock_irqrestore (&mega_lock, flags);
+
+  mega_rundoneq();
   return SCSI_RESET_PUNT;
 }
 
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/megaraid.h linux/drivers/scsi/megaraid.h
--- v2.2.7/linux/drivers/scsi/megaraid.h	Fri Apr 16 14:47:31 1999
+++ linux/drivers/scsi/megaraid.h	Mon May 10 11:16:13 1999
@@ -6,24 +6,23 @@
 #endif
 
 #define IN_ISR                  0x80000000L
-#define NO_INTR                 0x40000000L
-#define IN_TIMEOUT              0x20000000L
-#define PENDING                 0x10000000L
+#define IN_ABORT                0x40000000L
+#define IN_RESET                0x20000000L
 #define BOARD_QUARTZ            0x08000000L
 
-#define SCB_ACTIVE 0x1
-#define SCB_WAITQ  0x2
-#define SCB_ISSUED 0x4
-
-#define SCB_FREE                -1
-#define SCB_RESET               -2
-#define SCB_ABORT               -3
-#define SCB_LOCKED              -4
+#define SCB_FREE     0x0
+#define SCB_ACTIVE   0x1
+#define SCB_WAITQ    0x2
+#define SCB_ISSUED   0x3
+#define SCB_COMPLETE 0x4
+#define SCB_ABORTED  0x5
+#define SCB_RESET    0x6
 
 #define MEGA_CMD_TIMEOUT        10
 
 #define MAX_SGLIST              17
-#define MAX_COMMANDS            254
+#define MAX_COMMANDS            250
+#define MAX_CMD_PER_LUN         63
 
 #define MAX_LOGICAL_DRIVES      8
 #define MAX_CHANNEL             5
@@ -99,7 +98,7 @@
 #define PCI_CONF_BASE_ADDR_OFFSET  0x10
 #define PCI_CONF_IRQ_OFFSET        0x3c
 #define PCI_CONF_AMISIG            0xa0
-#define AMI_SIGNATURE              0x11223344
+#define AMI_SIGNATURE              0x3344
 
 #if LINUX_VERSION_CODE < 0x20100
 #define MEGARAID \
@@ -117,11 +116,11 @@
     megaraid_reset,                     /* Reset Command Function    */\
     NULL,                               /* Slave Attach Function     */\
     megaraid_biosparam,                 /* Disk BIOS Parameters      */\
-    254,                                /* # of cmds that can be\
+    MAX_COMMANDS,                       /* # of cmds that can be\
                                            outstanding at any time */\
     7,                                  /* HBA Target ID             */\
     MAX_SGLIST,                         /* Scatter/Gather Table Size */\
-    64,                                 /* SCSI Commands per LUN     */\
+    MAX_CMD_PER_LUN,                    /* SCSI Commands per LUN     */\
     0,                                  /* Present                   */\
     0,                                  /* Default Unchecked ISA DMA */\
     ENABLE_CLUSTERING }		/* Enable Clustering         */
@@ -138,10 +137,10 @@
     abort:            megaraid_abort,          /* Abort Command Function    */\
     reset:            megaraid_reset,          /* Reset Command Function    */\
     bios_param:       megaraid_biosparam,      /* Disk BIOS Parameters      */\
-    can_queue:        1 /* MAX_COMMANDS */,            /* Can Queue                 */\
+    can_queue:        MAX_COMMANDS,            /* Can Queue                 */\
     this_id:          7,                       /* HBA Target ID             */\
     sg_tablesize:     MAX_SGLIST,              /* Scatter/Gather Table Size */\
-    cmd_per_lun:      64,                      /* SCSI Commands per LUN     */\
+    cmd_per_lun:      MAX_CMD_PER_LUN,         /* SCSI Commands per LUN     */\
     present:          0,                       /* Present                   */\
     unchecked_isa_dma:0,                       /* Default Unchecked ISA DMA */\
     use_clustering:   ENABLE_CLUSTERING       /* Enable Clustering         */\
@@ -250,13 +249,14 @@
 typedef struct _mega_scb mega_scb;
 
 struct _mega_scb {
-    int idx;
-    u_long flag;
-    Scsi_Cmnd *SCpnt;
-    u_char mboxData[16];
-    mega_passthru pthru;
-    mega_sglist *sgList;
-    mega_scb *next;
+    int            idx;
+    u_long         state;
+    u_long         isrcount;
+    u_char         mboxData[16];
+    mega_passthru  pthru;
+    Scsi_Cmnd     *SCpnt;
+    mega_sglist   *sgList;
+    mega_scb      *next;
 };
 
 /* Per-controller data */
@@ -264,8 +264,12 @@
     u_char numldrv;
     u_long flag;
     u_long base;
+ 
+    mega_scb *qFree;
+    mega_scb *qPending;
 
-    struct tq_struct megaTq;
+  u_long nReads[MAX_LOGICAL_DRIVES];
+  u_long nWrites[MAX_LOGICAL_DRIVES];
 
     /* Host adapter parameters */
     u_char fwVer[7];
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c
--- v2.2.7/linux/drivers/scsi/ppa.c	Mon Mar 29 11:09:11 1999
+++ linux/drivers/scsi/ppa.c	Fri May  7 10:57:42 1999
@@ -741,6 +741,7 @@
 {
     ppa_struct *tmp = (ppa_struct *) data;
     Scsi_Cmnd *cmd = tmp->cur_cmd;
+    unsigned long flags;
 
     if (!cmd) {
 	printk("PPA: bug in ppa_interrupt\n");
@@ -792,7 +793,10 @@
 	ppa_pb_release(cmd->host->unique_id);
 
     tmp->cur_cmd = 0;
+    
+    spin_lock_irqsave(&io_request_lock, flags);
     cmd->scsi_done(cmd);
+    spin_unlock_irqrestore(&io_request_lock, flags);
     return;
 }
 
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- v2.2.7/linux/drivers/scsi/scsi.c	Tue Mar 23 14:35:48 1999
+++ linux/drivers/scsi/scsi.c	Thu Apr 29 11:53:41 1999
@@ -1926,10 +1926,12 @@
     SDpnt->device_queue = NULL;
 
     for(j=0;j<SDpnt->queue_depth;j++){
-      SCpnt = (Scsi_Cmnd *)
+        SCpnt = (Scsi_Cmnd *)
               scsi_init_malloc(sizeof(Scsi_Cmnd),
                                GFP_ATOMIC |
                                (host->unchecked_isa_dma ? GFP_DMA : 0));
+	if (NULL == SCpnt)
+	    break; /* If not, the next line will oops ... */
         memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout));
 	SCpnt->host                      = host;
 	SCpnt->device                    = SDpnt;
@@ -1951,6 +1953,12 @@
 	SDpnt->device_queue              = SCpnt;
         SCpnt->state                     = SCSI_STATE_UNUSED;
         SCpnt->owner                     = SCSI_OWNER_NOBODY;
+    }
+    if (j < SDpnt->queue_depth) { /* low on space (D.Gilbert 990424) */
+	printk("scsi_build_commandblocks: want=%d, space for=%d blocks\n",
+	       SDpnt->queue_depth, j);
+	SDpnt->queue_depth = j;
+	/* Still problem if 0==j , continue anyway ... */
     }
     SDpnt->has_cmdblocks = 1;
 }
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c
--- v2.2.7/linux/drivers/scsi/scsi_ioctl.c	Wed Sep  9 14:51:09 1998
+++ linux/drivers/scsi/scsi_ioctl.c	Thu Apr 29 11:53:41 1999
@@ -131,15 +131,16 @@
 	    else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
 	    break;
 	case NOT_READY: /* This happens if there is no disc in drive */
-	    if(dev->removable){
+	    if(dev->removable && (cmd[0] != TEST_UNIT_READY)){
 		printk(KERN_INFO "Device not ready.  Make sure there is a disc in the drive.\n");
 		break;
-	    };
+	    }
 	case UNIT_ATTENTION:
 	    if (dev->removable){
 		dev->changed = 1;
 		SCpnt->result = 0; /* This is no longer considered an error */
-		printk(KERN_INFO "Disc change detected.\n");
+		/* gag this error, VFS will log it anyway /axboe */
+		/* printk(KERN_INFO "Disc change detected.\n"); */
 		break;
 	    };
 	default: /* Fall through for non-removable media */
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- v2.2.7/linux/drivers/scsi/sd.c	Tue Feb 23 15:21:34 1999
+++ linux/drivers/scsi/sd.c	Thu Apr 29 11:53:41 1999
@@ -719,6 +719,12 @@
  	    SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
  	    goto repeat;
  	}
+    if (rscsi_disks[dev].sector_size == 4096) 
+	if((block & 7) || (SCpnt->request.nr_sectors & 7)) {
+	    printk("sd.cBad block number/count requested");
+	    SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+	    goto repeat;
+	}
      
     switch (SCpnt->request.cmd)
     {
@@ -984,6 +990,13 @@
 
     cmd[1] = (SCpnt->lun << 5) & 0xe0;
 
+     if (rscsi_disks[dev].sector_size == 4096){
+	if(block & 7) panic("sd.c:Bad block number requested");
+	if(this_count & 7) panic("sd.c:Bad block number requested");
+	block = block >> 3;
+	this_count = block >> 3;
+     }
+
      if (rscsi_disks[dev].sector_size == 2048){
  	if(block & 3) panic("sd.c:Bad block number requested");
  	if(this_count & 3) panic("sd.c:Bad block number requested");
@@ -1335,6 +1348,7 @@
 	if (rscsi_disks[i].sector_size != 512 &&
 	    rscsi_disks[i].sector_size != 1024 &&
 	    rscsi_disks[i].sector_size != 2048 &&
+	    rscsi_disks[i].sector_size != 4096 &&
 	    rscsi_disks[i].sector_size != 256)
 	{
 	    printk ("%s : unsupported sector size %d.\n",
@@ -1394,6 +1408,8 @@
 		nbuff, hard_sector, rscsi_disks[i].capacity,
                 mb, sz_quot, sz_rem);
     }
+	if(rscsi_disks[i].sector_size == 4096)
+	    rscsi_disks[i].capacity <<= 3;
 	if(rscsi_disks[i].sector_size == 2048)
 	    rscsi_disks[i].capacity <<= 2;  /* Change into 512 byte sectors */
 	if(rscsi_disks[i].sector_size == 1024)
diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c
--- v2.2.7/linux/drivers/scsi/sg.c	Fri Apr 16 14:47:31 1999
+++ linux/drivers/scsi/sg.c	Fri May  7 11:05:30 1999
@@ -16,7 +16,7 @@
  *
  *  Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book.
  */
- static char * sg_version_str = "Version: 2.1.31 (990327)";
+ static char * sg_version_str = "Version: 2.1.32 (990501)";
 /*
  *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au)
  *      - scatter list logic replaces previous large atomic SG_BIG_BUFF
@@ -69,8 +69,9 @@
 
 int sg_big_buff = SG_SCATTER_SZ;  /* sg_big_buff is ro through sysctl */
 /* N.B. This global is here to keep existing software happy. It now holds
-   the size of the "first buffer" of the most recent sucessful sg_open(). */
-/* Only available when 'sg' compiled into kernel (rather than a module). */
+   the size of the "first buffer" of the most recent sucessful sg_open(). 
+   Only available when 'sg' compiled into kernel (rather than a module). 
+   This should probably be deprecated (use SG_GET_RESERVED_SIZE instead). */
 
 #define SG_SECTOR_SZ 512
 #define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
@@ -146,6 +147,7 @@
     char closed;        /* 1 -> fd closed but request(s) outstanding */
     char my_mem_src;    /* heap whereabouts of this sg_fb object */
     char cmd_q;         /* 1 -> allow command queuing, 0 -> don't */
+    char underrun_flag; /* 1 -> flag underruns, 0 -> don't, 2 -> test */
 } Sg_fd; /* around 1192 bytes long on i386 */
 
 typedef struct sg_device /* holds the state of each scsi generic device */
@@ -173,7 +175,7 @@
 static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, 
                             int * retSzp);
 static void sg_low_free(char * buff, int size, int mem_src);
-static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev);
+static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev, int get_reserved);
 static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
 static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id);
 static Sg_request * sg_add_request(Sg_fd * sfp);
@@ -240,11 +242,14 @@
     if (! sdp->headfp) { /* no existing opens on this device */
         sdp->sgdebug = 0;
         sdp->sg_tablesize = sdp->device->host->sg_tablesize;
-        sdp->merge_fd = SG_DEF_MERGE_FD;
+        sdp->merge_fd = 0;   /* A little tricky if SG_DEF_MERGE_FD set */
     }
-    if ((sfp = sg_add_sfp(sdp, dev))) {
+    if ((sfp = sg_add_sfp(sdp, dev, O_RDWR == (flags & O_ACCMODE)))) {
+        filp->private_data = sfp;
+#if SG_DEF_MERGE_FD
         if (0 == sdp->merge_fd)
-            filp->private_data = sfp;
+            sdp->merge_fd = 1;
+#endif
     }
     else {
         if (flags & O_EXCL) sdp->exclude = 0; /* undo if error */
@@ -322,11 +327,12 @@
             return -ERESTARTSYS;
         srp = sg_get_request(sfp, req_pack_id);
     }
-    srp->header.pack_len = srp->header.reply_len;   /* Why ????? */
+    if (2 != sfp->underrun_flag)
+        srp->header.pack_len = srp->header.reply_len;   /* Why ????? */
 
     /* Now copy the result back to the user buffer.  */
     if (count >= size_sg_header) {
-        copy_to_user(buf, &srp->header, size_sg_header);
+        __copy_to_user(buf, &srp->header, size_sg_header);
         buf += size_sg_header;
         if (count > srp->header.reply_len)
             count = srp->header.reply_len;
@@ -371,7 +377,7 @@
         ; /* FIXME: Hmm.  Seek to the right place, or fail?  */
 
     if ((k = verify_area(VERIFY_READ, buf, count)))
-        return k;
+        return k;  /* protects following copy_from_user()s + get_user()s */
 /* The minimum scsi command length is 6 bytes.  If we get anything
  * less than this, it is clearly bogus.  */
     if (count < (size_sg_header + 6))
@@ -382,10 +388,10 @@
         SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full, domain error\n"));
         return -EDOM;
     }
-    copy_from_user(&srp->header, buf, size_sg_header);
+    __copy_from_user(&srp->header, buf, size_sg_header); 
     buf += size_sg_header;
     srp->header.pack_len = count;
-    get_user(opcode, buf);
+    __get_user(opcode, buf);
     cmd_size = COMMAND_SIZE(opcode);
     if ((opcode >= 0xc0) && srp->header.twelve_byte) 
         cmd_size = 12;
@@ -427,7 +433,7 @@
     SCpnt->sense_buffer[0] = 0;
     SCpnt->cmd_len = cmd_size;
     /* Now copy the SCSI command from the user's address space.  */
-    copy_from_user(cmnd, buf, cmd_size);
+    __copy_from_user(cmnd, buf, cmd_size);
 
 /* Set the LUN field in the command structure.  */
     cmnd[1]= (cmnd[1] & 0x1f) | (sdp->device->lun << 5);
@@ -439,11 +445,10 @@
     SCpnt->use_sg = srp->data.use_sg;
     SCpnt->sglist_len = srp->data.sglist_len;
     SCpnt->bufflen = srp->data.bufflen;
-    SCpnt->underflow = srp->data.bufflen;
-/* Not many drivers look at this:
-        aic7xxx driver gives DID_RETRY_COMMAND on underrun
-        seagate comments out its underrun checking code, and the rest ...
-*/
+    if (1 == sfp->underrun_flag)
+        SCpnt->underflow = srp->data.bufflen;
+    else
+        SCpnt->underflow = 0;
     SCpnt->buffer = srp->data.buffer;
     srp->data.use_sg = 0;
     srp->data.sglist_len = 0;
@@ -479,14 +484,10 @@
     switch(cmd_in)
     {
     case SG_SET_TIMEOUT:
-        result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
-        if (result) return result;
         return get_user(sfp->timeout, (int *)arg);
     case SG_GET_TIMEOUT:
         return sfp->timeout; /* strange ..., for backward compatibility */
     case SG_SET_FORCE_LOW_DMA:
-        result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
-        if (result) return result;
         result = get_user(val, (int *)arg);
         if (result) return result;
         if (val) {
@@ -503,28 +504,23 @@
             sfp->low_dma = sdp->device->host->unchecked_isa_dma;
         return 0;
     case SG_GET_LOW_DMA:
-        result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
-        if (result) return result;
-        put_user((int)sfp->low_dma, (int *)arg);
-        return 0;
+        return put_user((int)sfp->low_dma, (int *)arg);
     case SG_GET_SCSI_ID:
         result = verify_area(VERIFY_WRITE, (void *)arg, sizeof(Sg_scsi_id));
         if (result) return result;
         else {
             Sg_scsi_id * sg_idp = (Sg_scsi_id *)arg;
-            put_user((int)sdp->device->host->host_no, &sg_idp->host_no);
-            put_user((int)sdp->device->channel, &sg_idp->channel);
-            put_user((int)sdp->device->id, &sg_idp->scsi_id);
-            put_user((int)sdp->device->lun, &sg_idp->lun);
-            put_user((int)sdp->device->type, &sg_idp->scsi_type);
-            put_user(0, &sg_idp->unused1);
-            put_user(0, &sg_idp->unused2);
-            put_user(0, &sg_idp->unused3);
+            __put_user((int)sdp->device->host->host_no, &sg_idp->host_no);
+            __put_user((int)sdp->device->channel, &sg_idp->channel);
+            __put_user((int)sdp->device->id, &sg_idp->scsi_id);
+            __put_user((int)sdp->device->lun, &sg_idp->lun);
+            __put_user((int)sdp->device->type, &sg_idp->scsi_type);
+            __put_user(0, &sg_idp->unused1);
+            __put_user(0, &sg_idp->unused2);
+            __put_user(0, &sg_idp->unused3);
             return 0;
         }
     case SG_SET_FORCE_PACK_ID:
-        result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
-        if (result) return result;
         result = get_user(val, (int *)arg);
         if (result) return result;
         sfp->force_packid = val ? 1 : 0;
@@ -535,16 +531,14 @@
         srp = sfp->headrp;
         while (srp) {
             if (! srp->my_cmdp) {
-                put_user(srp->header.pack_id, (int *)arg);
+                __put_user(srp->header.pack_id, (int *)arg);
                 return 0;
             }
             srp = srp->nextrp;
         }
-        put_user(-1, (int *)arg);
+        __put_user(-1, (int *)arg);
         return 0;
     case SG_GET_NUM_WAITING:
-        result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
-        if (result) return result;
         srp = sfp->headrp;
         val = 0;
         while (srp) {
@@ -552,36 +546,25 @@
                 ++val;
             srp = srp->nextrp;
         }
-        put_user(val, (int *)arg);
-        return 0;
+        return put_user(val, (int *)arg);
     case SG_GET_SG_TABLESIZE:
-        result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
-        if (result) return result;
-        put_user(sdp->sg_tablesize, (int *)arg);
-        return 0;
+        return put_user(sdp->sg_tablesize, (int *)arg);
     case SG_SET_RESERVED_SIZE:
         /* currently ignored, future extension */
         if (O_RDWR != (filp->f_flags & O_ACCMODE))
             return -EACCES;
-        result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
+        result = get_user(val, (int *)arg);
         if (result) return result;
+        /* logic should go here */
         return 0;
     case SG_GET_RESERVED_SIZE:
-        result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
-        if (result) return result;
-        put_user(sfp->fb_size, (int *)arg);
-        return 0;
+        return put_user(sfp->fb_size, (int *)arg);
     case SG_GET_MERGE_FD:
-        result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
-        if (result) return result;
-        put_user((int)sdp->merge_fd, (int *)arg);
-        return 0;
+        return put_user((int)sdp->merge_fd, (int *)arg);
     case SG_SET_MERGE_FD:
         if (O_RDWR != (filp->f_flags & O_ACCMODE))
             return -EACCES; /* require write access since effect wider
                                then just this fd */
-        result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
-        if (result) return result;
         result = get_user(val, (int *)arg);
         if (result) return result;
         val = val ? 1 : 0;
@@ -591,17 +574,19 @@
         sdp->merge_fd = val;
         return 0;
     case SG_SET_COMMAND_Q:
-        result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
-        if (result) return result;
         result = get_user(val, (int *)arg);
         if (result) return result;
         sfp->cmd_q = val ? 1 : 0;
         return 0;
     case SG_GET_COMMAND_Q:
-        result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
+        return put_user((int)sfp->cmd_q, (int *)arg);
+    case SG_SET_UNDERRUN_FLAG:
+        result = get_user(val, (int *)arg);
         if (result) return result;
-        put_user((int)sfp->cmd_q, (int *)arg);
+        sfp->underrun_flag = val;
         return 0;
+    case SG_GET_UNDERRUN_FLAG:
+        return put_user((int)sfp->underrun_flag, (int *)arg);
     case SG_EMULATED_HOST:
         return put_user(sdp->device->host->hostt->emulated, (int *)arg);
     case SCSI_IOCTL_SEND_COMMAND:
@@ -613,8 +598,6 @@
                                dangerous */
         return scsi_ioctl_send_command(sdp->device, (void *)arg);
     case SG_SET_DEBUG:
-        result = verify_area(VERIFY_READ, (const void *)arg, sizeof(int));
-        if (result) return result;
         result = get_user(val, (int *)arg);
         if (result) return result;
         sdp->sgdebug = (char)val;
@@ -625,6 +608,8 @@
         return 0;
     case SCSI_IOCTL_GET_IDLUN:
     case SCSI_IOCTL_GET_BUS_NUMBER:
+    case SCSI_IOCTL_PROBE_HOST:
+    case SG_GET_TRANSFORM:
         return scsi_ioctl(sdp->device, cmd_in, (void *)arg);
     default:
         if (O_RDWR != (filp->f_flags & O_ACCMODE))
@@ -698,6 +683,7 @@
     sdp = &sg_dev_arr[dev];
     if (NULL == sdp->device)
         return; /* Get out of here quick ... */
+
     sfp = sdp->headfp;
     while (sfp) {
         srp = sfp->headrp;
@@ -721,6 +707,8 @@
     srp->data.sglist_len = SCpnt->sglist_len;
     srp->data.bufflen = SCpnt->bufflen;
     srp->data.buffer = SCpnt->buffer;
+    if (2 == sfp->underrun_flag)
+        srp->header.pack_len = SCpnt->underflow;
     sg_clr_scpnt(SCpnt);
     srp->my_cmdp = NULL;
 
@@ -755,7 +743,7 @@
        * underrun or overrun should signal an error.  Until that can be
        * implemented, this kludge allows for returning useful error values
        * except in cases that return DID_ERROR that might be due to an
-       * underrun. [Underrun on advansys adapter yields DID_ABORT -dpg]  */
+       * underrun. */
       if (SCpnt->sense_buffer[0] == 0 &&
           status_byte(SCpnt->result) == GOOD)
           srp->header.result = 0;
@@ -887,8 +875,9 @@
             printk(">> Following FD has NULL parent pointer ???\n");
         printk("   FD(%d): timeout=%d, fb_size=%d, cmd_q=%d\n",
                k, fp->timeout, fp->fb_size, (int)fp->cmd_q);
-        printk("   low_dma=%d, force_packid=%d, closed=%d\n",
-               (int)fp->low_dma, (int)fp->force_packid, (int)fp->closed);
+        printk("   low_dma=%d, force_packid=%d, urun_flag=%d, closed=%d\n",
+               (int)fp->low_dma, (int)fp->force_packid, 
+               (int)fp->underrun_flag, (int)fp->closed);
         srp = fp->headrp;
         if (NULL == srp)
             printk("     No requests active\n");
@@ -1002,7 +991,7 @@
     sdp->generic_wait = NULL;
     sdp->headfp= NULL;
     sdp->exclude = 0;
-    sdp->merge_fd = 0;
+    sdp->merge_fd = 0;  /* Cope with SG_DEF_MERGE_FD on open */
     sdp->sgdebug = 0;
     sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0;
     sdp->i_rdev = MKDEV(SCSI_GENERIC_MAJOR, k);
@@ -1120,7 +1109,7 @@
     if ((blk_size < 0) || (! srp))
         return -EFAULT;
     
-    SCSI_LOG_TIMEOUT(4, printk("sg build: m_b_s=%d, num_write_xfer=%d\n", 
+    SCSI_LOG_TIMEOUT(4, printk("sg_sc_build: m_b_s=%d, num_write_xfer=%d\n", 
                                   max_buff_size, num_write_xfer)); 
     if (0 == blk_size)
         ++blk_size;             /* don't know why */
@@ -1139,7 +1128,7 @@
             srp->data.mem_src = mem_src;
             srp->data.b_malloc_len = blk_size;
             if (inp && (num_write_xfer > 0))
-                copy_from_user(srp->data.buffer, inp, num_write_xfer);
+                __copy_from_user(srp->data.buffer, inp, num_write_xfer);
             return 0;
         }
     }
@@ -1185,17 +1174,17 @@
             }
             sclp->address = p;
             sclp->length = ret_sz;
-            sclp->alt_address = (char *)mem_src;
+            sclp->alt_address = (char *)(long)mem_src;
             
             if(inp && (num_write_xfer > 0)) {
                 num = (ret_sz > num_write_xfer) ? num_write_xfer : ret_sz;
-                copy_from_user(sclp->address, inp, num);
+                __copy_from_user(sclp->address, inp, num);
                 num_write_xfer -= num;
                 inp += num;
             }
             SCSI_LOG_TIMEOUT(5, 
-                printk("sg_sc_build: k=%d, a=0x%x, len=%d, ms=%d\n", 
-                k, (int)sclp->address, ret_sz, (int)sclp->alt_address));
+                printk("sg_sc_build: k=%d, a=0x%p, len=%d, ms=%d\n", 
+                k, sclp->address, ret_sz, mem_src));
         } /* end of for loop */
         srp->data.use_sg = k;
         SCSI_LOG_TIMEOUT(5, 
@@ -1224,20 +1213,20 @@
             if (num_read_xfer > 0) {
                 num = (int)sclp->length;
                 if (num > num_read_xfer) {
-                    copy_to_user(outp, sclp->address, num_read_xfer);
+                    __copy_to_user(outp, sclp->address, num_read_xfer);
                     outp += num_read_xfer;
                     num_read_xfer = 0;
                 }
                 else {
-                    copy_to_user(outp, sclp->address, num);
+                    __copy_to_user(outp, sclp->address, num);
                     outp += num;
                     num_read_xfer -= num;
                 }
             }
-            mem_src = (int)sclp->alt_address;
+            mem_src = (int)(long)sclp->alt_address;
             SCSI_LOG_TIMEOUT(5, 
-                printk("sg_sc_undo_rem: k=%d, a=0x%x, len=%d, ms=%d\n", 
-                       k, (int)sclp->address, sclp->length, mem_src));
+                printk("sg_sc_undo_rem: k=%d, a=0x%p, len=%d, ms=%d\n", 
+                       k, sclp->address, sclp->length, mem_src));
             sg_free(srp, sclp->address, sclp->length, mem_src);
         }
         sg_free(srp, srp->data.buffer, srp->data.sglist_len, 
@@ -1245,13 +1234,13 @@
     }
     else {
         if (num_read_xfer > 0) 
-            copy_to_user(outp, srp->data.buffer, num_read_xfer);
+            __copy_to_user(outp, srp->data.buffer, num_read_xfer);
         sg_free(srp, srp->data.buffer, srp->data.b_malloc_len, 
                 srp->data.mem_src);
     }
     if (0 == sg_remove_request(srp->parentfp, srp)) {
-        SCSI_LOG_TIMEOUT(1, printk("sg_sc_undo_rem: srp=%d not found\n", 
-                                   (int)srp));
+        SCSI_LOG_TIMEOUT(1, printk("sg_sc_undo_rem: srp=0x%p not found\n", 
+                                   srp));
     }
     return 0;
 }
@@ -1336,7 +1325,7 @@
     return 0;
 }
 
-static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev)
+static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev, int get_reserved)
 {
     Sg_fd * sfp;
 
@@ -1357,8 +1346,12 @@
     sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
                    sdp->device->host->unchecked_isa_dma : 1;
     sfp->cmd_q = SG_DEF_COMMAND_Q;
-    sfp->fst_buf = sg_low_malloc(SG_SCATTER_SZ, sfp->low_dma, 
-                                 SG_HEAP_PAGE, &sfp->fb_size);
+    sfp->underrun_flag = SG_DEF_UNDERRUN_FLAG;
+    if (get_reserved)
+        sfp->fst_buf = sg_low_malloc(SG_SCATTER_SZ, sfp->low_dma, 
+                                     SG_HEAP_PAGE, &sfp->fb_size);
+    else
+        sfp->fst_buf = NULL;
     if (! sfp->fst_buf)
         sfp->fb_size = 0;
     sfp->parentdp = sdp;
@@ -1371,10 +1364,10 @@
         pfp->nextfp = sfp;
     }
     sg_big_buff = sfp->fb_size; /* show sysctl most recent "fb" size */
-    SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%x, m_s=%d\n",
-                               (int)sfp, (int)sfp->my_mem_src));
-    SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp:   fb_sz=%d, fst_buf=0x%x\n",
-                               sfp->fb_size, (int)sfp->fst_buf));
+    SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p, m_s=%d\n",
+                               sfp, (int)sfp->my_mem_src));
+    SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp:   fb_sz=%d, fst_buf=0x%p\n",
+                               sfp->fb_size, sfp->fst_buf));
     return sfp;
 }
 
@@ -1416,13 +1409,13 @@
                 prev_fp = fp;
             }
         }
-SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp:    fb_sz=%d, fst_buf=0x%x\n",
-                 sfp->fb_size, (int)sfp->fst_buf));
+SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp:    fb_sz=%d, fst_buf=0x%p\n",
+                 sfp->fb_size, sfp->fst_buf));
         sg_low_free(sfp->fst_buf, sfp->fb_size, SG_HEAP_PAGE);
         sfp->parentdp = NULL;
         sfp->fst_buf = NULL;
         sfp->fb_size = 0;
-    SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp:    sfp=0x%x\n", (int)sfp));
+    SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp:    sfp=0x%p\n", sfp));
         sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->my_mem_src);
         res = 1;
     }
@@ -1573,8 +1566,8 @@
         }
         if (resp) *mem_srcp = l_ms;
     }
-    SCSI_LOG_TIMEOUT(6, printk("sg_malloc: size=%d, ms=%d, ret=0x%x\n", 
-                               size, *mem_srcp, (int)resp));
+    SCSI_LOG_TIMEOUT(6, printk("sg_malloc: size=%d, ms=%d, ret=0x%p\n", 
+                               size, *mem_srcp, resp));
     return resp;
 }
 
@@ -1598,8 +1591,8 @@
         free_pages((unsigned long)buff, order);
     }
     else
-        printk("sg_low_free: bad mem_src=%d, buff=0x%x, rqSz=%df\n", 
-               mem_src, (int)buff, size);
+        printk("sg_low_free: bad mem_src=%d, buff=0x%p, rqSz=%df\n", 
+               mem_src, buff, size);
 }
 
 static void sg_free(Sg_request * srp, char * buff, int size, int mem_src)
@@ -1607,7 +1600,7 @@
     Sg_fd * sfp = srp->parentfp;
 
     SCSI_LOG_TIMEOUT(6, 
-        printk("sg_free: buff=0x%x, size=%d\n", (int)buff, size));
+        printk("sg_free: buff=0x%p, size=%d\n", buff, size));
     if ((! sfp) || (! buff) || (size <= 0))
         ;
     else if (sfp->fst_buf == buff) {
@@ -1624,5 +1617,7 @@
     SCpnt->sglist_len = 0;
     SCpnt->bufflen = 0;
     SCpnt->buffer = NULL;
+    SCpnt->underflow = 0;
+    SCpnt->request.rq_dev = MKDEV(0, 0);  /* "sg" _disowns_ command blk */
 }
 
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.2.7/linux/drivers/usb/Config.in	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/Config.in	Mon May 10 10:18:34 1999
@@ -16,6 +16,10 @@
   if [ ! "$CONFIG_USB" = "n" ]; then
     bool 'UHCI (intel PIIX4 and others) support?' CONFIG_USB_UHCI
     bool 'OHCI (compaq and some others) support?' CONFIG_USB_OHCI
+    bool 'OHCI-HCD (other OHCI opt. Virt. Root Hub) support?' CONFIG_USB_OHCI_HCD
+    if [ "$CONFIG_USB_OHCI_HCD" = "y" ]; then
+       bool 'OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB
+    fi
 
     bool 'USB mouse support' CONFIG_USB_MOUSE
     bool 'USB keyboard support' CONFIG_USB_KBD
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/Makefile linux/drivers/usb/Makefile
--- v2.2.7/linux/drivers/usb/Makefile	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/Makefile	Mon May 10 10:18:34 1999
@@ -59,7 +59,17 @@
   endif
 endif
 
-
+ifeq ($(CONFIG_USB_OHCI_HCD),y)
+  ifeq ($(CONFIG_USB), y)
+    L_OBJS += ohci-hcd.o ohci-root-hub.o
+  else
+    ifeq ($(CONFIG_USB),m)
+      USBO_OBJS += ohci-hcd.o ohci-root-hub.o
+      M_OBJS += usb-ohci-hcd.o
+      MIX_OBJS += $(USBX_OBJS)
+    endif
+  endif
+endif
 include $(TOPDIR)/Rules.make
 
 keymap.o: keymap.c
@@ -73,3 +83,6 @@
 usb-ohci.o: ohci.o ohci-debug.o $(USBX_OBJS)
 	$(LD) $(LD_RFLAG) -r -o $@ ohci.o ohci-debug.o $(USBX_OBJS)
 
+usb-ohci-hcd.o: ohci-hcd.o ohci-root-hub.o $(USBX_OBJS)
+	$(LD) $(LD_RFLAG) -r -o $@ ohci-hcd.o ohci-root-hub.o $(USBX_OBJS)
+       
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/README.ohci_hcd linux/drivers/usb/README.ohci_hcd
--- v2.2.7/linux/drivers/usb/README.ohci_hcd	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/README.ohci_hcd	Mon May 10 10:18:34 1999
@@ -0,0 +1,112 @@
+
+The OHCI HCD layer is a simple but nearly complete implementation of what the
+USB people would call a HCD  for the OHCI. 
+ (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled)
+It is based on Linus Torvalds UHCI code and Gregory Smith OHCI fragments (0.03 source tree).
+The layer (functions) on top of it, is for interfacing to the alternate-usb device-drivers. 
+
+- Roman Weissgaerber <weissg@vienna.at>
+
+
+ * v2.1 1999/05/09 ep_addr correction, code cleanup
+ * v0.2.0 1999/05/04 
+ * everything has been moved into 2 files (ohci-hcd.c, ohci-hub-root.c and headers)
+ * virtual root hub is now an option, 
+ * memory allocation based on kmalloc and kfree now, simple Bus error handling, 
+ * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion
+ * 
+ * from Linus Torvalds (uhci.c): APM (not tested); hub, usb_device, bus and related stuff
+ * from Greg Smith (ohci.c): better reset ohci-controller handling, hub
+ * 
+ * v0.1.0 1999/04/27 initial release
+ 
+to remove the module try:
+killall root-hub
+:
+rmmod usb-ohci-hcd
+
+Features:
+- virtual root hub, all basic hub descriptors and commands (state: complete) 
+  this is an option now (v0.2.0)
+  #define  CONFIG_USB_OHCI_VROOTHUB includes the virtual hub code, (VROOTHUB)
+  default is without. 
+  (at the moment: the Virtual Root Hub option is not recommended)
+  
+  files: ohci-root-hub.c, ohci-root-hub.h 
+ 
+
+- Endpoint Descriptor (ED) handling more static approach 
+ (EDs should be allocated in parallel to the SET CONFIGURATION command and they live
+ as long as the function (device) is alive or another configuration is choosen.
+ In the HCD layer the EDs has to be allocated manually either by calling a subroutine
+ or by sending a USB root hub vendor specific command to the virtual root hub.
+ At the alternate linux usb stack EDs will be added (allocated) at their first use.
+ 
+ files: ohci-hcd.c ohci-hcd.h
+ routines:   (do not use for drivers, use the top layer alternate usb commands instead)
+ 
+ int usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr1, 
+            int interval, int load, f_handler handler, int ep_size, int speed)
+       adds an endpoint, (if the endpoint already exists some parameters will be updated)
+       
+ int usb_ohci_rm_ep(struct  usb_ohci_ed *ed, struct ohci * ohci) 
+       removes an endpoint and all pending TDs of that EP
+       
+  usb_ohci_rm_function( struct ohci * ohci, union ep_addr_ ep_addr)
+       removes all Endpoints of a function (device)
+
+- Transfer Descriptors (TD): handling and allocation of TDs is transparent to the upper layers
+  The HCD takes care of TDs and EDs memory allocation whereas the upper layers (UBSD ...) has
+  to take care of buffer allocation.
+  files: ohci-hcd.c ohci-hcd.h 
+
+  There is one basic command for all types of bus transfers (INT, BULK, ISO, CTRL):
+  
+  int ohci_trans_req(struct ohci * ohci, int ep_addr, int ctrl_len, void  *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1)
+  
+  CTRL: ctrl, ctrl_len ... cmd buffer 
+        data, data_len ... data buffer (in or out)
+  INT, BULK:  ctrl = NULL, ctrl_len=0,
+  		data, data_len ... data buffer (in or out)
+  ISO: tbd
+
+  There is no buffer reinsertion done by the internal HCD function. 
+  (The interface layer does this for a INT-pipe on request.)
+  If you want a transfer then you have to 
+  provide buffers by sending ohci_trans_req requests. As they are queued as TDs on an ED
+  you can send as many as you like. They should come back by the callback f_handler in
+  the same order (for each endpoint, not globally) If an error occurs all
+  queued transfers of an endpoint will return unsent. They will be marked with an error status.
+  
+  e.g double-buffering for int transfers:
+
+   	ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
+  	ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
+  	
+  and when a data0 packet returns by the callback f_handler requeue it:
+  	ohci_trans_req(ohci, ep_addr, 0, NULL, data0, data0_len, 0,0)
+  and when a data1 packet returns by the callback f_handler requeue it:
+  	ohci_trans_req(ohci, ep_addr, 0, NULL, data1, data1_len, 0,0)
+  	
+  lw0, lw1 are private fields for upper layers for ids or fine grained handlers.
+  The alternate usb uses them for dev_id and usb_device_irq handler.
+
+
+- Done list handling: returns the requests (callback f_handler in ED) and does 
+  some error handling, root-hub request dequeuing
+  (files: ohci-done-list.c in ohci-hcd.c now(v0.2.0))
+
+ep_addr union or int  is for addressing devices&endpoints: 
+__u8 ep_addr.bep.ep ... bit 3..0  endpoint address
+						bit 4     0
+						bit 6,5  type: eg. 10 CTRL, 11 BULK, 01 INT, 00 ISO
+						bit 7	direction 1 IN, 0 OUT
+
+__u8 ep_addr.bep.fa ... bit 6..0  function address
+						bit 7	  0
+
+(__u8 ep_addr.bep.hc ... host controller nr) not used
+(__u8 ep_addr.bep.host ... host nr) not used
+
+
+  
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/hub.c linux/drivers/usb/hub.c
--- v2.2.7/linux/drivers/usb/hub.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/hub.c	Fri Apr 30 08:20:01 1999
@@ -30,6 +30,9 @@
 /* List of hubs needing servicing */
 static struct list_head hub_event_list;
 
+/* PID of khubd */
+static int khubd_pid = 0;
+
 /*
  * A irq handler returns non-zero to indicate to
  * the low-level driver that it wants to be re-activated,
@@ -166,7 +169,8 @@
 	/* Is it a hub? */
 	if (interface->bInterfaceClass != 9)
 		return -1;
-	if (interface->bInterfaceSubClass != 0)
+	if ((interface->bInterfaceSubClass != 0) &&
+	    (interface->bInterfaceSubClass != 1))
 		return -1;
 
 	/* Multiple endpoints? What kind of mutant ninja-hub is this? */
@@ -398,8 +402,10 @@
 
 	usb_register(&hub_driver);
 	pid = kernel_thread(usb_hub_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-	if (pid >= 0)
+	if (pid >= 0) {
+		khubd_pid = pid;
 		return 0;
+	}
 
 	/* Fall through if kernel_thread failed */
 	usb_deregister(&hub_driver);
@@ -407,3 +413,10 @@
 	return 0;
 }
 
+void hub_cleanup(void)
+{
+	if (khubd_pid >= 0)
+		kill_proc(khubd_pid, SIGINT, 1);
+
+	usb_deregister(&hub_driver);
+}
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/inits.h linux/drivers/usb/inits.h
--- v2.2.7/linux/drivers/usb/inits.h	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/inits.h	Fri Apr 30 08:20:30 1999
@@ -2,3 +2,5 @@
 int usb_kbd_init(void);
 int usb_audio_init(void);
 int hub_init(void);
+void hub_cleanup(void);
+void usb_mouse_cleanup(void);
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/mouse.c linux/drivers/usb/mouse.c
--- v2.2.7/linux/drivers/usb/mouse.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/mouse.c	Fri Apr 30 08:20:49 1999
@@ -1,9 +1,12 @@
 /*
  * USB HID boot protocol mouse support based on MS BusMouse driver, psaux 
- * driver, and Linus's skeleton USB mouse driver
+ * driver, and Linus's skeleton USB mouse driver. Fixed up a lot by Linus.
  *
  * Brad Keryan 4/3/1999
  *
+ * version 0.20: Linus rewrote read_mouse() to do PS/2 and do it
+ * correctly. Events are added together, not queued, to keep the rodent sober.
+ *
  * version 0.02: Hmm, the mouse seems drunk because I'm queueing the events.
  * This is wrong: when an application (like X or gpm) reads the mouse device,
  * it wants to find out the mouse's current position, not its recent history.
@@ -282,18 +285,9 @@
 	return 0;
 }
 
-#if 0
-
-int init_module(void)
-{
-	return usb_mouse_init();
-}
-
-void cleanup_module(void)
+void usb_mouse_cleanup(void)
 {
 	/* this, too, probably needs work */
 	usb_deregister(&mouse_driver);
 	misc_deregister(&usb_mouse);
 }
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/ohci-hcd.c linux/drivers/usb/ohci-hcd.c
--- v2.2.7/linux/drivers/usb/ohci-hcd.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/ohci-hcd.c	Mon May 10 10:18:34 1999
@@ -0,0 +1,1488 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ *
+ * The OHCI HCD layer is a simple but nearly complete implementation of what the
+ * USB people would call a HCD  for the OHCI. 
+ * (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled)
+ * The layer on top of it, is for interfacing to the alternate-usb device-drivers.
+ * 
+ * [ This is based on Linus' UHCI code and gregs OHCI fragments (0.03c source tree). ]
+ * [ Open Host Controller Interface driver for USB. ]
+ * [ (C) Copyright 1999 Linus Torvalds (uhci.c) ]
+ * [ (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com> ]
+ * [ $Log: ohci.c,v $ ]
+ * [ Revision 1.1  1999/04/05 08:32:30  greg ]
+ * 
+ * 
+ * v2.1 1999/05/09 ep_addr correction, code clean up
+ * v2.0 1999/05/04 
+ * virtual root hub is now an option, 
+ * memory allocation based on kmalloc and kfree now, Bus error handling, 
+ * INT and CTRL transfers enabled, Bulk included but disabled, ISO needs completion
+ * 
+ * from Linus Torvalds (uhci.c) (APM not tested; hub, usb_device, bus and related stuff)
+ * from Greg Smith (ohci.c) (reset controller handling, hub)
+ * 
+ * v1.0 1999/04/27 initial release
+ * ohci-hcd.c
+ */
+
+/* #define OHCI_DBG  */  /* printk some debug information */
+
+ 
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+
+#include <asm/spinlock.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "usb.h"
+#include "ohci-hcd.h"
+#include "inits.h" 
+
+ 
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+static int handle_apm_event(apm_event_t event);
+static int apm_resume = 0;
+#endif
+
+ 
+
+static struct wait_queue *control_wakeup;         
+static struct wait_queue *root_hub = NULL;
+ 
+static __u8 cc_to_status[16] = { /* mapping of the OHCI CC to the UHCI status codes; first guess */
+/* Activ, Stalled, Data Buffer Err, Babble Detected : NAK recvd, CRC/Timeout, Bitstuff, reservd */
+/* No  Error  */		0x00,
+/* CRC Error  */		0x04,
+/* Bit Stuff  */		0x02,
+/* Data Togg  */ 		0x40,
+/* Stall      */		0x40,
+/* DevNotResp */		0x04,
+/* PIDCheck   */		0x04,
+/* UnExpPID   */		0x40,
+/* DataOver   */		0x20,
+/* DataUnder  */ 		0x20,
+/* reservd    */		0x40,
+/* reservd    */		0x40,
+/* BufferOver */		0x20,
+/* BuffUnder  */		0x20,
+/* Not Access */		0x80,
+/* Not Access */		0x80
+ };
+ 
+ 
+/********
+ **** Interface functions
+ ***********************************************/
+ 
+static int sohci_int_handler(void * ohci_in, unsigned int ep_addr, int ctrl_len, void * ctrl, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw1)
+{
+
+	struct ohci * ohci = ohci_in; 
+	usb_device_irq handler=(void *) lw0;
+	void *dev_id = (void *) lw1;
+	int ret;
+	
+	OHCI_DEBUG({ int i; printk("USB HC IRQ <<<: %x: data(%d):", ep_addr, data_len);)
+	OHCI_DEBUG( for(i=0; i < data_len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
+	OHCI_DEBUG( printk(" ret_status: %x\n", status); })
+	
+ 	ret = handler(cc_to_status[status & 0xf], data, dev_id);
+	if(ret == 0) return 0; /* 0 .. do not requeue  */
+	if(status > 0) return -1; /* error occured do not requeue ? */
+	ohci_trans_req(ohci, ep_addr, 0, NULL, data, 8, (__OHCI_BAG) handler, (__OHCI_BAG) dev_id); /* requeue int request */
+	return 0;
+}
+
+static int sohci_ctrl_handler(void * ohci_in, unsigned int ep_addr, int ctrl_len, void * ctrl, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw)
+{  
+	*(int * )lw0 = status;
+	wake_up(&control_wakeup);
+
+	OHCI_DEBUG( { int i; printk("USB HC CTRL<<<: %x: ctrl(%d):", ep_addr, ctrl_len);)
+	OHCI_DEBUG( for(i=0; i < 8; i++ ) printk(" %02x", ((__u8 *) ctrl)[i]);)
+	OHCI_DEBUG( printk(" data(%d):", data_len);) 
+	OHCI_DEBUG( for(i=0; i < data_len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
+	OHCI_DEBUG( printk(" ret_status: %x\n", status); })
+    return 0;                       
+} 
+                                                             
+static int sohci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
+{
+	struct ohci * ohci = usb_dev->bus->hcpriv;
+	union ep_addr_ ep_addr;
+	
+	ep_addr.iep = 0;
+	ep_addr.bep.ep = ((pipe >> 15) & 0x0f) 		/* endpoint address */
+				| (pipe  & 0x80)  	 			/* direction */
+				| (1 << 5);						/* type = int*/
+	ep_addr.bep.fa = ((pipe >> 8) & 0x7f);			/* device address */
+
+	OHCI_DEBUG( printk("USB HC IRQ >>>: %x: every %d ms\n", ep_addr.iep, period);) 
+	
+	usb_ohci_add_ep(ohci, ep_addr.iep, period, 1, sohci_int_handler, 1 << ((pipe & 0x03) + 3) , (pipe >> 26) & 0x01);
+	
+   	ohci_trans_req(ohci, ep_addr.iep, 0, NULL, ((struct ohci_device *) usb_dev->hcpriv)->data, 8, (__OHCI_BAG) handler, (__OHCI_BAG) dev_id);
+	return 0;
+}
+
+
+static int sohci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void *cmd, void *data, int len)
+{
+	struct wait_queue wait = { current, NULL }; 
+	struct ohci * ohci = usb_dev->bus->hcpriv;
+	int status;
+	union ep_addr_ ep_addr;
+
+    ep_addr.iep = 0;
+	ep_addr.bep.ep = ((pipe >> 15) & 0x0f) 		/* endpoint address */		
+				| (pipe  & 0x80)  				/* direction */
+				|  (1 << 6);					/* type = ctrl*/
+	ep_addr.bep.fa	= ((pipe >> 8) & 0x7f);				/* device address */
+	
+	status = 0xf; /* CC not Accessed */
+	OHCI_DEBUG( { int i; printk("USB HC CTRL>>>: %x: ctrl(%d):", ep_addr.iep, 8);)
+	OHCI_DEBUG( for(i=0; i < 8; i++ ) printk(" %02x", ((__u8 *) cmd)[i]);)
+	OHCI_DEBUG( printk(" data(%d):", len);) 
+	OHCI_DEBUG( for(i=0; i < len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
+	OHCI_DEBUG( printk("\n"); })
+	
+	usb_ohci_add_ep(ohci, ep_addr.iep, 0, 1, sohci_ctrl_handler, 1 << ((pipe & 0x03) + 3) , (pipe >> 26) & 0x01);
+	
+	current->state = TASK_UNINTERRUPTIBLE;
+    add_wait_queue(&control_wakeup, &wait);   
+ 
+	ohci_trans_req(ohci, ep_addr.iep, 8, cmd, data, len, (__OHCI_BAG) &status, 0);
+
+	schedule_timeout(HZ/10);
+
+    remove_wait_queue(&control_wakeup, &wait); 
+     
+    OHCI_DEBUG(printk("USB HC status::: %x\n", cc_to_status[status & 0x0f]);)
+     
+	return cc_to_status[status & 0x0f];
+}
+
+
+static int sohci_usb_deallocate(struct usb_device *usb_dev) {
+    struct ohci_device *dev = usb_to_ohci(usb_dev); 
+	union ep_addr_ ep_addr;
+
+	ep_addr.iep = 0;
+	
+	OHCI_DEBUG(printk("USB HC dealloc %x\n", usb_dev->devnum);)
+
+	/* wait_ms(20); */
+
+	if(usb_dev->devnum >=0) {
+		ep_addr.bep.fa = usb_dev->devnum;
+    	usb_ohci_rm_function(((struct ohci_device *)usb_dev->hcpriv)->ohci, ep_addr.iep);
+	}
+	
+    USB_FREE(dev);
+	USB_FREE(usb_dev);
+
+	return 0;
+}
+
+static struct usb_device *sohci_usb_allocate(struct usb_device *parent) {
+ 
+	struct usb_device *usb_dev;
+	struct ohci_device *dev;
+	
+	
+	USB_ALLOC(usb_dev, sizeof(*usb_dev));
+	if (!usb_dev)
+		return NULL;
+		
+	memset(usb_dev, 0, sizeof(*usb_dev));
+
+	USB_ALLOC(dev, sizeof(*dev));
+	if (!dev) {
+		USB_FREE(usb_dev);
+		return NULL;
+	}
+
+	/* Initialize "dev" */
+	memset(dev, 0, sizeof(*dev));
+
+	usb_dev->hcpriv = dev;
+	dev->usb = usb_dev;
+
+	usb_dev->parent = parent;
+
+	if (parent) {
+		usb_dev->bus = parent->bus;
+		dev->ohci = usb_to_ohci(parent)->ohci;
+	}
+	return usb_dev;
+}
+
+struct usb_operations sohci_device_operations = {
+	sohci_usb_allocate,
+	sohci_usb_deallocate,
+	sohci_control_msg,
+	sohci_request_irq,
+};
+
+ 
+/******
+ *** ED handling functions
+ ************************************/
+
+
+
+/* 
+ * search for the right place to insert an interrupt ed into the int tree 
+ * do some load ballancing
+ * */
+
+static int usb_ohci_int_ballance(struct ohci * ohci, int interval, int load) {
+
+  int i,j;
+  
+  j = 0;   /* search for the least loaded interrupt endpoint branch of all 32 branches */
+  for(i=0; i< 32; i++) if(ohci->ohci_int_load[j] > ohci->ohci_int_load[i]) j=i; 
+
+  if(interval < 1) interval = 1;
+  if(interval > 32) interval = 32;
+  for(i= 0; ((interval >> i) > 1 ); interval &= (0xfffe << i++ )); /* interval = 2^int(ld(interval)) */
+  
+
+  for(i=j%interval; i< 32; i+=interval) ohci->ohci_int_load[i] += load;
+  j = interval + (j % interval); 
+  
+  OHCI_DEBUG(printk("USB HC new int ed on pos : %x \n",j);)
+  
+  return j;
+}
+
+/* get the ed from the endpoint / device adress */
+
+struct usb_ohci_ed * ohci_find_ep(struct ohci *ohci, unsigned int ep_addr_in) {
+
+union ep_addr_ ep_addr;
+struct usb_ohci_ed *tmp;
+unsigned int mask;
+
+mask = 0;
+ep_addr.iep = ep_addr_in;
+
+#ifdef VROOTHUB
+ if(ep_addr.bep.fa == ohci->root_hub_funct_addr) {
+ 	if((ep_addr.bep.ep & 0x0f) == 0)
+ 		return &ohci->ed_rh_ep0; /* root hub ep0 */
+ 	else
+ 		return &ohci->ed_rh_epi; /* root hub int ep */
+ }
+#endif
+
+ tmp = ohci->ed_func_ep0[ep_addr.bep.fa];
+ mask = ((((ep_addr.bep.ep >> 5) & 0x03)==2)?0x7f:0xff); 
+ ep_addr.bep.ep &= mask; /* mask out direction of ctrl ep */
+ 
+  while (tmp != NULL) {
+    if (tmp->ep_addr.iep == ep_addr.iep) 
+      return tmp;
+    tmp = tmp->ed_list;
+  }
+  return NULL;
+}
+ 
+spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
+/* add a new endpoint ep_addr */
+struct usb_ohci_ed *usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr_in, int interval, int load, f_handler handler, int ep_size, int speed) {
+   
+  struct usb_ohci_ed * ed; 
+  struct usb_ohci_td * td;
+  union ep_addr_ ep_addr;
+ 
+   
+  int int_junk;
+ 
+  struct usb_ohci_ed *tmp;
+
+  ep_addr.iep = ep_addr_in ;
+  ep_addr.bep.ep &= ((((ep_addr.bep.ep >> 5) & 0x03)==2)?0x7f:0xff); /* mask out direction of ctrl ep */
+
+  spin_lock(&usb_ed_lock);
+  
+  tmp =  ohci_find_ep(ohci, ep_addr.iep);
+  if (tmp != NULL) { 
+  
+#ifdef VROOTHUB
+  	if(ep_addr.bep.fa == ohci->root_hub_funct_addr) {
+ 		if((ep_addr.bep.ep & 0x0f) != 0) { /* root hub int ep */
+			ohci->ed_rh_epi.handler = handler;
+ 			ohci_init_rh_int_timer(ohci, interval);
+ 		}
+ 		else { /* root hub ep0 */
+ 			 ohci->ed_rh_ep0.handler = handler;
+ 		}			 	
+ 	}
+
+ 	else 
+#endif 
+
+ 		{
+ 		tmp->hw.info = ep_addr.bep.fa | ((ep_addr.bep.ep & 0xf) <<7)
+  		
+    	| (((ep_addr.bep.ep & 0x60) == 0)? 0x8000 : 0)
+    	| (speed << 13)
+    	| ep_size <<16;
+ 
+  		tmp->handler = handler; 
+  	}
+ 	spin_unlock(&usb_ed_lock);
+    return tmp;    /* ed  already in use */
+  }
+  
+  
+  OHCI_ALLOC(td, sizeof(td)); /* dummy td; end of td list for ed */
+  OHCI_ALLOC(ed, sizeof(ed));
+  td->prev_td = NULL;
+  
+  ed->hw.tail_td = virt_to_bus(&td->hw);
+  ed->hw.head_td = ed->hw.tail_td;
+  ed->hw.info = ep_addr.bep.fa | ((ep_addr.bep.ep & 0xf) <<7)
+  /*  | ((ep_addr.bep.port & 0x80)? 0x1000 : 0x0800 ) */
+    | (((ep_addr.bep.ep & 0x60) == 0)? 0x8000 : 0)
+    | (speed << 13)
+    | ep_size <<16;
+  
+  ed->handler = handler;
+
+  switch((ep_addr.bep.ep >> 5) & 0x03) {
+  case CTRL:
+    ed->hw.next_ed = 0;
+    if(ohci->ed_controltail == NULL) {
+      writel(virt_to_bus(&ed->hw), &ohci->regs->ed_controlhead);
+    }
+    else {
+      ohci->ed_controltail->hw.next_ed = virt_to_bus(&ed->hw);
+    }
+    ed->ed_prev = ohci->ed_controltail;
+    ohci->ed_controltail = ed;	  
+    break;
+  case BULK:  
+    ed->hw.next_ed = 0;
+    if(ohci->ed_bulktail == NULL) {
+      writel(virt_to_bus(&ed->hw), &ohci->regs->ed_bulkhead);
+    }
+    else {
+      ohci->ed_bulktail->hw.next_ed = virt_to_bus(&ed->hw);
+    }
+    ed->ed_prev = ohci->ed_bulktail;
+    ohci->ed_bulktail = ed;	  
+    break;
+  case INT:
+    int_junk = usb_ohci_int_ballance(ohci, interval, load);
+    ed->hw.next_ed = ohci->hc_area->ed[int_junk].next_ed; 
+    ohci->hc_area->ed[int_junk].next_ed = virt_to_bus(&ed->hw);
+    ed->ed_prev = (struct usb_ohci_ed *) &ohci->hc_area->ed[int_junk];
+    break;
+  case ISO:
+    ed->hw.next_ed = 0;
+    ohci->ed_isotail->hw.next_ed = virt_to_bus(&ed->hw);
+    ed->ed_prev = ohci->ed_isotail;
+    ohci->ed_isotail = ed;	  
+    break;
+  }
+  ed->ep_addr  = ep_addr;
+  
+  /* Add it to the "hash"-table of known endpoint descriptors */      
+  
+  ed->ed_list = ohci->ed_func_ep0[ed->ep_addr.bep.fa];
+  ohci->ed_func_ep0[ed->ep_addr.bep.fa] = ed; 
+
+  spin_unlock(&usb_ed_lock);
+  
+  OHCI_DEBUG(printk("USB HC new ed %x: %x :", ep_addr.iep, (unsigned int ) ed); )
+  OHCI_DEBUG({ int i; for( i= 0; i<8 ;i++) printk(" %4x", ((unsigned int *) ed)[i]) ; printk("\n"); }; )
+  return 0;
+}
+
+/*****
+ * Request the removal of an endpoint
+ * 
+ * put the ep on the rm_list and request a stop of the bulk or ctrl list 
+ * real removal is done at the next start of frame hardware interrupt 
+ */
+int usb_ohci_rm_ep(struct ohci * ohci, struct  usb_ohci_ed *ed)
+{    
+  unsigned int flags;
+  struct usb_ohci_ed *tmp;
+  
+  OHCI_DEBUG(printk("USB HC remove ed %x: %x :\n", ed->ep_addr.iep, (unsigned int ) ed); )
+
+  spin_lock_irqsave(&usb_ed_lock, flags);
+
+  tmp = ohci->ed_func_ep0[ed->ep_addr.bep.fa];
+  if (tmp == NULL) {
+  	spin_unlock_irqrestore(&usb_ed_lock, flags);
+    return 0;
+  }
+
+  if(tmp == ed) {
+     ohci->ed_func_ep0[ed->ep_addr.bep.fa] = ed->ed_list;
+  }
+  else {
+    while (tmp->ed_list != ed) {
+      if (tmp->ed_list == NULL) {
+        spin_unlock_irqrestore(&usb_ed_lock, flags);
+		return 0;
+	  }
+      tmp = tmp->ed_list;
+    }
+    tmp->ed_list = ed->ed_list;
+  }
+  ed->ed_list = ohci->ed_rm_list;
+  ohci->ed_rm_list = ed;
+  ed->hw.info  |=  OHCI_ED_SKIP;
+
+  switch((ed->ep_addr.bep.ep >> 5) & 0x03) {
+  	case CTRL:
+    	writel_mask(~(0x01<<4), &ohci->regs->control); /* stop CTRL list */
+    	break;
+  	case BULK:
+    	writel_mask(~(0x01<<5), &ohci->regs->control); /* stop BULK list */
+    	break;
+  }
+
+
+  writel( OHCI_INTR_SF, &ohci->regs->intrenable); /* enable sof interrupt */
+
+  spin_unlock_irqrestore(&usb_ed_lock, flags);
+
+  return 1;
+}
+
+/* we have requested to stop the bulk or CTRL list,
+ * now we can remove the eds on the rm_list */
+ 
+static int ohci_rm_eds(struct ohci * ohci) {
+
+  unsigned int flags;
+  struct usb_ohci_ed *ed;
+  struct usb_ohci_ed *ed_tmp;
+  struct usb_ohci_td *td;
+  __u32 td_hw_tmp;
+  __u32 td_hw;
+  
+  spin_lock_irqsave(&usb_ed_lock, flags);
+
+  ed = ohci->ed_rm_list;
+
+  while (ed != NULL) {
+    
+    switch((ed->ep_addr.bep.ep >> 5) & 0x03) {
+    case CTRL: 
+      if(ed->ed_prev == NULL) {
+		writel(ed->hw.next_ed, &ohci->regs->ed_controlhead);
+      }
+      else {
+		ed->ed_prev->hw.next_ed = ed->hw.next_ed;
+      }
+      if(ohci->ed_controltail == ed) {
+		ohci->ed_controltail = ed->ed_prev;
+      }
+      break;
+    case BULK: 
+      if(ed->ed_prev == NULL) {
+		writel(ed->hw.next_ed, &ohci->regs->ed_bulkhead);
+      }
+      else {
+		ed->ed_prev->hw.next_ed = ed->hw.next_ed;
+      }
+      if(ohci->ed_bulktail == ed) {
+		ohci->ed_bulktail = ed->ed_prev;
+      }
+      break;
+    case INT: 
+      	ed->ed_prev->hw.next_ed = ed->hw.next_ed;
+      break;
+    case ISO:
+      ed->ed_prev->hw.next_ed = ed->hw.next_ed;
+      if(ohci->ed_isotail == ed) {
+		ohci->ed_isotail = ed->ed_prev;
+      }
+      break;
+    }
+    
+    if(ed->hw.next_ed != 0) ((struct usb_ohci_ed *) bus_to_virt(ed->hw.next_ed))->ed_prev = ed->ed_prev;
+    
+
+/* tds directly connected to ed */
+ 
+	td_hw = ed->hw.head_td & 0xfffffff0;
+    while(td_hw != 0) {
+    	td = bus_to_virt(td_hw);
+    	td_hw_tmp = td_hw;
+    	td_hw = td->hw.next_td;
+    	OHCI_FREE(td); /* free pending tds */ 
+    	if(td_hw_tmp == ed->hw.tail_td) break;
+    	
+    }
+     
+    /* mark TDs on the hc done list (if there are any) */      
+	td_hw = readl(&ohci->regs->donehead) & 0xfffffff0;
+    while(td_hw != 0) {
+    	td = bus_to_virt(td_hw);
+    	td_hw = td->hw.next_td;
+    	if(td->ep == ed) td->ep = 0;
+   	}
+ 
+    /* mark TDs on the hcca done list (if there are any) */      
+	td_hw = ohci->hc_area->hcca.done_head & 0xfffffff0 ;
+	
+    while(td_hw != 0) { 
+    	td = bus_to_virt(td_hw); 
+    	td_hw = td->hw.next_td;
+    	if(td->ep == ed) td->ep = 0;
+   	}
+
+    ed_tmp = ed;
+    ed = ed->ed_list;
+    OHCI_FREE(ed_tmp);  /* free ed */ 
+  }
+  writel(0, &ohci->regs->ed_controlcurrent); /* reset CTRL list */
+  writel(0, &ohci->regs->ed_bulkcurrent);    /* reset BULK list */
+  writel_set((0x01<<4), &ohci->regs->control);   /* start CTRL u. (BULK list) */ 
+
+  spin_unlock_irqrestore(&usb_ed_lock, flags);
+  
+  ohci->ed_rm_list = NULL;
+  OHCI_DEBUG(printk("USB HC after rm ed control: %4x  intrstat: %4x intrenable: %4x\n", readl(&ohci->regs->control),readl(&ohci->regs->intrstatus),readl(&ohci->regs->intrenable));)
+ 
+
+  return 0;
+}
+
+/* remove all endpoints of a function (device) */
+int usb_ohci_rm_function( struct ohci * ohci, unsigned int ep_addr_in)
+{    
+  struct usb_ohci_ed *ed;
+  struct usb_ohci_ed *tmp;
+  union ep_addr_ ep_addr;
+
+ 
+  
+  ep_addr.iep = ep_addr_in;
+
+  for(ed = ohci->ed_func_ep0[ep_addr.bep.fa]; ed != NULL;) {
+	tmp = ed;
+    ed = ed->ed_list;
+    usb_ohci_rm_ep(ohci, tmp);
+  }
+ 
+
+  
+  return 1;
+}
+
+
+
+
+
+/******
+ *** TD handling functions
+ ************************************/
+
+
+#define FILL_TD(TD_PT, HANDLER, INFO, DATA, LEN, LW0, LW1)  \
+    td_pt = (TD_PT); \
+    td_pt1 = (struct usb_ohci_td *) bus_to_virt(usb_ep->hw.tail_td); \
+    td_pt1->ep = usb_ep; \
+    td_pt1->handler = (HANDLER); \
+    td_pt1->buffer_start = (DATA); \
+    td_pt1->lw0 = (LW0); \
+    td_pt1->lw1 = (LW1); \
+    td_pt1->hw.info = (INFO); \
+    td_pt1->hw.cur_buf = virt_to_bus(DATA); \
+    td_pt1->hw.buf_end = td_pt1->hw.cur_buf + (LEN) - 1; \
+    td_pt1->hw.next_td = virt_to_bus(td_pt); \
+    usb_ep->hw.tail_td = virt_to_bus(td_pt); \
+    td_pt->prev_td = td_pt1; \
+    td_pt->hw.next_td = 0
+
+spinlock_t usb_req_lock = SPIN_LOCK_UNLOCKED;
+
+int ohci_trans_req(struct ohci * ohci, unsigned int ep_addr, int ctrl_len, void  *ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1) {
+
+  int ed_type;
+  unsigned int flags;
+  struct usb_ohci_td *td_pt;
+  struct usb_ohci_td *td_pt1;
+  struct usb_ohci_td *td_pt_a1, *td_pt_a2, *td_pt_a3;
+  struct usb_ohci_ed *usb_ep;
+  f_handler handler;
+
+  
+ td_pt_a1 =NULL;
+ td_pt_a2 =NULL;
+ td_pt_a3 =NULL;
+  
+  usb_ep = ohci_find_ep(ohci, ep_addr);
+  if(usb_ep == NULL ) return -1; /* not known ep */
+  
+  handler = usb_ep->handler;
+ 
+#ifdef VROOTHUB 
+  if(usb_ep == &ohci->ed_rh_ep0) { /* root hub ep 0 control endpoint */  
+    root_hub_control_msg(ohci, 8, ctrl, data, data_len, lw0, lw1, handler);
+    return 0;
+  }
+
+  if(usb_ep == &ohci->ed_rh_epi) { /* root hub interrupt endpoint */
+  
+    root_hub_int_req(ohci, 8, ctrl, data, data_len, lw0, lw1, handler);  
+	return 0;
+  }
+#endif
+  /*  struct usb_ohci_ed * usb_ep = usb_ohci_add_ep(pipe, ohci, interval, 1); */
+ 
+   ed_type = ((((union ep_addr_)ep_addr).bep.ep >> 5) & 0x07);
+  
+  switch(ed_type) {
+  case BULK_IN:
+  case BULK_OUT:   
+  case INT_IN:
+  case INT_OUT:    
+    OHCI_ALLOC(td_pt_a1, sizeof(td_pt_a1));
+    break;
+
+  case CTRL_IN:
+  case CTRL_OUT:
+    OHCI_ALLOC(td_pt_a1, sizeof(td_pt_a1));
+    OHCI_ALLOC(td_pt_a3, sizeof(td_pt_a3));  
+    if(data_len > 0) {
+      OHCI_ALLOC(td_pt_a2, sizeof(td_pt_a2));
+    }
+    break;
+
+  case ISO_IN:
+  case ISO_OUT:
+
+  }
+    
+  spin_lock_irqsave(&usb_req_lock, flags);
+  
+  switch(ed_type) {
+  case BULK_IN:
+    FILL_TD( td_pt_a1, handler, TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE, data, data_len, lw0, lw1 );
+    writel( OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+    break;
+
+  case BULK_OUT: 
+    FILL_TD( td_pt_a1, handler, TD_CC | TD_DP_OUT | TD_T_TOGGLE, data, data_len, lw0, lw1 );
+    writel( OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+    break;
+
+  case INT_IN: 
+    FILL_TD( td_pt_a1, handler, TD_CC | TD_R | TD_DP_IN | TD_T_TOGGLE, data, data_len, lw0, lw1 );  
+    break;
+
+  case INT_OUT: 
+    FILL_TD( td_pt_a1, handler, TD_CC | TD_DP_OUT | TD_T_TOGGLE, data, data_len, lw0, lw1 );
+    break;
+
+  case CTRL_IN: 
+    FILL_TD( td_pt_a1, NULL, TD_CC | TD_DP_SETUP | TD_T_DATA0, ctrl, ctrl_len, 0, 0 );  
+    if(data_len > 0) { 
+      FILL_TD( td_pt_a2, NULL, TD_CC | TD_R |  TD_DP_IN | TD_T_DATA1, data, data_len, 0, 0 );  
+    } 
+    FILL_TD( td_pt_a3, handler, TD_CC | TD_DP_OUT | TD_T_DATA1, NULL, 0, lw0, lw1 );
+    writel( OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+    break;
+
+  case CTRL_OUT:     
+    FILL_TD( td_pt_a1, NULL, TD_CC | TD_DP_SETUP | TD_T_DATA0, ctrl, ctrl_len, 0, 0 );  
+    if(data_len > 0) { 
+      FILL_TD( td_pt_a2, NULL, TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1, data, data_len, 0, 0 );  
+    } 
+    FILL_TD( td_pt_a3, handler, TD_CC | TD_DP_IN | TD_T_DATA1, NULL, 0, lw0, lw1 );
+    writel( OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+    break;
+
+  case ISO_IN:
+  case ISO_OUT:
+    break;
+  }
+
+
+  
+
+ td_pt1 = (struct usb_ohci_td *) bus_to_virt(usb_ep->hw.tail_td); 
+
+ 
+  if(td_pt_a3 != NULL) td_pt_a3->prev_td = NULL;
+  	else if (td_pt_a2 != NULL) td_pt_a2->prev_td = NULL;
+  	  	else if (td_pt_a1 != NULL) td_pt_a1->prev_td = NULL;
+  	  
+  spin_unlock_irqrestore(&usb_req_lock, flags);
+  return 0;
+}
+
+
+/******
+ *** Done List handling functions
+ ************************************/
+
+/* replies to the request have to be on a FIFO basis so
+ * we reverse the reversed done-list */
+ 
+static struct usb_ohci_td * ohci_reverse_done_list(struct ohci * ohci) {
+
+  __u32 td_list_hc;
+  struct usb_ohci_td      * td_list = NULL;
+  struct usb_ohci_td      * td_rev = NULL;
+  	
+	td_list_hc = ohci->hc_area->hcca.done_head & 0xfffffff0;
+    ohci->hc_area->hcca.done_head = 0;
+    
+ 	while(td_list_hc) {
+		
+		td_list = (struct  usb_ohci_td *) bus_to_virt(td_list_hc);
+		td_list->next_dl_td = td_rev;
+			
+		td_rev = td_list;
+		td_list_hc = td_list->hw.next_td & 0xfffffff0;
+	}
+ return td_list;
+}
+
+/* all done requests are replied here */
+static int usb_ohci_done_list(struct ohci *  ohci) {
+
+  struct usb_ohci_td      * td = NULL;
+  struct usb_ohci_td      * td_list; 
+  struct usb_ohci_td      * td_list_next = NULL;
+  struct usb_ohci_td      * td_err = NULL;
+	__u32 td_hw;
+ 
+	
+  td_list = ohci_reverse_done_list(ohci);
+
+  while(td_list) {
+   	td_list_next = td_list->next_dl_td;
+    td = td_list;
+
+    if(td->ep == NULL) { /* removed ep */
+   		OHCI_FREE(td_list);
+   		break;
+   	}
+   	
+   	/* the HC halts an ED if an error occurs; put all pendings TDs of an halted ED on the
+   	 * done list; they are marked with an 0xf CC_error code 
+   	 */
+   	 
+ 	if(TD_CC_GET(td_list->hw.info) != TD_CC_NOERROR) { /* on error move all pending tds of an ed into the done list */
+ 		printk("******* USB BUS error %x @ep %x\n", TD_CC_GET(td_list->hw.info), td_list->ep->ep_addr.iep);
+    td_err= td_list;
+	td_hw = td_list->ep->hw.head_td & 0xfffffff0;
+    while(td_hw != 0) { 
+    	if(td_hw == td_list->ep->hw.tail_td) break;
+    	td = bus_to_virt(td_hw);
+    	td_err->next_dl_td = td;
+    	td_err= td;
+    	td_hw = td->hw.next_td;
+    }
+    td_list->ep->hw.head_td = td_list->ep->hw.tail_td;
+    td->next_dl_td = td_list_next;
+    td_list_next = td_list->next_dl_td;
+ 	
+    }
+  /*  send the reply  */
+ 	if(td_list->handler != NULL)  {
+    	if(td_list->prev_td == NULL) {
+			td_list->handler((void *) ohci,
+						td_list->ep->ep_addr.iep,
+						0, 
+						NULL, 
+						td_list->buffer_start, 
+						td_list->hw.buf_end-virt_to_bus(td_list->buffer_start)+1, 
+						TD_CC_GET(td_list->hw.info),
+						td_list->lw0,
+						td_list->lw1);
+			OHCI_FREE(td_list);			
+   	  	}
+      	else {
+      		if(td_list->prev_td->prev_td == NULL) { /* cntrl 2 Transactions dataless */
+	  		td_list->handler((void *) ohci,
+	  		            td_list->ep->ep_addr.iep,
+	  					td_list->prev_td->hw.buf_end-virt_to_bus(td_list->prev_td->buffer_start)+1,
+	  					td_list->prev_td->buffer_start, 
+	  					NULL,
+	  					0, 
+	  					(TD_CC_GET(td_list->prev_td->hw.info) > 0) ? TD_CC_GET(td_list->prev_td->hw.info) : TD_CC_GET(td_list->hw.info),
+						td_list->lw0,
+						td_list->lw1);
+			OHCI_FREE(td_list->prev_td);
+			OHCI_FREE(td_list);
+			}
+			else { /* cntrl 3 Transactions */
+	  			td_list->handler((void *) ohci,
+	  					td_list->ep->ep_addr.iep, 
+	  					td_list->prev_td->prev_td->hw.buf_end-virt_to_bus(td_list->prev_td->prev_td->buffer_start)+1, 
+	  					td_list->prev_td->prev_td->buffer_start, 
+	  					td_list->prev_td->buffer_start, 
+	  					td_list->prev_td->hw.buf_end-virt_to_bus(td_list->prev_td->buffer_start)+1, 
+	  					(TD_CC_GET(td_list->prev_td->prev_td->hw.info) > 0) ? TD_CC_GET(td_list->prev_td->prev_td->hw.info)
+	  						: (TD_CC_GET(td_list->prev_td->hw.info) > 0) ? TD_CC_GET(td_list->prev_td->hw.info) : TD_CC_GET(td_list->hw.info),
+						td_list->lw0,
+						td_list->lw1); 
+				OHCI_FREE(td_list->prev_td->prev_td);			
+				OHCI_FREE(td_list->prev_td);
+				OHCI_FREE(td_list);
+					
+			}
+      	} 
+    	
+    }
+    td_list = td_list_next;
+  }  
+  return 0; 
+}
+
+
+
+/******
+ *** HC functions
+ ************************************/
+ 
+
+ 
+void reset_hc(struct ohci *ohci) {
+	int retries = 5;
+	int timeout = 30;
+	int fminterval;
+	
+	if(readl(&ohci->regs->control) & 0x100) { /* SMM owns the HC */
+		writel(0x08,  &ohci->regs->cmdstatus); /* request ownership */
+		printk("USB HC TakeOver from SMM\n");
+		do {
+			wait_ms(100);
+			if(--retries) { 
+				printk("USB HC TakeOver timed out!\n");
+				break;
+			}
+		}
+		while(readl(&ohci->regs->control) & 0x100); 
+	}	
+		
+	writel((1<<31), &ohci->regs->intrdisable); /* Disable HC interrupts */
+	OHCI_DEBUG(printk("USB HC reset_hc: %x ; retries: %d\n", readl(&ohci->regs->control), 5-retries);)
+	fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
+	writel(1,  &ohci->regs->cmdstatus);	   /* HC Reset */
+	while ((readl(&ohci->regs->cmdstatus) & 0x01) != 0) { /* 10us Reset */
+		if (--timeout == 0) {
+			printk("USB HC reset timed out!\n");
+			return;
+		}	
+		udelay(1);
+	}
+	/* set the timing */
+	fminterval |= (((fminterval -210) * 6)/7)<<16; 
+	writel(fminterval, &ohci->regs->fminterval);
+	writel(((fminterval&0x3fff)*9)/10, &ohci->regs->periodicstart);
+}
+
+
+/*
+ * Reset and start an OHCI controller
+ */
+void start_hc(struct ohci *ohci)
+{
+   /*  int fminterval; */
+    unsigned int mask;
+  /*  fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
+	reset_hc(ohci); */
+ 
+
+	writel(virt_to_bus(&ohci->hc_area->hcca), &ohci->regs->hcca); /* a reset clears this */
+ 
+	/* Choose the interrupts we care about now, others later on demand */
+	mask = OHCI_INTR_MIE | OHCI_INTR_WDH;
+	/* | OHCI_INTR_SO | OHCI_INTR_UE |OHCI_INTR_RHSC |OHCI_INTR_SF|  
+		OHCI_INTR_FNO */
+		
+
+	 
+	writel((0x00), &ohci->regs->control); /* USB Reset BUS */
+	wait_ms(10);
+	  
+	writel((0x97), &ohci->regs->control); /* USB Operational  */
+	
+ 	writel( 0x10000, &ohci->regs->roothub.status); /* root hub power on */
+	wait_ms(50); 
+		
+	OHCI_DEBUG(printk("USB HC rstart_hc_operational: %x\n", readl(&ohci->regs->control)); )
+ 	OHCI_DEBUG(printk("USB HC roothubstata: %x \n", readl( &(ohci->regs->roothub.a) )); )
+ 	OHCI_DEBUG(printk("USB HC roothubstatb: %x \n", readl( &(ohci->regs->roothub.b) )); )
+ 	OHCI_DEBUG(printk("USB HC roothubstatu: %x \n", readl( &(ohci->regs->roothub.status) )); )
+ 	OHCI_DEBUG(printk("USB HC roothubstat1: %x \n", readl( &(ohci->regs->roothub.portstatus[0]) )); )
+   	OHCI_DEBUG(printk("USB HC roothubstat2: %x \n", readl( &(ohci->regs->roothub.portstatus[1]) )); )
+  
+	/* control_wakeup = NULL; */
+	writel(mask, &ohci->regs->intrenable);
+	writel(mask, &ohci->regs->intrstatus);
+ 
+#ifdef VROOTHUB
+	{
+
+	struct usb_device * usb_dev;
+	struct ohci_device *dev;
+
+	usb_dev = sohci_usb_allocate(ohci->root_hub->usb);
+	dev = usb_dev->hcpriv; 
+
+	dev->ohci = ohci; 
+
+	usb_connect(usb_dev);
+
+	ohci->root_hub->usb->children[0] = usb_dev;
+
+	usb_new_device(usb_dev);
+	}
+#endif
+
+ 
+	
+}
+
+
+
+
+static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r)
+{
+  struct ohci *ohci = __ohci;
+  struct ohci_regs *regs = ohci->regs;
+ 
+  int ints; 
+
+ 
+ if((ohci->hc_area->hcca.done_head != 0) && !(ohci->hc_area->hcca.done_head & 0x01)) {
+    ints =  OHCI_INTR_WDH;
+  }
+  else { 
+    if((ints = (readl(&regs->intrstatus) & readl(&regs->intrenable))) == 0)
+      return;
+   } 
+   
+  ohci->intrstatus |= ints;
+  OHCI_DEBUG(printk("USB HC interrupt: %x (%x) \n", ints, readl(&ohci->regs->intrstatus));)
+
+  /* ints &= ~(OHCI_INTR_WDH);  WH Bit will be set by done list subroutine */
+ /*  if(ints & OHCI_INTR_FNO) {
+   	writel(OHCI_INTR_FNO,  &regs->intrstatus);
+   	if (waitqueue_active(&ohci_tasks)) wake_up(&ohci_tasks);
+  } */
+  
+  if(ints & OHCI_INTR_WDH) {
+   	writel(OHCI_INTR_WDH,  &regs->intrdisable);	
+   	ohci->intrstatus &= (~OHCI_INTR_WDH);
+	usb_ohci_done_list(ohci); /* prepare out channel list */
+	writel(OHCI_INTR_WDH, &ohci->regs->intrstatus);
+	writel(OHCI_INTR_WDH, &ohci->regs->intrenable);
+   	 
+  }
+  
+  if(ints & OHCI_INTR_SF) {
+  	writel(OHCI_INTR_SF,  &regs->intrdisable);	
+  	writel(OHCI_INTR_SF, &ohci->regs->intrstatus);
+	ohci->intrstatus &= (~OHCI_INTR_SF);
+  	if(ohci->ed_rm_list != NULL) {
+			ohci_rm_eds(ohci);
+ 	 }
+  }
+#ifndef VROOTHUB 
+  if(ints & OHCI_INTR_RHSC) {  
+  	writel(OHCI_INTR_RHSC, &regs->intrdisable);
+  	writel(OHCI_INTR_RHSC, &ohci->regs->intrstatus);
+	wake_up(&root_hub);
+
+  }
+ #endif
+
+  writel(OHCI_INTR_MIE, &regs->intrenable);
+	
+}
+ 
+#ifndef VROOTHUB
+/*
+ * This gets called if the connect status on the root
+ * hub (and the root hub only) changes.
+ */
+static void ohci_connect_change(struct ohci *ohci, unsigned int port_nr)
+{
+	struct usb_device *usb_dev;
+    struct ohci_device *dev;
+	OHCI_DEBUG(printk("uhci_connect_change: called for %d stat %x\n", port_nr,readl(&ohci->regs->roothub.portstatus[port_nr]) );)
+
+	/*
+	 * Even if the status says we're connected,
+	 * the fact that the status bits changed may
+	 * that we got disconnected and then reconnected.
+	 *
+	 * So start off by getting rid of any old devices..
+	 */
+	usb_disconnect(&ohci->root_hub->usb->children[port_nr]);
+
+	 if(!(readl(&ohci->regs->roothub.portstatus[port_nr]) & RH_PS_CCS)) {
+	 	writel(RH_PS_CCS, &ohci->regs->roothub.portstatus[port_nr]);
+		return; /* nothing connected */
+	}
+	/*
+	 * Ok, we got a new connection. Allocate a device to it,
+	 * and find out what it wants to do..
+	 */
+	usb_dev = sohci_usb_allocate(ohci->root_hub->usb);
+	dev = usb_dev->hcpriv; 
+	dev->ohci = ohci; 
+	usb_connect(dev->usb);
+	ohci->root_hub->usb->children[port_nr] = usb_dev;
+	wait_ms(200); /* wait for powerup */
+    /* reset port/device */
+ 	writel(RH_PS_PRS, &ohci->regs->roothub.portstatus[port_nr]); /* reset port */
+ 	while(!(readl( &ohci->regs->roothub.portstatus[port_nr]) & RH_PS_PRSC)) wait_ms(10); /* reset active ? */
+ 	writel(RH_PS_PES, &ohci->regs->roothub.portstatus[port_nr]); /* enable port */
+ 	wait_ms(10);
+	/* Get speed information */
+	usb_dev->slow = (readl( &ohci->regs->roothub.portstatus[port_nr]) & RH_PS_LSDA) ? 1 : 0;
+
+	/*
+	 * Ok, all the stuff specific to the root hub has been done.
+	 * The rest is generic for any new USB attach, regardless of
+	 * hub type.
+	 */
+	usb_new_device(usb_dev);
+}
+#endif
+ 
+
+
+/*
+ * Allocate the resources required for running an OHCI controller.
+ * Host controller interrupts must not be running while calling this
+ * function.
+ *
+ * The mem_base parameter must be the usable -virtual- address of the
+ * host controller's memory mapped I/O registers.
+ *
+ * This is where OHCI triumphs over UHCI, because good is dumb.
+ * Note how much simpler this function is than in uhci.c.
+ *
+ * OHCI hardware takes care of most of the scheduling of different
+ * transfer types with the correct prioritization for us.
+ */
+
+
+static struct ohci *alloc_ohci(void* mem_base)
+{
+	int i,j;
+	struct ohci *ohci;
+	struct ohci_hc_area *hc_area;
+	struct usb_bus *bus;
+	struct ohci_device *dev;
+	struct usb_device *usb;
+
+	/*
+	 * Here we allocate some dummy  EDs as well as the
+	 * OHCI host controller communications area.  The HCCA is just
+	 * a nice pool of memory with pointers to endpoint descriptors
+	 * for the different interrupts.
+	 *
+	 * The first page of memory  contains the HCCA and ohci structure
+	 */
+	hc_area = (struct  ohci_hc_area *) __get_free_pages(GFP_KERNEL, 1);
+	if (!hc_area)
+		return NULL;
+	memset(hc_area, 0, sizeof(*hc_area));
+    ohci = &hc_area->ohci;
+	ohci->irq = -1;
+	ohci->regs = mem_base;
+    
+	ohci->hc_area = hc_area;
+	/* Tell the controller where the HCCA is */
+	writel(virt_to_bus(&hc_area->hcca), &ohci->regs->hcca);
+	
+ 
+	/*
+	 * Initialize the ED polling "tree",  full tree;
+         * dummy eds ed[i] (hc should skip them) 
+         * i == 0 is the end of the iso list;
+		 * 1 is the   1ms node, 
+         * 2,3        2ms nodes,
+         * 4,5,6,7    4ms nodes,
+         * 8  ... 15  8ms nodes,
+         * 16 ... 31  16ms nodes,
+         * 32 ... 63  32ms nodes
+         * Sequenzes:
+		 * 32-16- 8-4-2-1-0
+         * 33-17- 9-5-3-1-0
+         * 34-18-10-6-2-1-0
+         * 35-19-11-7-3-1-0
+         * 36-20-12-4-2-1-0
+         * 37-21-13-5-3-1-0
+         * 38-22-14-6-2-1-0
+         * 39-23-15-7-3-1-0
+         * 40-24- 8-4-2-1-0
+         * 41-25- 9-5-3-1-0
+         * 42-26-10-6-2-1-0
+         *     :      :
+         * 63-31-15-7-3-1-0
+	 */
+        hc_area->ed[ED_ISO].info |=  OHCI_ED_SKIP; /* place holder, so skip it */
+        hc_area->ed[ED_ISO].next_ed =  0x0000;       /* end of iso list */
+
+        hc_area->ed[1].next_ed = virt_to_bus(&(hc_area->ed[ED_ISO]));
+        hc_area->ed[1].info |=  OHCI_ED_SKIP; /* place holder, skip it */
+	     
+        j=1;
+        for (i = 2; i < (NUM_INTS * 2); i++) {
+          	if (i >= NUM_INTS) 
+	   		 	hc_area->hcca.int_table[i - NUM_INTS] = virt_to_bus(&(hc_area->ed[i]));
+           
+          	if( i == j*4) j *= 2;
+	    	hc_area->ed[i].next_ed = virt_to_bus(&(hc_area->ed[j+ i%j]));
+            hc_area->ed[i].info |=  OHCI_ED_SKIP; /* place holder, skip it */
+        }
+
+
+	/*
+	 * for load ballancing of the interrupt branches 
+	 */
+	for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;
+
+	/*
+	 * Store the end of control and bulk list eds. So, we know where we can add
+	 * elements to these lists.
+	 */
+	ohci->ed_isotail     = (struct usb_ohci_ed *) &(hc_area->ed[ED_ISO]);
+        ohci->ed_controltail = NULL;
+        ohci->ed_bulktail    = NULL;
+	
+	/*
+	 * Tell the controller where the control and bulk lists are
+	 * The lists are empty now.
+	 */	
+	writel(0, &ohci->regs->ed_controlhead);
+	writel(0, &ohci->regs->ed_bulkhead);
+
+	
+	USB_ALLOC(bus, sizeof(*bus));
+	if (!bus)
+		return NULL;
+
+	memset(bus, 0, sizeof(*bus));
+
+	ohci->bus = bus;
+	bus->hcpriv = (void *) ohci;
+	bus->op = &sohci_device_operations;
+
+	 
+	usb = sohci_usb_allocate(NULL);
+	if (!usb)
+		return NULL;
+
+	dev = ohci->root_hub = usb_to_ohci(usb);
+
+	usb->bus = bus;
+	/* bus->root_hub = ohci_to_usb(ohci->root_hub); */
+	dev->ohci = ohci;
+	
+	/* Initialize the root hub */
+	 
+	usb->maxchild = readl(&ohci->regs->roothub.a) & 0xff;
+	usb_init_root_hub(usb);
+
+	return ohci;
+} 
+
+
+/*
+ * De-allocate all resources..
+ */
+
+static void release_ohci(struct ohci *ohci)
+{
+	int i;
+	union ep_addr_ ep_addr;
+	ep_addr.iep = 0;
+	
+    OHCI_DEBUG(printk("USB HC release ohci \n");)
+    
+	if (ohci->irq >= 0) {
+		free_irq(ohci->irq, ohci);
+		ohci->irq = -1;
+	}
+
+    /* stop hc */
+	writel(OHCI_USB_SUSPEND, &ohci->regs->control);
+		
+	/* deallocate all EDs and TDs */
+	for(i=0; i < 128; i ++) {
+		ep_addr.bep.fa = i;
+		usb_ohci_rm_function(ohci, ep_addr.iep);
+	}
+	ohci_rm_eds(ohci); /* remove eds */
+	
+    /* disconnect all devices */    
+	if(ohci->root_hub)
+		for(i = 0; i < ohci->root_hub->usb->maxchild; i++)
+			  usb_disconnect(ohci->root_hub->usb->children + i);
+	    
+    USB_FREE(ohci->root_hub->usb);
+    USB_FREE(ohci->root_hub);
+    USB_FREE(ohci->bus);
+    
+	/* unmap the IO address space */
+	iounmap(ohci->regs);
+       
+	
+	free_pages((unsigned int) ohci->hc_area, 1);
+	
+}
+
+ 
+void cleanup_drivers(void);
+
+static int ohci_roothub_thread(void * __ohci)
+{
+        struct ohci *ohci = (struct ohci *)__ohci;
+        lock_kernel(); 
+
+        /*
+         * This thread doesn't need any user-level access,
+         * so get rid of all our resources..
+         */
+        printk("ohci_roothub_thread at %p\n", &ohci_roothub_thread);
+        exit_mm(current);
+        exit_files(current);
+        exit_fs(current);
+
+
+        strcpy(current->comm, "root-hub");
+
+         
+		start_hc(ohci);
+		writel( 0x10000, &ohci->regs->roothub.status);
+		wait_ms(50); /* root hub power on */
+         do {
+#ifdef CONFIG_APM
+		if (apm_resume) {
+			apm_resume = 0;
+			start_hc(ohci);
+			continue;
+		}
+#endif
+ 	 
+         OHCI_DEBUG(printk("USB RH tasks: int: %x\n", ohci->intrstatus); )
+#ifndef VROOTHUB
+		/*	if (ohci->intrstatus & OHCI_INTR_RHSC)  */
+			{
+				int port_nr;
+	     		for(port_nr=0; port_nr< ohci->root_hub->usb->maxchild; port_nr++)
+	     			if(readl(&ohci->regs->roothub.portstatus[port_nr]) & (RH_PS_CSC | RH_PS_PRSC)) {		
+	     		 		ohci_connect_change(ohci, port_nr);
+	     		 		writel(0xffff0000, &ohci->regs->roothub.portstatus[port_nr]);
+	     		 	}
+	     		 ohci->intrstatus &= ~(OHCI_INTR_RHSC);
+	     		 writel(OHCI_INTR_RHSC, &ohci->regs->intrenable);
+	    	}
+#endif
+ 
+         interruptible_sleep_on(&root_hub);
+ 
+      	} while (!signal_pending(current)); 
+             	
+#ifdef VROOTHUB
+		ohci_del_rh_int_timer(ohci);
+#endif
+ 
+
+		cleanup_drivers();
+      /*  reset_hc(ohci); */
+	 
+        release_ohci(ohci);
+        MOD_DEC_USE_COUNT;
+
+	    printk("ohci_control_thread exiting\n");
+
+        return 0;
+}
+
+
+ 
+
+/*
+ * Increment the module usage count, start the control thread and
+ * return success.
+ */
+static int found_ohci(int irq, void* mem_base)
+{
+	int retval;
+	struct ohci *ohci;
+    OHCI_DEBUG(printk("USB HC found  ohci: irq= %d membase= %x \n", irq, (int)mem_base);)
+	/* Allocate the running OHCI structures */
+	ohci = alloc_ohci(mem_base);
+	if (!ohci) {
+	  return -ENOMEM;
+	}
+
+	reset_hc(ohci);
+
+	retval = -EBUSY;
+	if (request_irq(irq, ohci_interrupt, SA_SHIRQ, "ohci-usb", ohci) == 0) {
+		int pid;
+
+		MOD_INC_USE_COUNT; 
+		ohci->irq = irq;
+		 
+		pid = kernel_thread(ohci_roothub_thread, ohci, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+		if (pid >= 0) 
+		 	return 0;
+		
+
+		MOD_DEC_USE_COUNT;
+		retval = pid;
+	}
+	
+	release_ohci(ohci);
+	return retval;
+}
+ 
+static int start_ohci(struct pci_dev *dev)
+{
+	unsigned int mem_base = dev->base_address[0];
+
+	/* If its OHCI, its memory */
+	if (mem_base & PCI_BASE_ADDRESS_SPACE_IO)
+		return -ENODEV;
+
+	/* Get the memory address and map it for IO */
+	mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
+
+	/* 
+	 * FIXME ioremap_nocache isn't implemented on all CPUs (such
+	 * as the Alpha) [?]  What should I use instead...
+	 *
+	 * The iounmap() is done on in release_ohci.
+	 */
+	mem_base = (unsigned int) ioremap_nocache(mem_base, 4096);
+
+	if (!mem_base) {
+		printk("Error mapping OHCI memory\n");
+		return -EFAULT;
+	}
+
+	return found_ohci(dev->irq, (void *) mem_base);
+} 
+
+
+
+#ifdef CONFIG_APM
+static int handle_apm_event(apm_event_t event)
+{
+	static int down = 0;
+
+	switch (event) {
+	case APM_SYS_SUSPEND:
+	case APM_USER_SUSPEND:
+		if (down) {
+			printk(KERN_DEBUG "ohci: received extra suspend event\n");
+			break;
+		}
+		down = 1;
+		break;
+	case APM_NORMAL_RESUME:
+	case APM_CRITICAL_RESUME:
+		if (!down) {
+			printk(KERN_DEBUG "ohci: received bogus resume event\n");
+			break;
+		}
+		down = 0;
+		if (waitqueue_active(&root_hub)) {
+			apm_resume = 1;
+			wake_up(&root_hub);
+		}
+		break;
+	}
+	return 0;
+}
+#endif
+
+
+ int usb_mouse_init(void); 
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+#ifdef CONFIG_APM
+	apm_unregister_callback(&handle_apm_event);
+#endif
+}
+
+#define ohci_hcd_init init_module
+
+#endif
+
+#define PCI_CLASS_SERIAL_USB_OHCI 0x0C0310
+#define PCI_CLASS_SERIAL_USB_OHCI_PG 0x10
+ 
+
+int ohci_hcd_init(void)
+{
+  int retval;
+  struct pci_dev *dev = NULL;
+ 
+  retval = -ENODEV;
+   
+  dev = NULL;
+  while((dev = pci_find_class(PCI_CLASS_SERIAL_USB_OHCI, dev))) { /* OHCI */
+    retval = start_ohci(dev);
+    if (retval < 0) break;
+
+    
+#ifdef CONFIG_USB_MOUSE
+		usb_mouse_init();
+#endif
+#ifdef CONFIG_USB_KBD		
+		usb_kbd_init();
+#endif		
+		hub_init();
+#ifdef CONFIG_USB_AUDIO		
+		usb_audio_init();
+#endif		
+#ifdef CONFIG_APM
+		apm_register_callback(&handle_apm_event);
+#endif
+  
+    return 0;
+  }
+  return retval;
+}
+
+void cleanup_drivers(void)
+{
+	 hub_cleanup(); 
+#ifdef CONFIG_USB_MOUSE
+	 usb_mouse_cleanup();
+#endif
+}
+
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/ohci-hcd.h linux/drivers/usb/ohci-hcd.h
--- v2.2.7/linux/drivers/usb/ohci-hcd.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/ohci-hcd.h	Mon May 10 10:18:34 1999
@@ -0,0 +1,402 @@
+ /*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ *
+ * The OHCI HCD layer is a simple but nearly complete implementation of what the
+ * USB people would call a HCD  for the OHCI. 
+ * (ISO comming soon, Bulk disabled, INT u. CTRL transfers enabled)
+ * The layer on top of it, is for interfacing to the alternate-usb device-drivers.
+ * 
+ * [ This is based on Linus' UHCI code and gregs OHCI fragments (0.03c source tree). ]
+ * [ Open Host Controller Interface driver for USB. ]
+ * [ (C) Copyright 1999 Linus Torvalds (uhci.c) ]
+ * [ (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com> ]
+ * [ $Log: ohci.c,v $ ]
+ * [ Revision 1.1  1999/04/05 08:32:30  greg ]
+ * 
+ * 
+ * v2.1 1999/05/09 ep_addr correction, code clean up
+ * v2.0 1999/05/04 
+ * v1.0 1999/04/27
+ * ohci-hcd.h
+ */
+
+#ifdef CONFIG_USB_OHCI_VROOTHUB
+#define VROOTHUB  
+#endif
+/* enables virtual root hub 
+ * (root hub will be managed by the hub controller 
+ *  hub.c of the alternate usb driver)
+ *  last time I did more testing without virtual root hub 
+ *  -> the virtual root hub could be more unstable now */
+ 
+ 
+  
+#ifdef OHCI_DBG
+#define OHCI_DEBUG(X) X
+#else 
+#define OHCI_DEBUG(X)
+#endif 
+
+/* for readl writel functions */
+#include <linux/list.h>
+#include <asm/io.h>
+
+/* for ED and TD structures */
+
+typedef void * __OHCI_BAG;
+typedef int (*f_handler )(void * ohci, unsigned int ep_addr, int cmd_len, void *cmd, void *data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw1);
+
+
+
+struct ep_address {
+  __u8 ep;  /* bit 7: IN/-OUT, 6,5: type 10..CTRL 00..ISO  11..BULK 10..INT, 3..0: ep nr */ 
+  __u8 fa;    /* function address */
+  __u8 hc;
+  __u8 host;
+};
+
+union ep_addr_ {
+  unsigned int iep;
+  struct ep_address bep;
+};
+
+/*
+ * ED and TD descriptors has to be 16-byte aligned
+ */
+struct ohci_hw_ed {
+  __u32 info;       
+  __u32 tail_td;	/* TD Queue tail pointer */
+  __u32 head_td;	/* TD Queue head pointer */
+  __u32 next_ed;	/* Next ED */
+} __attribute((aligned(16)));
+
+
+struct usb_ohci_ed {
+  struct ohci_hw_ed hw;
+  /*  struct ohci * ohci; */
+  f_handler handler;
+  union ep_addr_ ep_addr;
+  struct usb_ohci_ed *ed_list;
+  struct usb_ohci_ed *ed_prev;
+} __attribute((aligned(32)));
+
+ /* OHCI Hardware fields */
+struct ohci_hw_td {     
+  __u32 info;
+  __u32 cur_buf;		/* Current Buffer Pointer */
+  __u32 next_td;		/* Next TD Pointer */
+  __u32 buf_end;		/* Memory Buffer End Pointer */
+} __attribute((aligned(16)));
+
+/* TD info field */
+#define TD_CC       0xf0000000
+#define TD_CC_GET(td_p) ((td_p >>28) & 0x04)
+#define TD_EC       0x0C000000
+#define TD_T        0x03000000
+#define TD_T_DATA0  0x02000000
+#define TD_T_DATA1  0x03000000
+#define TD_T_TOGGLE 0x00000000
+#define TD_R        0x00040000
+#define TD_DI       0x00E00000
+#define TD_DI_SET(X) (((X) & 0x07)<< 21)
+#define TD_DP       0x00180000
+#define TD_DP_SETUP 0x00000000
+#define TD_DP_IN    0x00100000
+#define TD_DP_OUT   0x00080000
+
+/* CC Codes */
+#define TD_CC_NOERROR      0x00
+#define TD_CC_CRC          0x01
+#define TD_CC_BITSTUFFING  0x02
+#define TD_CC_DATATOGGLEM  0x03
+#define TD_CC_STALL        0x04
+#define TD_DEVNOTRESP      0x05
+#define TD_PIDCHECKFAIL    0x06
+#define TD_UNEXPECTEDPID   0x07
+#define TD_DATAOVERRUN     0x08
+#define TD_DATAUNDERRUN    0x09
+#define TD_BUFFEROVERRUN   0x0C
+#define TD_BUFFERUNDERRUN  0x0D
+#define TD_NOTACCESSED     0x0F
+
+
+
+struct usb_ohci_td {
+  struct ohci_hw_td hw;
+  void *  buffer_start;
+  f_handler handler; 
+  struct usb_ohci_td *prev_td;
+  struct usb_ohci_ed *ep;
+  struct usb_ohci_td *next_dl_td;
+  __OHCI_BAG lw0;
+  __OHCI_BAG lw1;
+} __attribute((aligned(32)));
+
+
+
+/* TD types */
+#define BULK		0x03
+#define INT			0x01
+#define CTRL		0x02
+#define ISO			0x00
+/* TD types with direction */
+#define BULK_IN		0x07
+#define BULK_OUT	0x03
+#define INT_IN		0x05
+#define INT_OUT		0x01
+#define CTRL_IN		0x06
+#define CTRL_OUT	0x02
+#define ISO_IN		0x04
+#define ISO_OUT		0x00
+
+struct ohci_rep_td {
+  int cmd_len;
+  void * cmd;
+  void * data;
+  int data_len;
+  f_handler handler;
+  struct ohci_rep_td *next_td;
+  int ep_addr;
+  __OHCI_BAG lw0;
+  __OHCI_BAG lw1;
+  __u32 status;
+} __attribute((aligned(32))); 
+
+#define OHCI_ED_SKIP	(1 << 14)
+#define OHCI_ED_MPS	(0x7ff << 16)
+#define OHCI_ED_F_NORM	(0)
+#define OHCI_ED_F_ISOC	(1 << 15)
+#define OHCI_ED_S_LOW	(1 << 13)
+#define OHCI_ED_S_HIGH	(0)
+#define OHCI_ED_D	(3 << 11)
+#define OHCI_ED_D_IN	(2 << 11)
+#define OHCI_ED_D_OUT	(1 << 11)
+#define OHCI_ED_EN	(0xf << 7)
+#define OHCI_ED_FA	(0x7f)
+
+ 
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of.  It must be 256-byte aligned.
+ */
+#define NUM_INTS 32	/* part of the OHCI standard */
+struct ohci_hcca {
+    __u32	int_table[NUM_INTS];	/* Interrupt ED table */
+	__u16	frame_no;		/* current frame number */
+	__u16	pad1;			/* set to 0 on each frame_no change */
+	__u32	done_head;		/* info returned for an interrupt */
+	u8		reserved_for_hc[116];
+} __attribute((aligned(256)));
+
+  
+
+#define ED_INT_1	1
+#define ED_INT_2	2
+#define ED_INT_4	4
+#define ED_INT_8	8
+#define ED_INT_16	16
+#define ED_INT_32	32
+#define ED_CONTROL	64
+#define ED_BULK		65
+#define ED_ISO		0	/* same as 1ms interrupt queue */
+ 
+
+/*
+ * This is the maximum number of root hub ports.  I don't think we'll
+ * ever see more than two as that's the space available on an ATX
+ * motherboard's case, but it could happen.  The OHCI spec allows for
+ * up to 15... (which is insane!)
+ * 
+ * Although I suppose several "ports" could be connected directly to
+ * internal laptop devices such as a keyboard, mouse, camera and
+ * serial/parallel ports.  hmm...  That'd be neat.
+ */
+#define MAX_ROOT_PORTS	15	/* maximum OHCI root hub ports */
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region.  This is Memory Mapped I/O.  You must use the readl() and
+ * writel() macros defined in asm/io.h to access these!!
+ */
+struct ohci_regs {
+	/* control and status registers */
+	__u32	revision;
+	__u32	control;
+	__u32	cmdstatus;
+	__u32	intrstatus;
+	__u32	intrenable;
+	__u32	intrdisable;
+	/* memory pointers */
+	__u32	hcca;
+	__u32	ed_periodcurrent;
+	__u32	ed_controlhead;
+	__u32	ed_controlcurrent;
+	__u32	ed_bulkhead;
+	__u32	ed_bulkcurrent;
+	__u32	donehead;
+	/* frame counters */
+	__u32	fminterval;
+	__u32	fmremaining;
+	__u32	fmnumber;
+	__u32	periodicstart;
+	__u32	lsthresh;
+	/* Root hub ports */
+	struct	ohci_roothub_regs {
+		__u32	a;
+		__u32	b;
+		__u32	status;
+		__u32	portstatus[MAX_ROOT_PORTS];
+	} roothub;
+} __attribute((aligned(32)));
+
+
+/* 
+ * Read a MMIO register and re-write it after ANDing with (m)
+ */
+#define writel_mask(m, a) writel( (readl((__u32)(a))) & (__u32)(m), (__u32)(a) )
+
+/*
+ * Read a MMIO register and re-write it after ORing with (b)
+ */
+#define writel_set(b, a) writel( (readl((__u32)(a))) | (__u32)(b), (__u32)(a) )
+
+/*
+ * cmdstatus register */
+#define OHCI_CLF  0x02
+#define OHCI_BLF  0x04
+
+/*
+ * Interrupt register masks
+ */
+#define OHCI_INTR_SO	(1)
+#define OHCI_INTR_WDH	(1 << 1)
+#define OHCI_INTR_SF	(1 << 2)
+#define OHCI_INTR_RD	(1 << 3)
+#define OHCI_INTR_UE	(1 << 4)
+#define OHCI_INTR_FNO	(1 << 5)
+#define OHCI_INTR_RHSC	(1 << 6)
+#define OHCI_INTR_OC	(1 << 30)
+#define OHCI_INTR_MIE	(1 << 31)
+
+/*
+ * Control register masks
+ */
+#define OHCI_USB_OPER		(2 << 6)
+#define OHCI_USB_SUSPEND	(3 << 6)
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+
+
+struct ohci {
+    	int irq;
+	    struct ohci_regs *regs;					/* OHCI controller's memory */	
+	    struct ohci_hc_area *hc_area;			/* hcca, int ed-tree, ohci itself .. */                
+        int root_hub_funct_addr;                /* Address of Root Hub endpoint */       
+        int ohci_int_load[32];                       /* load of the 32 Interrupt Chains (for load ballancing)*/     
+        struct usb_ohci_ed * ed_rm_list;        /* list of all endpoints to be removed */
+        struct usb_ohci_ed * ed_bulktail;       /* last endpoint of bulk list */
+        struct usb_ohci_ed * ed_controltail;    /* last endpoint of control list */
+        struct usb_ohci_ed * ed_isotail;        /* last endpoint of iso list */
+        struct ohci_device * root_hub;
+        struct usb_ohci_ed ed_rh_ep0;
+        struct usb_ohci_ed ed_rh_epi;
+        struct ohci_rep_td *td_rh_epi;
+        int intrstatus;
+        struct usb_ohci_ed *ed_func_ep0[128];   /* "hash"-table for ep to ed mapping */
+        struct ohci_rep_td *repl_queue;			/* for internal requests */
+        int rh_int_interval;
+        int rh_int_timer;   
+        struct usb_bus *bus;
+       
+       
+};
+
+/*
+ *  Warning: This constant must not be so large as to cause the
+ *  ohci_device structure to exceed one 4096 byte page.  Or "weird
+ *  things will happen" as the alloc_ohci() function assumes that
+ *  its less than one page at the moment.  (FIXME)
+ */
+#define NUM_TDS	4		/* num of preallocated transfer descriptors */
+#define NUM_EDS 80		/* num of preallocated endpoint descriptors */
+
+struct ohci_hc_area {
+
+	struct ohci_hcca 	hcca;		/* OHCI mem. mapped IO area 256 Bytes*/
+
+	struct ohci_hw_ed		ed[NUM_EDS];	/* Endpoint Descriptors 80 * 16  : 1280 Bytes */
+	struct ohci_hw_td		td[NUM_TDS];	/* Transfer Descriptors 2 * 32   : 64 Bytes */
+        struct ohci             ohci;
+        
+};
+struct ohci_device {
+	struct usb_device	*usb;
+	struct ohci			*ohci;
+	unsigned long		data[16];
+};
+
+#define ohci_to_usb(uhci)	((ohci)->usb)
+#define usb_to_ohci(usb)	((struct ohci_device *)(usb)->hcpriv)
+
+/* Debugging code */
+/*void show_ed(struct ohci_ed *ed);
+void show_td(struct ohci_td *td);
+void show_status(struct ohci *ohci); */
+
+/* hcd */
+int ohci_trans_req(struct ohci * ohci, unsigned int ep_addr, int cmd_len, void  *cmd, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1); 
+struct usb_ohci_ed *usb_ohci_add_ep(struct ohci * ohci, unsigned int ep_addr, int interval, int load, f_handler handler, int ep_size, int speed);
+int usb_ohci_rm_function(struct ohci * ohci, unsigned int ep_addr); 
+int usb_ohci_rm_ep(struct ohci * ohci, struct  usb_ohci_ed *ed);
+struct usb_ohci_ed * ohci_find_ep(struct ohci *ohci, unsigned int ep_addr_in);
+
+/* roothub */
+int ohci_del_rh_int_timer(struct ohci * ohci);
+int	ohci_init_rh_int_timer(struct ohci * ohci, int interval);  	
+int root_hub_int_req(struct ohci * ohci, int cmd_len, void * ctrl, void *  data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler);
+int root_hub_send_irq(struct ohci * ohci, void * data, int data_len );
+int root_hub_control_msg(struct ohci *ohci, int cmd_len, void *rh_cmd, void *rh_data, int len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler);
+int queue_reply(struct ohci * ohci, unsigned int ep_addr, int cmd_len,void * cmd, void * data,int  len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler);
+int send_replies(struct ohci * ohci);
+
+  
+ 
+
+/* Root-Hub Register info */
+
+#define RH_PS_CCS            0x00000001   
+#define RH_PS_PES            0x00000002   
+#define RH_PS_PSS            0x00000004   
+#define RH_PS_POCI           0x00000008   
+#define RH_PS_PRS            0x00000010  
+#define RH_PS_PPS            0x00000100   
+#define RH_PS_LSDA           0x00000200    
+#define RH_PS_CSC            0x00010000 
+#define RH_PS_PESC           0x00020000   
+#define RH_PS_PSSC           0x00040000    
+#define RH_PS_OCIC           0x00080000    
+#define RH_PS_PRSC           0x00100000   
+
+
+#ifdef OHCI_DBG
+#define OHCI_FREE(x) kfree(x); printk("OHCI FREE: %d\n", -- __ohci_free_cnt)
+#define OHCI_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL); printk("OHCI ALLO: %d\n", ++ __ohci_free_cnt)
+#define USB_FREE(x) kfree(x); printk("USB FREE: %d\n", -- __ohci_free1_cnt)
+#define USB_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL); printk("USB ALLO: %d\n", ++ __ohci_free1_cnt)
+static int __ohci_free_cnt = 0;
+static int __ohci_free1_cnt = 0;
+#else
+#define OHCI_FREE(x) kfree(x) 
+#define OHCI_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL) 
+#define USB_FREE(x) kfree(x) 
+#define USB_ALLOC(x,size) (x) = kmalloc(size, GFP_KERNEL) 
+#endif
+ 
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/ohci-root-hub.c linux/drivers/usb/ohci-root-hub.c
--- v2.2.7/linux/drivers/usb/ohci-root-hub.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/ohci-root-hub.c	Mon May 10 10:18:34 1999
@@ -0,0 +1,604 @@
+/*
+ * HCD (OHCI) Virtual Root Hub for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber (weissg@vienna.at)
+ *
+ * The Root Hub is build into the HC (UHCI or OHCI) hardware. 
+ * This piece of code lets it look like it resides on the usb
+ * like the other hubs.
+ * (for anyone who wants to do a control operation on the root hub)
+ *  
+ * v2.1 1999/05/09 
+ * v2.0 1999/05/04
+ * v1.0 1999/04/27
+ * ohci-root-hub.c
+ *  
+ */
+ 
+
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+
+#include "usb.h"
+#include "ohci-hcd.h" 
+
+#ifdef VROOTHUB 
+
+#include "ohci-root-hub.h"
+
+
+static __u8 root_hub_dev_des[] =
+{
+        0x12,       /*  __u8  bLength; */
+		0x01,       /*  __u8  bDescriptorType; Device */
+		0x00,	    /*  __u16 bcdUSB; v1.0 */
+        0x01,
+		0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
+		0x00,	    /*  __u8  bDeviceSubClass; */
+		0x00,       /*  __u8  bDeviceProtocol; */
+		0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
+		0x00,       /*  __u16 idVendor; */
+        0x00,
+		0x00,       /*  __u16 idProduct; */
+        0x00,
+		0x00,       /*  __u16 bcdDevice; */
+        0x00,
+		0x00,       /*  __u8  iManufacturer; */
+		0x00,       /*  __u8  iProduct; */
+		0x00,       /*  __u8  iSerialNumber; */
+        0x01        /*  __u8  bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+		0x09,       /*  __u8  bLength; */
+		0x02,       /*  __u8  bDescriptorType; Configuration */
+		0x19,       /*  __u16 wTotalLength; */
+        0x00,
+		0x01,       /*  __u8  bNumInterfaces; */
+		0x01,       /*  __u8  bConfigurationValue; */
+		0x00,       /*  __u8  iConfiguration; */
+		0x40,       /*  __u8  bmAttributes; 
+                 Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
+		0x00,       /*  __u8  MaxPower; */
+      
+     /* interface */	  
+        0x09,       /*  __u8  if_bLength; */
+        0x04,       /*  __u8  if_bDescriptorType; Interface */
+        0x00,       /*  __u8  if_bInterfaceNumber; */
+        0x00,       /*  __u8  if_bAlternateSetting; */
+        0x01,       /*  __u8  if_bNumEndpoints; */
+        0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+        0x00,       /*  __u8  if_bInterfaceSubClass; */
+        0x00,       /*  __u8  if_bInterfaceProtocol; */
+        0x00,       /*  __u8  if_iInterface; */
+     
+     /* endpoint */
+        0x07,       /*  __u8  ep_bLength; */
+        0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
+        0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+        0x03,       /*  __u8  ep_bmAttributes; Interrupt */
+        0x40,       /*  __u16 ep_wMaxPacketSize; 64 Bytes */
+        0x00,
+        0xff        /*  __u8  ep_bInterval; 255 ms */
+};
+
+/* 
+For OHCI we need just the  2nd Byte, so we 
+don't need this constant byte-array 
+
+static __u8 root_hub_hub_des[] =
+{ 
+        0x00,       *  __u8  bLength; *
+		0x29,       *  __u8  bDescriptorType; Hub-descriptor *
+        0x02,       *  __u8  bNbrPorts; *
+        0x00,       * __u16  wHubCharacteristics; *
+        0x00,
+        0x01,       *  __u8  bPwrOn2pwrGood; 2ms * 
+        0x00,       *  __u8  bHubContrCurrent; 0 mA *
+        0x00,       *  __u8  DeviceRemovable; *** 8 Ports max *** *
+        0xff        *  __u8  PortPwrCtrlMask; *** 8 ports max *** *
+};
+*/
+
+
+int root_hub_control_msg(struct ohci *ohci, int cmd_len, void *rh_cmd, void *rh_data, int leni, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler)
+{ 
+
+  __u32 stat;
+  __u32 rep_handler;
+  int req_reply=0;
+  union ep_addr_ ep_addr;
+  union ep_addr_ ep_addr_ret;
+        __u8 * cmd = rh_cmd;
+	__u8 * data = rh_data;
+	int i;
+	int len =leni;
+
+        __u8  bmRequestType = cmd[0];
+        __u8  bRequest      = cmd[1];
+        __u16 wValue        = cmd[3] << 8 | cmd [2];
+        __u16 wIndex        = cmd[5] << 8 | cmd [4];
+        __u16 wLength       = cmd[7] << 8 | cmd [6];
+printk("USB root hub: adr: %8x cmd(%8x): ", ohci->root_hub_funct_addr, 8);
+for(i=0;i<8;i++)
+	printk("%2x", ((char *)rh_cmd)[i]);
+ 
+printk(" ; \n");
+
+	ep_addr_ret.iep = 0;
+	ep_addr_ret.bep.fa = ohci->root_hub_funct_addr;
+	ep_addr_ret.bep.ep =  (bmRequestType & 0x80) | 0x40;
+
+  switch (bmRequestType | bRequest << 8) {
+   /* Request Destination:
+      without flags: Device, 
+      RH_INTERFACE: interface, 
+      RH_ENDPOINT: endpoint,
+      RH_CLASS means HUB here, 
+      RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
+   */
+  
+   case RH_GET_STATUS:
+     len = 2; 
+     data[0] = 0x01;
+     data[1] = 0x00;
+     req_reply = RH_ACK; 
+     break;
+   case RH_GET_STATUS | RH_INTERFACE:
+     len = 2; 
+     data[0] = 0x00;
+     data[1] = 0x00;     
+     req_reply = RH_ACK;
+     break;
+   case RH_GET_STATUS | RH_ENDPOINT:
+     len = 2; 
+     data[0] = 0x00;
+     data[1] = 0x00;     
+     req_reply = RH_ACK;
+     break;
+   case RH_GET_STATUS | RH_CLASS: /* HUB_STATUS */
+     stat = readl(&ohci->regs->roothub.status) & 0x7fff7fff; /* bit 31 u. 15 has other meaning */ 
+     data[0] = stat & 0xff;
+     data[1] = (stat >> 8) & 0xff;
+     data[2] = (stat >> 16) & 0xff;
+     data[3] = (stat >> 24) & 0xff;
+     len = 4;
+     req_reply = RH_ACK; 
+     break;
+   case RH_GET_STATUS | RH_OTHER | RH_CLASS: /* PORT_STATUS */
+     stat = readl(&ohci->regs->roothub.portstatus[wIndex-1]);
+     data[0] = stat & 0xff;
+     data[1] = (stat >> 8) & 0xff;
+     data[2] = (stat >> 16) & 0xff;
+     data[3] = (stat >> 24) & 0xff;
+     len = 4;
+     req_reply = RH_ACK; 
+     printk("rh: stat %4x wIndex %4x;\n", stat , wIndex);
+     break;
+
+   case RH_CLEAR_FEATURE:
+     switch (wValue) {
+       case (RH_DEVICE_REMOTE_WAKEUP):
+       default:
+     }
+     break;
+
+   case RH_CLEAR_FEATURE | RH_ENDPOINT:  
+     switch (wValue) {
+       case (RH_ENDPOINT_STALL): 
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       default:
+     }
+     break;
+
+   case RH_CLEAR_FEATURE | RH_CLASS:
+     switch (wValue) {
+       /*     case (RH_C_HUB_LOCAL_POWER):  OHCI says: no switching of this one */
+       case (RH_C_HUB_OVER_CURRENT):
+         writel(RH_PS_OCIC, &ohci->regs->roothub.status);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       default:
+     }
+     break;
+   case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+     switch (wValue) {
+       case (RH_PORT_ENABLE):
+	     writel(RH_PS_CCS, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_PORT_SUSPEND):
+         writel(RH_PS_POCI, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_PORT_POWER):
+         writel(RH_PS_LSDA, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_C_PORT_CONNECTION):
+         writel(RH_PS_CSC, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_C_PORT_ENABLE):
+         writel(RH_PS_PESC, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_C_PORT_SUSPEND):
+         writel(RH_PS_PSSC, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_C_PORT_OVER_CURRENT):
+         writel(RH_PS_OCIC, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_C_PORT_RESET):
+         writel(RH_PS_PRSC, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       /*
+       case (RH_PORT_CONNECTION):
+       case (RH_PORT_OVER_CURRENT):
+       case (RH_PORT_RESET):
+       case (RH_PORT_LOW_SPEED):
+       */
+       default:
+     }
+     break;
+   case RH_SET_FEATURE:  
+     switch (wValue) {
+       case (RH_DEVICE_REMOTE_WAKEUP):
+       default:
+     }
+     break;
+
+   case RH_SET_FEATURE | RH_ENDPOINT:
+     switch (wValue) {
+       case (RH_ENDPOINT_STALL):
+       default:
+     }
+     break;
+
+   case RH_SET_FEATURE | RH_CLASS: 
+     switch (wValue) {
+       /* case (RH_C_HUB_LOCAL_POWER): Root Hub has no local Power 
+       case (RH_C_HUB_OVER_CURRENT): */
+      default:
+     }
+     break;
+   case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+     switch (wValue) {
+       case (RH_PORT_SUSPEND):
+         writel(RH_PS_PSS, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_PORT_RESET):
+         if((readl(&ohci->regs->roothub.portstatus[wIndex-1]) &1) != 0)  /* BUG IN HUP CODE *********/
+         writel(RH_PS_PRS, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_PORT_POWER):
+         writel(RH_PS_PPS, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       case (RH_PORT_ENABLE):
+         writel(RH_PS_PES, &ohci->regs->roothub.portstatus[wIndex-1]);
+         len=0;
+         req_reply = RH_ACK;
+         break;
+       /*
+       case (RH_PORT_CONNECTION):
+       case (RH_PORT_OVER_CURRENT):
+       case (RH_PORT_LOW_SPEED):
+       case (RH_C_PORT_CONNECTION):
+       case (RH_C_PORT_ENABLE):
+       case (RH_C_PORT_SUSPEND):
+       case (RH_C_PORT_OVER_CURRENT):
+       case (RH_C_PORT_RESET):
+       */
+       default:  
+     }
+     break;
+
+  case RH_SET_ADDRESS:
+     ohci->root_hub_funct_addr = wValue; 
+	/* ohci->ed_func_ep0[wValue] = &ohci->ed_rh_ep0;
+	 ohci->ed_func_ep0[wValue]->ep_addr.bep.fa = wValue; 
+	 ohci->ed_func_ep0[wValue]->ed_list = &ohci->ed_rh_epi; */
+	 ohci->ed_rh_epi.ed_list = NULL;
+	 ohci->ed_rh_epi.ep_addr.bep.fa = wValue;
+	 ohci->ed_rh_epi.ep_addr.bep.ep = 0xa1; /* Int in port 1 */
+     ohci->ed_func_ep0[0]= NULL;
+     len = 0;
+     req_reply = RH_ACK;
+     break;
+
+   case RH_GET_DESCRIPTOR:
+     switch ((wValue & 0xff00) >> 8) {
+     case (0x01): /* device descriptor */
+       len = min(sizeof(root_hub_dev_des), wLength);
+       memcpy(data, root_hub_dev_des, len);
+       req_reply = RH_ACK;
+       break;
+     case (0x02): /* configuration descriptor */
+       len = min(sizeof(root_hub_config_des), wLength);
+       memcpy(data, root_hub_config_des, len);
+       req_reply = RH_ACK;
+       break;
+     case (0x03): /* string descriptors */
+     default:
+     }
+     break;
+  case RH_GET_DESCRIPTOR | RH_CLASS:
+     data[1] = 0x29;
+     stat = readl(&ohci->regs->roothub.a);  
+     data[2] = stat & 0xff;        /* number of ports */
+     data[0] = (data[2] / 8) * 2 + 9; /* length of descriptor */
+     if(data[0] > wLength) {
+       req_reply =  RH_REQ_ERR;
+       break;
+     }
+     data[3] = (stat >> 8) & 0xff;
+     data[4] = (stat >> 16) & 0xff;
+     data[5] = (stat >> 24) & 0xff;
+     data[6] = 0; /* Root Hub needs no current from bus */
+     stat = readl(&ohci->regs->roothub.b); 
+     if(data[2] <= 8) { /* less than 8 Ports */
+       data[7] = stat & 0xff;
+       data[8] = (stat >> 16) & 0xff; /* 0xff for USB Rev. 1.1 ?, stat >> 16 for USB Rev. 1.0 */
+     }
+     else {
+       data[7] = stat & 0xff;
+       data[8] = (stat >> 8) & 0xff;
+       data[9] = (stat >> 16) & 0xff;  /* 0xff for USB Rev. 1.1?, stat >> 16 for USB Rev. 1.0 */
+       data[10] = (stat >> 24) & 0xff; /* 0xff for USB Rev. 1.1?, stat >> 24 for USB Rev. 1.0 */
+     }
+     len = data[0];
+     req_reply = RH_ACK;
+     break;
+
+   case RH_SET_DESCRIPTOR:
+     break;
+
+   case RH_GET_CONFIGURATION:
+     len = 1;
+     data[0] = 0x01;
+     req_reply = RH_ACK;
+     break;
+
+   case RH_SET_CONFIGURATION: /* start it up */
+     writel( 0x10000, &ohci->regs->roothub.status);
+     /*writel( OHCI_INTR_RHSC, &ohci->regs->intrenable);*/
+     len = 0;
+     req_reply = RH_ACK;
+     break;
+   /*  Optional or meaningless requests 
+     case RH_GET_STATE | RH_OTHER | RH_CLASS:
+     case RH_GET_INTERFACE | RH_INTERFACE:
+     case RH_SET_INTERFACE | RH_INTERFACE:
+     case RH_SYNC_FRAME | RH_ENDPOINT: 
+   */
+
+  /* Vendor Requests, we are the vendor!
+	Will the USB-Consortium give us a Vendor Id
+	for a virtual hub-device :-) ?
+     We could use these requests for configuration purposes on the HCD Driver, not used in the altenate usb !*/ 
+
+  case RH_SET_FEATURE | RH_VENDOR: /* remove all endpoints of device wIndex = Dev << 8  */
+    switch(wValue) {
+    case RH_REMOVE_EP:
+      ep_addr.iep = 0;
+      ep_addr.bep.ep = wIndex & 0xff;
+      ep_addr.bep.fa = (wIndex << 8) & 0xff00;
+      usb_ohci_rm_function(ohci, ep_addr.iep);
+      len=0;
+      req_reply = RH_ACK;
+      break;
+    }
+    break;
+  case RH_SET_FEATURE | RH_ENDPOINT | RH_VENDOR: /* remove endpoint wIndex = Dev << 8 | EP */
+    switch(wValue) {
+    case RH_REMOVE_EP: 
+      ep_addr.iep = 0;
+      ep_addr.bep.ep = wIndex & 0xff;
+      ep_addr.bep.fa = (wIndex << 8) & 0xff00;
+      usb_ohci_rm_ep(ohci, ohci_find_ep(ohci, ep_addr.iep));
+      len=0;
+      req_reply = RH_ACK;
+      break;
+    }
+    break;
+  case RH_SET_EP | RH_ENDPOINT | RH_VENDOR:   
+    ep_addr.bep.ep = data[0];
+    ep_addr.bep.fa = data[1];
+    ep_addr.bep.hc = data[2];
+    ep_addr.bep.host = data[3];  
+    rep_handler  = data[7] << 24 |data[6] << 16 | data[5] << 8 | data[4];
+    /*  struct usb_ohci_ed *usb_ohci_add_ep(union ep_addr_ ep_addr,
+	struct ohci * ohci, int interval, int load, int (*handler)(int, void*), int ep_size, int speed) */
+    usb_ohci_add_ep(ohci, ep_addr.iep, data[8], data[9], (f_handler) rep_handler, data[11] << 8 | data[10] , data[12]);
+    len=0;
+    req_reply = RH_ACK;
+    break;
+
+  default: 
+  }
+ printk("USB HC roothubstat1: %x \n", readl( &(ohci->regs->roothub.portstatus[0]) ));
+  printk("USB HC roothubstat2: %x \n", readl( &(ohci->regs->roothub.portstatus[1]) ));
+
+  /* if (req_reply == RH_ACK) len; */
+  queue_reply(ohci, ep_addr_ret.iep, 8, rh_cmd, data, len, lw0, lw1, handler);
+  return 0;
+}
+
+int root_hub_int_req(struct ohci * ohci, int cmd_len, void * ctrl, void *  data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler){
+
+	struct ohci_rep_td *td;
+ 	struct ohci_rep_td *tmp;
+ 	union ep_addr_ ep_addr;
+ 	
+ 	td = kmalloc(sizeof(td),GFP_KERNEL);
+ 	tmp = ohci->td_rh_epi;
+ 	td->next_td = NULL;
+ 	if(tmp == NULL) { /* queue td */
+ 		ohci->td_rh_epi = td;	
+ 	}
+ 	else {
+ 		while(tmp->next_td != NULL) tmp = tmp->next_td;
+ 		tmp->next_td = td;
+ 	}
+ 	ep_addr.iep = 0;
+ 	ep_addr.bep.fa = ohci->root_hub_funct_addr;
+ 	ep_addr.bep.ep = 0xA1; /* INT IN EP endpoint 1 */
+  	td->cmd_len = 0;
+  	td->cmd = NULL;
+  	td->data = data;
+  	td->data_len = data_len;
+  	td->handler = handler; 
+  	td->next_td = NULL;
+  	td->ep_addr = ep_addr.iep;
+	td->lw0 = lw0;
+	td->lw1 = lw1;
+	ohci_init_rh_int_timer(ohci, 255);
+	return 0;
+}
+
+
+/* prepare Interrupt pipe transaction data; HUP INTERRUPT ENDPOINT */ 
+int root_hub_send_irq(struct ohci * ohci, void * rh_data, int rh_len ) {
+
+  int num_ports;
+  int i;
+  int ret;
+  int len;
+
+  __u8 * data = rh_data;
+
+  num_ports = readl(&ohci->regs->roothub.a) & 0xff; 
+  data[0] = (readl(&ohci->regs->roothub.status) & 0x00030000)>0?1:0;
+  ret = data[0];
+
+  for(i=0; i < num_ports; i++) {
+    data[i/8] |= ((readl(&ohci->regs->roothub.portstatus[i]) & 0x001f0000)>0?1:0) << ((i+1) % 8);
+    ret += data[i/8];
+  }
+  len = i/8 + 1;
+  
+  if (ret > 0) return len;
+
+  return  RH_NACK;
+}
+
+
+
+
+ 
+static struct timer_list rh_int_timer;
+
+/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
+static void rh_int_timer_do(unsigned long ptr) {
+	int len; 
+	int interval;
+	struct ohci * ohci = (struct ohci *) ptr;
+    struct ohci_rep_td *td = ohci->td_rh_epi;
+
+	if(td != NULL) { /* if ther is a TD handle the INT request */
+		
+		len = root_hub_send_irq(ohci, td->data, td->data_len );
+		if(len > 0) {
+			ohci->td_rh_epi = td->next_td;
+			td->next_td = ohci->repl_queue; 
+			ohci->repl_queue = td;
+			send_replies(ohci);
+		}
+	}	
+	interval = ohci->rh_int_interval;
+	init_timer(& rh_int_timer);
+	rh_int_timer.function = rh_int_timer_do;
+	rh_int_timer.data = (unsigned long) ohci;
+	rh_int_timer.expires = jiffies + (HZ * (interval<30?30: interval)) /1000;
+	add_timer(&rh_int_timer);
+}
+
+/* Root Hub INTs are polled by this timer */
+int ohci_init_rh_int_timer(struct ohci * ohci, int interval) {
+
+	if(!(ohci->rh_int_timer)) { 
+		ohci->rh_int_timer = 1;
+		ohci->rh_int_interval = interval;
+		init_timer(& rh_int_timer);
+		rh_int_timer.function = rh_int_timer_do;
+		rh_int_timer.data = (unsigned long) ohci;
+		rh_int_timer.expires = jiffies + (HZ * (interval<30?30: interval)) /1000;
+		add_timer(&rh_int_timer);
+	}
+	return 0;
+}
+
+int ohci_del_rh_int_timer(struct ohci * ohci) {
+	del_timer(&rh_int_timer);
+	return 0;
+}
+/* for root hub replies, queue the reply, (it will be sent immediately now) */
+
+int queue_reply(struct ohci * ohci, unsigned int ep_addr, int cmd_len,void * cmd, void * data,int  len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler) {
+
+ struct ohci_rep_td *td;
+ int status = 0;
+ 
+printk("queue_reply ep: %x len: %x\n", ep_addr, len);
+td = kmalloc(sizeof(td), GFP_KERNEL);
+
+  if (len < 0) { status = len; len = 0;}
+  td->cmd_len = cmd_len;
+  td->cmd = cmd;
+  td->data = data;
+  td->data_len = len;
+  td->handler = handler; 
+  td->next_td = ohci->repl_queue; ohci->repl_queue = td;
+  td->ep_addr = ep_addr;
+  td->lw0 = lw0;
+  td->lw1 = lw1;
+  td->status = status;
+  send_replies(ohci);
+return 0;
+}
+
+/* for root hub replies; send the reply */
+int send_replies(struct ohci * ohci) { 
+	struct ohci_rep_td *td;
+	struct ohci_rep_td *tmp;
+
+	td = ohci->repl_queue; ohci->repl_queue = NULL;
+	while ( td != NULL) {
+		td->handler((void *) ohci, td->ep_addr,td->cmd_len,td->cmd, td->data, td->data_len, td->status, td->lw0, td->lw1); 
+		tmp = td;
+		td = td->next_td;
+	
+		kfree(tmp);
+	}
+	return 0;
+}
+ 
+#endif
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/ohci-root-hub.h linux/drivers/usb/ohci-root-hub.h
--- v2.2.7/linux/drivers/usb/ohci-root-hub.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/ohci-root-hub.h	Mon May 10 10:18:34 1999
@@ -0,0 +1,71 @@
+/*
+ * HCD (OHCI) Virtual Root Hub Protocol for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber (weissg@vienna.at)
+ *
+ * The Root Hub is build into the HC (UHCI or OHCI) hardware. 
+ * This piece of code lets it look like it resides on the bus 
+ * like the other hubs.
+ * (for anyone who wants to do a control operation on the root hub)
+ *  
+ * v1.0 1999/04/27
+ * ohci-root-hub.h
+ *  
+ */
+ 
+/* destination of request */
+#define RH_INTERFACE               0x01
+#define RH_ENDPOINT                0x02
+#define RH_OTHER                   0x03
+
+#define RH_CLASS                   0x20
+#define RH_VENDOR                  0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS           0x0080
+#define RH_CLEAR_FEATURE        0x0100
+#define RH_SET_FEATURE          0x0300
+#define RH_SET_ADDRESS			0x0500
+#define RH_GET_DESCRIPTOR		0x0680
+#define RH_SET_DESCRIPTOR       0x0700
+#define RH_GET_CONFIGURATION	0x0880
+#define RH_SET_CONFIGURATION	0x0900
+#define RH_GET_STATE            0x0280
+#define RH_GET_INTERFACE        0x0A80
+#define RH_SET_INTERFACE        0x0B00
+#define RH_SYNC_FRAME           0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP               0x2000
+
+
+/* Hub port features */
+#define RH_PORT_CONNECTION         0x00
+#define RH_PORT_ENABLE             0x01
+#define RH_PORT_SUSPEND            0x02
+#define RH_PORT_OVER_CURRENT       0x03
+#define RH_PORT_RESET              0x04
+#define RH_PORT_POWER              0x08
+#define RH_PORT_LOW_SPEED          0x09
+#define RH_C_PORT_CONNECTION       0x10
+#define RH_C_PORT_ENABLE           0x11
+#define RH_C_PORT_SUSPEND          0x12
+#define RH_C_PORT_OVER_CURRENT     0x13
+#define RH_C_PORT_RESET            0x14  
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER       0x00
+#define RH_C_HUB_OVER_CURRENT      0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP    0x00
+#define RH_ENDPOINT_STALL          0x01
+
+/* Our Vendor Specific feature */
+#define RH_REMOVE_EP               0x00
+
+
+#define RH_ACK                     0x01
+#define RH_REQ_ERR                 -1
+#define RH_NACK                    0x00
+ 
+#define min(a,b) (((a)<(b))?(a):(b))  
+ 
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- v2.2.7/linux/drivers/usb/uhci.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/uhci.c	Fri Apr 30 08:20:53 1999
@@ -47,9 +47,6 @@
 
 #define compile_assert(x) do { switch (0) { case 1: case !(x): } } while (0)
 
-int usb_mouse_init(void);
-int hub_init(void);
-
 static struct wait_queue *uhci_configure = NULL;
 
 /*
@@ -515,6 +512,7 @@
 
 	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev) {
+		usb_destroy_configuration(usb_dev);
 		kfree(usb_dev);
 		return NULL;
 	}
@@ -573,6 +571,7 @@
 	}
 
 	kfree(dev);
+	usb_destroy_configuration(usb_dev);
 	kfree(usb_dev);
 
 	return 0;
@@ -995,6 +994,8 @@
 	kfree(uhci);
 }
 
+void cleanup_drivers(void);
+
 static int uhci_control_thread(void * __uhci)
 {
 	struct uhci *uhci = (struct uhci *)__uhci;
@@ -1052,6 +1053,8 @@
 			usb_disconnect(uhci->root_hub->usb->children + i);
 #endif
 
+	cleanup_drivers();
+
 	reset_hc(uhci);
 	release_region(uhci->io_addr, 32);
 
@@ -1199,4 +1202,12 @@
 		return 0;
 	}
 	return retval;
+}
+
+void cleanup_drivers(void)
+{
+	hub_cleanup();
+#ifdef CONFIG_USB_MOUSE
+	usb_mouse_cleanup();
+#endif
 }
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.2.7/linux/drivers/usb/usb.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/usb.c	Fri May  7 15:16:04 1999
@@ -213,6 +213,15 @@
 		return -1;
 	}
 
+	interface->endpoint = (struct usb_endpoint_descriptor *)
+		kmalloc(interface->bNumEndpoints * sizeof(struct usb_endpoint_descriptor), GFP_KERNEL);
+	if(interface->endpoint==NULL)
+	{
+		printk(KERN_WARNING "usb: out of memory.\n");
+		return -1;	
+	}
+	memset(interface->endpoint, 0, interface->bNumEndpoints*sizeof(struct usb_endpoint_descriptor));
+	
 	for (i = 0; i < interface->bNumEndpoints; i++) {
 //		if(((USB_DT_HID << 8) | 9) == *(unsigned short*)(ptr + parsed)) {
 //			parsed += 9;	/* skip over the HID descriptor for now */
@@ -242,8 +251,18 @@
 	{
 		printk(KERN_WARNING "usb: too many interfaces.\n");
 		return -1;
+
 	}
 
+	config->interface = (struct usb_interface_descriptor *)
+		kmalloc(config->bNumInterfaces * sizeof(struct usb_interface_descriptor), GFP_KERNEL);
+	if(config->interface==NULL)
+	{
+		printk(KERN_WARNING "usb: out of memory.\n");
+		return -1;	
+	}
+	memset(config->interface, 0, config->bNumInterfaces*sizeof(struct usb_interface_descriptor));
+	
 	for (i = 0; i < config->bNumInterfaces; i++) {
 		int retval = usb_parse_interface(dev, config->interface + i, ptr + parsed, len);
 		if (retval < 0)
@@ -266,6 +285,14 @@
 		return -1;
 	}
 
+	dev->config = (struct usb_config_descriptor *)
+		kmalloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor), GFP_KERNEL);
+	if(dev->config==NULL)
+	{
+		printk(KERN_WARNING "usb: out of memory.\n");
+		return -1;	
+	}
+	memset(dev->config, 0, dev->descriptor.bNumConfigurations*sizeof(struct usb_config_descriptor));
 	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
 		int retval = usb_parse_config(dev, dev->config + i, ptr, bytes);
 		if (retval < 0)
@@ -276,6 +303,31 @@
 	return 0;
 }
 
+void usb_destroy_configuration(struct usb_device *dev)
+{
+	int c, i;
+	struct usb_config_descriptor *cf;
+	struct usb_interface_descriptor *ifp;
+	
+	if(dev->config==NULL)
+		return;
+	for(c=0;c<dev->descriptor.bNumConfigurations;c++)
+	{
+		cf=&dev->config[c];
+		if(cf->interface==NULL)
+			break;
+		for(i=0;i<cf->bNumInterfaces;i++)
+		{
+			ifp=&cf->interface[i];
+			if(ifp->endpoint==NULL)
+				break;
+			kfree(ifp->endpoint);
+		}
+		kfree(cf->interface);
+	}
+	kfree(dev->config);
+}
+			
 void usb_init_root_hub(struct usb_device *dev)
 {
 	dev->devnum = -1;
@@ -517,24 +569,29 @@
 
 int usb_get_configuration(struct usb_device *dev)
 {
-	unsigned int size;
+	unsigned int cfgno,size;
 	unsigned char buffer[400];
-
-	/* Get the first 8 bytes - guaranteed */
-	if (usb_get_descriptor(dev, USB_DT_CONFIG, 0, buffer, 8))
-		return -1;
-
-	/* Get the full buffer */
-	size = *(unsigned short *)(buffer+2);
-	if (size > sizeof(buffer))
-	{
-		printk(KERN_INFO "usb: truncated DT_CONFIG (want %d).\n", size);
-		size = sizeof(buffer);
+	unsigned char * bufptr;
+	
+	bufptr=buffer;
+        for (cfgno=0;cfgno<dev->descriptor.bNumConfigurations;cfgno++) {
+  		/* Get the first 8 bytes - guaranteed */
+	  	if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, 8))
+	    		return -1;
+
+  	  	/* Get the full buffer */
+	  	size = *(unsigned short *)(bufptr+2);
+	  	if (bufptr+size > buffer+sizeof(buffer))
+	  	{
+			printk(KERN_INFO "usb: truncated DT_CONFIG (want %d).\n", size);
+			size = buffer+sizeof(buffer)-bufptr;
+		}
+		if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, size))
+			return -1;
+			
+		/* Prepare for next configuration */
+		bufptr+=size;
 	}
-
-	if (usb_get_descriptor(dev, USB_DT_CONFIG, 0, buffer, size))
-		return -1;
-
 	return usb_parse_configuration(dev, buffer, size);
 }
 
diff -u --recursive --new-file v2.2.7/linux/drivers/usb/usb.h linux/drivers/usb/usb.h
--- v2.2.7/linux/drivers/usb/usb.h	Wed Apr 28 11:37:30 1999
+++ linux/drivers/usb/usb.h	Mon May 10 10:35:29 1999
@@ -1,6 +1,7 @@
 #ifndef __LINUX_USB_H
 #define __LINUX_USB_H
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/sched.h>
@@ -8,7 +9,7 @@
 static __inline__ void wait_ms(unsigned int ms)
 {
         current->state = TASK_UNINTERRUPTIBLE;
-        schedule_timeout(1 + ms / 10);
+        schedule_timeout(1 + ms * HZ / 1000);
 }
 
 
@@ -99,17 +100,11 @@
  *
  * USB device information
  *
- * Make this MUCH dynamic, right now
- * it contains enough information for
- * a USB floppy controller, and nothing
- * else.
- *
- * I'm not proud. I just want this dang
- * thing to start working.
  */
-#define USB_MAXCONFIG		2
-#define USB_MAXINTERFACES	8
-#define USB_MAXENDPOINTS	4
+
+#define USB_MAXCONFIG		8
+#define USB_MAXINTERFACES	32
+#define USB_MAXENDPOINTS	32
 
 struct usb_device_descriptor {
 	__u8  bLength;
@@ -136,6 +131,7 @@
 	__u8  bmAttributes;
 	__u16 wMaxPacketSize;
 	__u8  bInterval;
+	void  *audio;
 };
 
 /* Interface descriptor */
@@ -150,7 +146,8 @@
 	__u8  bInterfaceProtocol;
 	__u8  iInterface;
 
-	struct usb_endpoint_descriptor endpoint[USB_MAXENDPOINTS];
+	struct usb_endpoint_descriptor *endpoint;
+	void  *audio;
 };
 
 /* Configuration descriptor information.. */
@@ -164,7 +161,7 @@
 	__u8  bmAttributes;
 	__u8  MaxPower;
 
-	struct usb_interface_descriptor interface[USB_MAXINTERFACES];
+	struct usb_interface_descriptor *interface;
 };
 
 /* String descriptor */
@@ -228,7 +225,7 @@
 	struct usb_bus *bus;					/* Bus we're apart of */
 	struct usb_driver *driver;				/* Driver */
 	struct usb_device_descriptor descriptor;		/* Descriptor */
-	struct usb_config_descriptor config[USB_MAXCONFIG];	/* All of the configs */
+	struct usb_config_descriptor *config;			/* All of the configs */
 	struct usb_device *parent;
   
 	/*
@@ -363,8 +360,8 @@
 void usb_audio_interface(struct usb_interface_descriptor *, u8 *);
 void usb_audio_endpoint(struct usb_endpoint_descriptor *, u8 *);
 #else
-extern inline void usb_audio_interface(struct usb_interface_descriptor *, u8 *) {}
-extern inline void usb_audio_endpoint(struct usb_endpoint_descriptor *, u8 *) {}
+extern inline void usb_audio_interface(struct usb_interface_descriptor *interface, u8 *data) {}
+extern inline void usb_audio_endpoint(struct usb_endpoint_descriptor *interface, u8 *data) {}
 #endif
 
 #endif
diff -u --recursive --new-file v2.2.7/linux/drivers/video/matroxfb.c linux/drivers/video/matroxfb.c
--- v2.2.7/linux/drivers/video/matroxfb.c	Wed Apr 28 11:37:30 1999
+++ linux/drivers/video/matroxfb.c	Thu Apr 29 12:53:48 1999
@@ -57,6 +57,9 @@
  *               "H. Peter Arvin" <hpa@transmeta.com>
  *                     Ideas
  *
+ *               "Cort Dougan" <cort@cs.nmt.edu>
+ *                     CHRP fixes and PReP cleanup
+ *
  * (following author is not in any relation with this code, but his code
  *  is included in this driver)
  *
@@ -187,14 +190,8 @@
 #if defined(__m68k__)
 #define MAP_BUSTOVIRT
 #else
-#if defined(CONFIG_PPC) && defined(CONFIG_PREP) && defined(_ISA_MEM_BASE)
-/* do not tell me that PPC is not broken... if ioremap() oops with
-   invalid value written to msr... */
-#define MAP_ISAMEMBASE
-#else
 #define MAP_IOREMAP
 #endif
-#endif
 
 #ifdef DEBUG
 #define dprintk(X...)	printk(X)
@@ -354,11 +351,7 @@
 #ifdef MAP_BUSTOVIRT
 	virt->vaddr = bus_to_virt(phys);
 #else
-#ifdef MAP_ISAMEMBASE
-	virt->vaddr = (void*)(phys + _ISA_MEM_BASE);
-#else
 #error "Your architecture does not have neither ioremap nor bus_to_virt... Giving up"
-#endif
 #endif
 #endif
 	return (virt->vaddr == 0); /* 0, !0... 0, error_code in future */
diff -u --recursive --new-file v2.2.7/linux/drivers/video/offb.c linux/drivers/video/offb.c
--- v2.2.7/linux/drivers/video/offb.c	Tue Mar 23 14:35:48 1999
+++ linux/drivers/video/offb.c	Thu Apr 29 12:53:48 1999
@@ -476,9 +476,7 @@
 	    printk("no framebuffer address found for %s\n", dp->full_name);
 	    return;
 	}
-	/* needed for the gxt on the f50 -- Cort */
-	if ( dp->addrs[i].address < isa_mem_base )
-		(u_long)dp->addrs[i].address += isa_mem_base;
+
 	address = (u_long)dp->addrs[i].address;
 
 	/* kludge for valkyrie */
@@ -487,6 +485,7 @@
     }
     offb_init_fb(dp->name, dp->full_name, width, height, depth,
 		 pitch, address);
+    
 }
 
 __initfunc(static void offb_init_fb(const char *name, const char *full_name,
diff -u --recursive --new-file v2.2.7/linux/drivers/video/vesafb.c linux/drivers/video/vesafb.c
--- v2.2.7/linux/drivers/video/vesafb.c	Fri Apr 16 14:47:31 1999
+++ linux/drivers/video/vesafb.c	Mon May 10 10:32:45 1999
@@ -635,10 +635,8 @@
 		video_cmap_len = 256;
 	}
 	request_region(0x3c0, 32, "vga+");
-#ifdef CONFIG_MTRR
 	if (mtrr)
 		mtrr_add((unsigned long)video_base, video_size, MTRR_TYPE_WRCOMB, 1);
-#endif
 	
 	strcpy(fb_info.modename, "VESA VGA");
 	fb_info.changevar = NULL;
diff -u --recursive --new-file v2.2.7/linux/fs/autofs/root.c linux/fs/autofs/root.c
--- v2.2.7/linux/fs/autofs/root.c	Wed Apr 28 11:37:30 1999
+++ linux/fs/autofs/root.c	Sat May  8 17:56:37 1999
@@ -168,7 +168,7 @@
  * yet completely filled in, and revalidate has to delay such
  * lookups..
  */
-static int autofs_revalidate(struct dentry * dentry)
+static int autofs_revalidate(struct dentry * dentry, int flags)
 {
 	struct inode * dir = dentry->d_parent->d_inode;
 	struct autofs_sb_info *sbi = autofs_sbi(dir->i_sb);
@@ -241,7 +241,7 @@
 	d_add(dentry, NULL);
 
 	up(&dir->i_sem);
-	autofs_revalidate(dentry);
+	autofs_revalidate(dentry, 0);
 	down(&dir->i_sem);
 
 	/*
diff -u --recursive --new-file v2.2.7/linux/fs/coda/dir.c linux/fs/coda/dir.c
--- v2.2.7/linux/fs/coda/dir.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/coda/dir.c	Sat May  8 17:56:37 1999
@@ -44,7 +44,7 @@
 static int coda_readdir(struct file *file, void *dirent, filldir_t filldir);
 
 /* dentry ops */
-static int coda_dentry_revalidate(struct dentry *de);
+static int coda_dentry_revalidate(struct dentry *de, int);
 static void coda_dentry_delete(struct dentry *);
 
 /* support routines */
@@ -778,7 +778,7 @@
 }
 
 /* called when a cache lookup succeeds */
-static int coda_dentry_revalidate(struct dentry *de)
+static int coda_dentry_revalidate(struct dentry *de, int flags)
 {
 	int valid = 1;
 	struct inode *inode = de->d_inode;
diff -u --recursive --new-file v2.2.7/linux/fs/devpts/root.c linux/fs/devpts/root.c
--- v2.2.7/linux/fs/devpts/root.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/devpts/root.c	Sat May  8 17:56:37 1999
@@ -18,7 +18,7 @@
 
 static int devpts_root_readdir(struct file *,void *,filldir_t);
 static struct dentry *devpts_root_lookup(struct inode *,struct dentry *);
-static int devpts_revalidate(struct dentry *);
+static int devpts_revalidate(struct dentry *, int);
 
 static struct file_operations devpts_root_operations = {
 	NULL,                   /* llseek */
@@ -116,7 +116,7 @@
  * the pty really does still exist.  Never revalidate negative dentries;
  * for simplicity (fix later?)
  */
-static int devpts_revalidate(struct dentry * dentry)
+static int devpts_revalidate(struct dentry * dentry, int flags)
 {
 	struct devpts_sb_info *sbi;
 
diff -u --recursive --new-file v2.2.7/linux/fs/dquot.c linux/fs/dquot.c
--- v2.2.7/linux/fs/dquot.c	Wed Mar 10 15:29:49 1999
+++ linux/fs/dquot.c	Fri May  7 18:04:12 1999
@@ -1268,11 +1268,11 @@
 
 int quota_on(kdev_t dev, short type, char *path)
 {
-	struct file *filp = NULL;
-	struct dentry *dentry;
+	struct file *f;
 	struct vfsmount *vfsmnt;
 	struct inode *inode;
 	struct dquot *dquot;
+	struct quota_mount_options *mnt_dquot;
 	char *tmp;
 	int error;
 
@@ -1281,69 +1281,48 @@
 		return -ENODEV;
 
 	if (is_enabled(vfsmnt, type))
-		return(-EBUSY);
+		return -EBUSY;
+	mnt_dquot = &vfsmnt->mnt_dquot;
 
 	tmp = getname(path);
 	error = PTR_ERR(tmp);
 	if (IS_ERR(tmp))
 		return error;
 
-	dentry = open_namei(tmp, O_RDWR, 0600);
+	f = filp_open(tmp, O_RDWR, 0600);
 	putname(tmp);
+	if (IS_ERR(f))
+		return PTR_ERR(f);
 
-	error = PTR_ERR(dentry);
-	if (IS_ERR(dentry))
-		return error;
-	inode = dentry->d_inode;
-
-	if (!S_ISREG(inode->i_mode)) {
-		dput(dentry);
-		return -EACCES;
-	}
-
-	if (inode->i_size == 0 || (inode->i_size % sizeof(struct dqblk)) != 0) {
-		dput(dentry);
-		return(-EINVAL);
-	}
-
-	filp = get_empty_filp();
-	if (filp != (struct file *)NULL) {
-		filp->f_mode = (O_RDWR + 1) & O_ACCMODE;
-		filp->f_flags = O_RDWR;
-		filp->f_dentry = dentry;
-		filp->f_pos = 0;
-		filp->f_reada = 0;
-		filp->f_op = inode->i_op->default_file_ops;
-		if (filp->f_op->read || filp->f_op->write) {
-			error = get_write_access(inode);
-			if (!error) {
-				if (filp->f_op && filp->f_op->open)
-					error = filp->f_op->open(inode, filp);
-				if (!error) {
-					set_enable_flags(vfsmnt, type);
-					vfsmnt->mnt_dquot.files[type] = filp;
-
-					dquot = dqget(dev, 0, type);
-					vfsmnt->mnt_dquot.inode_expire[type] = (dquot) ? dquot->dq_itime : MAX_IQ_TIME;
-					vfsmnt->mnt_dquot.block_expire[type] = (dquot) ? dquot->dq_btime : MAX_DQ_TIME;
-					dqput(dquot);
-
-					vfsmnt->mnt_sb->dq_op = &dquot_operations;
-					add_dquot_ref(dev, type);
-
-					return(0);
-				}
-				put_write_access(inode);
-			}
-		} else
-			error = -EIO;
-		put_filp(filp);
-	} else
-		error = -EMFILE;
-
-	dput(dentry);
-
-	return(error);
+	/* sanity checks */
+	error = -EIO;
+	if (!f->f_op->read && !f->f_op->write)
+		goto cleanup;
+	inode = f->f_dentry->d_inode;
+	error = -EACCES;
+	if (!S_ISREG(inode->i_mode))
+		goto cleanup;
+	error = -EINVAL;
+	if (inode->i_size == 0 || (inode->i_size % sizeof(struct dqblk)) != 0)
+		goto cleanup;
+
+	/* OK, there we go */
+	set_enable_flags(vfsmnt, type);
+	mnt_dquot->files[type] = f;
+
+	dquot = dqget(dev, 0, type);
+	mnt_dquot->inode_expire[type] = (dquot) ? dquot->dq_itime : MAX_IQ_TIME;
+	mnt_dquot->block_expire[type] = (dquot) ? dquot->dq_btime : MAX_DQ_TIME;
+	dqput(dquot);
+
+	vfsmnt->mnt_sb->dq_op = &dquot_operations;
+	add_dquot_ref(dev, type);
+
+	return(0);
+
+cleanup:
+	fput(f);
+	return error;
 }
 
 /*
@@ -1370,8 +1349,8 @@
 		case Q_GETSTATS:
 			break;
 		case Q_GETQUOTA:
-			if (((type == USRQUOTA && current->uid != id) ||
-			     (type == GRPQUOTA && current->gid != id)) &&
+			if (((type == USRQUOTA && current->euid != id) ||
+			     (type == GRPQUOTA && current->egid != id)) &&
 			    !capable(CAP_SYS_RESOURCE))
 				goto out;
 			break;
diff -u --recursive --new-file v2.2.7/linux/fs/exec.c linux/fs/exec.c
--- v2.2.7/linux/fs/exec.c	Tue Jan 19 11:32:52 1999
+++ linux/fs/exec.c	Thu Apr 29 22:10:12 1999
@@ -29,7 +29,6 @@
 #include <linux/a.out.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
-#include <linux/user.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 
diff -u --recursive --new-file v2.2.7/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
--- v2.2.7/linux/fs/ext2/inode.c	Tue Mar 23 14:35:48 1999
+++ linux/fs/ext2/inode.c	Tue May  4 16:27:07 1999
@@ -286,7 +286,8 @@
 	u32 * p;
 	struct buffer_head * result;
 	int blocks = inode->i_sb->s_blocksize / 512;
-
+	unsigned long limit;
+	
 	if (!bh)
 		return NULL;
 	if (!buffer_uptodate(bh)) {
@@ -309,13 +310,22 @@
 		brelse (result);
 		goto repeat;
 	}
-	if (!create || new_block >= 
-	    (current->rlim[RLIMIT_FSIZE].rlim_cur >> 
-	     EXT2_BLOCK_SIZE_BITS(inode->i_sb))) {
+	*err = -EFBIG;
+	if (!create) {
 		brelse (bh);
-		*err = -EFBIG;
 		return NULL;
 	}
+
+	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+	if (limit < RLIM_INFINITY) {
+		limit >>= EXT2_BLOCK_SIZE_BITS(inode->i_sb);
+		if (new_block >= limit) {
+			brelse (bh);
+			send_sig(SIGXFSZ, current, 0);
+			return NULL;
+		}
+	}
+
 	if (inode->u.ext2_i.i_next_alloc_block == new_block)
 		goal = inode->u.ext2_i.i_next_alloc_goal;
 	if (!goal) {
diff -u --recursive --new-file v2.2.7/linux/fs/hfs/sysdep.c linux/fs/hfs/sysdep.c
--- v2.2.7/linux/fs/hfs/sysdep.c	Mon Dec 28 15:00:52 1998
+++ linux/fs/hfs/sysdep.c	Sat May  8 17:56:37 1999
@@ -18,7 +18,7 @@
 #include <linux/hfs_fs_i.h>
 #include <linux/hfs_fs.h>
 
-static int hfs_revalidate_dentry(struct dentry *);
+static int hfs_revalidate_dentry(struct dentry *, int);
 static int hfs_hash_dentry(struct dentry *, struct qstr *);
 static int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
 static void hfs_dentry_iput(struct dentry *, struct inode *);
@@ -89,7 +89,7 @@
 	iput(inode);
 }
 
-static int hfs_revalidate_dentry(struct dentry *dentry)
+static int hfs_revalidate_dentry(struct dentry *dentry, int flags)
 {
 	struct inode *inode = dentry->d_inode;
 	int diff;
diff -u --recursive --new-file v2.2.7/linux/fs/inode.c linux/fs/inode.c
--- v2.2.7/linux/fs/inode.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/inode.c	Tue May  4 10:57:12 1999
@@ -522,6 +522,7 @@
 	inode->i_nlink = 1;
 	inode->i_writecount = 0;
 	inode->i_size = 0;
+	inode->i_generation = 0;
 	memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
 	sema_init(&inode->i_sem, 1);
 }
diff -u --recursive --new-file v2.2.7/linux/fs/namei.c linux/fs/namei.c
--- v2.2.7/linux/fs/namei.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/namei.c	Sat May  8 20:46:08 1999
@@ -23,18 +23,6 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 
-/*
- * The bitmask for a lookup event:
- *  - follow links at the end
- *  - require a directory
- *  - ending slashes ok even for nonexistent files
- *  - internal "there are more path compnents" flag
- */
-#define LOOKUP_FOLLOW		(1)
-#define LOOKUP_DIRECTORY	(2)
-#define LOOKUP_SLASHOK		(4)
-#define LOOKUP_CONTINUE		(8)
-
 #include <asm/namei.h>
 
 /* This can be removed after the beta phase. */
@@ -225,12 +213,12 @@
 /*
  * Internal lookup() using the new generic dcache.
  */
-static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name)
+static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name, int flags)
 {
 	struct dentry * dentry = d_lookup(parent, name);
 
 	if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
-		if (!dentry->d_op->d_revalidate(dentry) && !d_invalidate(dentry)) {
+		if (!dentry->d_op->d_revalidate(dentry, flags) && !d_invalidate(dentry)) {
 			dput(dentry);
 			dentry = NULL;
 		}
@@ -245,7 +233,7 @@
  * We get the directory semaphore, and after getting that we also
  * make sure that nobody added the entry to the dcache in the meantime..
  */
-static struct dentry * real_lookup(struct dentry * parent, struct qstr * name)
+static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, int flags)
 {
 	struct dentry * result;
 	struct inode *dir = parent->d_inode;
@@ -258,7 +246,7 @@
 	 * FIXME! This could use version numbering or similar to
 	 * avoid unnecessary cache lookups.
 	 */
-	result = cached_lookup(parent, name);
+	result = cached_lookup(parent, name, flags);
 	if (!result) {
 		struct dentry * dentry = d_alloc(parent, name);
 		result = ERR_PTR(-ENOMEM);
@@ -392,9 +380,9 @@
 		/* This does the actual lookups.. */
 		dentry = reserved_lookup(base, &this);
 		if (!dentry) {
-			dentry = cached_lookup(base, &this);
+			dentry = cached_lookup(base, &this, flags);
 			if (!dentry) {
-				dentry = real_lookup(base, &this);
+				dentry = real_lookup(base, &this, flags);
 				if (IS_ERR(dentry))
 					break;
 			}
diff -u --recursive --new-file v2.2.7/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v2.2.7/linux/fs/ncpfs/dir.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/ncpfs/dir.c	Sat May  8 17:56:37 1999
@@ -112,14 +112,14 @@
 /*
  * Dentry operations routines
  */
-static int ncp_lookup_validate(struct dentry *);
+static int ncp_lookup_validate(struct dentry *, int);
 static int ncp_hash_dentry(struct dentry *, struct qstr *);
 static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *);
 static void ncp_delete_dentry(struct dentry *);
 
 struct dentry_operations ncp_dentry_operations =
 {
-	ncp_lookup_validate,	/* d_validate(struct dentry *) */
+	ncp_lookup_validate,	/* d_revalidate(struct dentry *, int) */
 	ncp_hash_dentry,	/* d_hash */
 	ncp_compare_dentry,    	/* d_compare */
 	ncp_delete_dentry	/* d_delete(struct dentry *) */
@@ -345,7 +345,7 @@
 
 
 static int
-ncp_lookup_validate(struct dentry * dentry)
+ncp_lookup_validate(struct dentry * dentry, int flags)
 {
 	struct ncp_server *server;
 	struct inode *dir = dentry->d_parent->d_inode;
diff -u --recursive --new-file v2.2.7/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.2.7/linux/fs/nfs/dir.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/nfs/dir.c	Sat May  8 23:18:22 1999
@@ -72,9 +72,9 @@
 	NULL,			/* select - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
-	NULL,			/* no special open is needed */
+	nfs_open,		/* open */
 	NULL,			/* flush */
-	NULL,			/* no special release code */
+	nfs_release,		/* release */
 	NULL			/* fsync */
 };
 
@@ -364,7 +364,48 @@
 	dentry->d_time = jiffies;
 }
 
-#define NFS_REVALIDATE_INTERVAL (5*HZ)
+static inline int nfs_dentry_force_reval(struct dentry *dentry, int flags)
+{
+	struct inode *inode = dentry->d_inode;
+	unsigned long timeout = NFS_ATTRTIMEO(inode);
+
+	/*
+	 * If it's the last lookup in a series, we use a stricter
+	 * cache consistency check by looking at the parent mtime.
+	 *
+	 * If it's been modified in the last hour, be really strict.
+	 * (This still means that we can avoid doing unnecessary
+	 * work on directories like /usr/share/bin etc which basically
+	 * never change).
+	 */
+	if (!(flags & LOOKUP_CONTINUE)) {
+		long diff = CURRENT_TIME - dentry->d_parent->d_inode->i_mtime;
+
+		if (diff < 15*60)
+			timeout = 0;
+	}
+	
+	return time_after(jiffies,dentry->d_time + timeout);
+}
+
+/*
+ * We judge how long we want to trust negative
+ * dentries by looking at the parent inode mtime.
+ *
+ * If mtime is close to present time, we revalidate
+ * more often.
+ */
+static inline int nfs_neg_need_reval(struct dentry *dentry)
+{
+	unsigned long timeout = 30 * HZ;
+	long diff = CURRENT_TIME - dentry->d_parent->d_inode->i_mtime;
+
+	if (diff < 5*60)
+		timeout = 1 * HZ;
+
+	return time_after(jiffies, dentry->d_time + timeout);
+}
+
 /*
  * This is called every time the dcache has a lookup hit,
  * and we should check whether we can really trust that
@@ -377,7 +418,7 @@
  * we do a new lookup and verify that the dentry is still
  * correct.
  */
-static int nfs_lookup_revalidate(struct dentry * dentry)
+static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
 {
 	struct dentry * parent = dentry->d_parent;
 	struct inode * inode = dentry->d_inode;
@@ -386,11 +427,15 @@
 	struct nfs_fattr fattr;
 
 	/*
-	 * If we don't have an inode, let's just assume
-	 * a 5-second "live" time for negative dentries.
+	 * If we don't have an inode, let's look at the parent
+	 * directory mtime to get a hint about how often we
+	 * should validate things..
 	 */
-	if (!inode)
-		goto do_lookup;
+	if (!inode) {
+		if (nfs_neg_need_reval(dentry))
+			goto out_bad;
+		goto out_valid;
+	}
 
 	if (is_bad_inode(inode)) {
 		dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n",
@@ -398,27 +443,17 @@
 		goto out_bad;
 	}
 
-	if (_nfs_revalidate_inode(NFS_DSERVER(dentry), dentry))
-		goto out_bad;
-
-	if (time_before(jiffies,dentry->d_time+NFS_ATTRTIMEO(inode)))
+	if (IS_ROOT(dentry))
 		goto out_valid;
 
-	if (IS_ROOT(dentry))
+	if (!nfs_dentry_force_reval(dentry, flags))
 		goto out_valid;
 
-do_lookup:
 	/*
 	 * Do a new lookup and check the dentry attributes.
 	 */
-	error = nfs_proc_lookup(NFS_DSERVER(parent), NFS_FH(parent), 
+	error = nfs_proc_lookup(NFS_DSERVER(parent), NFS_FH(parent),
 				dentry->d_name.name, &fhandle, &fattr);
-	if (dentry->d_inode == NULL) {
-		if (error == -ENOENT &&
-		    time_before(jiffies,dentry->d_time+NFS_REVALIDATE_INTERVAL))
-			goto out_valid;
-		goto out_bad;
-	}
 	if (error)
 		goto out_bad;
 
@@ -496,7 +531,7 @@
 }
 
 struct dentry_operations nfs_dentry_operations = {
-	nfs_lookup_revalidate,	/* d_validate(struct dentry *) */
+	nfs_lookup_revalidate,	/* d_revalidate(struct dentry *, int) */
 	NULL,			/* d_hash */
 	NULL,			/* d_compare */
 	nfs_dentry_delete,	/* d_delete(struct dentry *) */
diff -u --recursive --new-file v2.2.7/linux/fs/nfs/file.c linux/fs/nfs/file.c
--- v2.2.7/linux/fs/nfs/file.c	Tue Mar 23 14:35:48 1999
+++ linux/fs/nfs/file.c	Sat May  8 20:01:19 1999
@@ -46,9 +46,9 @@
 	NULL,			/* select - default */
 	NULL,			/* ioctl - default */
 	nfs_file_mmap,		/* mmap */
-	NULL,			/* no special open is needed */
+	nfs_open,		/* open */
 	nfs_file_flush,		/* flush */
-	NULL,			/* release */
+	nfs_release,		/* release */
 	nfs_fsync,		/* fsync */
 	NULL,			/* fasync */
 	NULL,			/* check_media_change */
diff -u --recursive --new-file v2.2.7/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.2.7/linux/fs/nfs/inode.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/nfs/inode.c	Sat May  8 20:00:46 1999
@@ -696,6 +696,22 @@
 }
 
 /*
+ * These are probably going to contain hooks for
+ * allocating and releasing RPC credentials for
+ * the file. I'll have to think about Tronds patch
+ * a bit more..
+ */
+int nfs_open(struct inode *inode, struct file *filp)
+{
+	return 0;
+}
+
+int nfs_release(struct inode *inode, struct file *filp)
+{
+	return 0;
+}
+
+/*
  * This function is called whenever some part of NFS notices that
  * the cached attributes have to be refreshed.
  */
diff -u --recursive --new-file v2.2.7/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.2.7/linux/fs/proc/array.c	Tue Mar 23 14:35:48 1999
+++ linux/fs/proc/array.c	Mon May 10 10:05:18 1999
@@ -896,7 +896,7 @@
 
 	return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
 %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
-%lu %lu %lu %lu %lu %lu %lu %lu %d\n",
+%lu %lu %lu %lu %lu %lu %lu %lu %d %d\n",
 		pid,
 		tsk->comm,
 		state,
@@ -938,7 +938,8 @@
 		wchan,
 		tsk->nswap,
 		tsk->cnswap,
-		tsk->exit_signal);
+		tsk->exit_signal,
+		tsk->processor);
 }
 		
 static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
diff -u --recursive --new-file v2.2.7/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- v2.2.7/linux/fs/smbfs/dir.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/smbfs/dir.c	Sat May  8 17:56:37 1999
@@ -191,14 +191,14 @@
 /*
  * Dentry operations routines
  */
-static int smb_lookup_validate(struct dentry *);
+static int smb_lookup_validate(struct dentry *, int);
 static int smb_hash_dentry(struct dentry *, struct qstr *);
 static int smb_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
 static void smb_delete_dentry(struct dentry *);
 
 static struct dentry_operations smbfs_dentry_operations =
 {
-	smb_lookup_validate,	/* d_validate(struct dentry *) */
+	smb_lookup_validate,	/* d_revalidate(struct dentry *) */
 	smb_hash_dentry,	/* d_hash */
 	smb_compare_dentry,	/* d_compare */
 	smb_delete_dentry	/* d_delete(struct dentry *) */
@@ -208,7 +208,7 @@
  * This is the callback when the dcache has a lookup hit.
  */
 static int
-smb_lookup_validate(struct dentry * dentry)
+smb_lookup_validate(struct dentry * dentry, int flags)
 {
 	struct inode * inode = dentry->d_inode;
 	unsigned long age = jiffies - dentry->d_time;
diff -u --recursive --new-file v2.2.7/linux/fs/super.c linux/fs/super.c
--- v2.2.7/linux/fs/super.c	Fri Apr 16 14:47:31 1999
+++ linux/fs/super.c	Mon May 10 10:08:51 1999
@@ -1131,6 +1131,7 @@
 			sb = get_empty_super(); /* "can't fail" */
 			sb->s_dev = get_unnamed_dev();
 			sb->s_flags = root_mountflags;
+			sema_init(&sb->s_vfs_rename_sem,1);
 			vfsmnt = add_vfsmnt(sb, "/dev/root", "/");
 			if (vfsmnt) {
 				if (nfs_root_mount(sb) >= 0) {
@@ -1156,12 +1157,22 @@
 
 #ifdef CONFIG_BLK_DEV_FD
 	if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
+#ifdef CONFIG_BLK_DEV_RAM
+		extern int rd_doload;
+#endif
 		floppy_eject();
 #ifndef CONFIG_BLK_DEV_RAM
 		printk(KERN_NOTICE "(Warning, this kernel has no ramdisk support)\n");
+#else
+		/* rd_doload is 2 for a dual initrd/ramload setup */
+		if(rd_doload==2)
+			rd_load_secondary();
+		else
 #endif
-		printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
-		wait_for_keypress();
+		{
+			printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
+			wait_for_keypress();
+		}
 	}
 #endif
 
diff -u --recursive --new-file v2.2.7/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c
--- v2.2.7/linux/fs/umsdos/dir.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/umsdos/dir.c	Sat May  8 17:56:37 1999
@@ -30,7 +30,7 @@
  */
 
 /* nothing for now ... */
-static int umsdos_dentry_validate(struct dentry *dentry)
+static int umsdos_dentry_validate(struct dentry *dentry, int flags)
 {
 	return 1;
 }
@@ -46,7 +46,7 @@
 
 struct dentry_operations umsdos_dentry_operations =
 {
-	umsdos_dentry_validate,	/* d_validate(struct dentry *) */
+	umsdos_dentry_validate,	/* d_revalidate(struct dentry *, int) */
 	NULL,			/* d_hash */
 	NULL,			/* d_compare */
 	umsdos_dentry_dput,	/* d_delete(struct dentry *) */
diff -u --recursive --new-file v2.2.7/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.2.7/linux/fs/vfat/namei.c	Wed Apr 28 11:37:31 1999
+++ linux/fs/vfat/namei.c	Sat May  8 17:56:37 1999
@@ -71,7 +71,7 @@
 static int vfat_hash(struct dentry *parent, struct qstr *qstr);
 static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b);
 static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b);
-static int vfat_revalidate(struct dentry *dentry);
+static int vfat_revalidate(struct dentry *dentry, int);
 
 static struct dentry_operations vfat_dentry_ops[4] = {
 	{
@@ -106,7 +106,7 @@
 	MOD_DEC_USE_COUNT;
 }
 
-static int vfat_revalidate(struct dentry *dentry)
+static int vfat_revalidate(struct dentry *dentry, int flags)
 {
 	PRINTK1(("vfat_revalidate: %s\n", dentry->d_name.name));
 	if (dentry->d_time == dentry->d_parent->d_inode->i_version) {
diff -u --recursive --new-file v2.2.7/linux/include/asm-alpha/fpu.h linux/include/asm-alpha/fpu.h
--- v2.2.7/linux/include/asm-alpha/fpu.h	Tue Mar 17 22:18:15 1998
+++ linux/include/asm-alpha/fpu.h	Mon May 10 09:55:21 1999
@@ -81,6 +81,18 @@
 	return fp;
 }
 
+static inline unsigned long
+ieee_fpcr_to_swcr(unsigned long fp)
+{
+	unsigned long sw;
+	sw = (fp >> 35) & IEEE_STATUS_MASK;
+	sw |= (~fp >> 48) & (IEEE_TRAP_ENABLE_INV
+			     | IEEE_TRAP_ENABLE_DZE
+			     | IEEE_TRAP_ENABLE_OVF);
+	sw |= (~fp >> 57) & (IEEE_TRAP_ENABLE_UNF | IEEE_TRAP_ENABLE_INE);
+	return sw;
+}
+
 #ifdef __KERNEL__
 
 /* The following two functions don't need trapb/excb instructions
diff -u --recursive --new-file v2.2.7/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h
--- v2.2.7/linux/include/asm-alpha/pgtable.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-alpha/pgtable.h	Mon May 10 09:55:21 1999
@@ -167,19 +167,6 @@
 
 #else /* __SMP__ */
 
-/* ipi_msg_flush_tb is owned by the holder of the global kernel lock. */
-struct ipi_msg_flush_tb_struct {
-	volatile unsigned int flush_tb_mask;
-	union {
-		struct mm_struct *	flush_mm;
-		struct vm_area_struct *	flush_vma;
-	} p;
-	unsigned long flush_addr;
-	unsigned long flush_end;
-};
-
-extern struct ipi_msg_flush_tb_struct ipi_msg_flush_tb;
-
 extern void flush_tlb_all(void);
 extern void flush_tlb_mm(struct mm_struct *);
 extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
diff -u --recursive --new-file v2.2.7/linux/include/asm-alpha/semaphore.h linux/include/asm-alpha/semaphore.h
--- v2.2.7/linux/include/asm-alpha/semaphore.h	Wed Apr 28 11:37:31 1999
+++ linux/include/asm-alpha/semaphore.h	Fri May  7 10:55:26 1999
@@ -190,7 +190,7 @@
 		"	stl_c	$28,%1\n"
 		"	beq	$28,2f\n"
 		"	mb\n"
-		"	ble	$27,3f\n"
+		"	ble	$24,3f\n"
 		"4:\n"
 		".section .text2,\"ax\"\n"
 		"2:	br	1b\n"
diff -u --recursive --new-file v2.2.7/linux/include/asm-alpha/system.h linux/include/asm-alpha/system.h
--- v2.2.7/linux/include/asm-alpha/system.h	Tue Jan 19 11:32:52 1999
+++ linux/include/asm-alpha/system.h	Mon May 10 09:55:21 1999
@@ -97,12 +97,15 @@
 
 extern void halt(void) __attribute__((noreturn));
 
-#define switch_to(prev,next) do {					\
-	current = next;							\
-	alpha_switch_to((unsigned long) &current->tss - IDENT_ADDR);	\
+#define switch_to(prev,next,last)			\
+do {							\
+	unsigned long pcbb;				\
+	current = (next);				\
+	pcbb = virt_to_phys(&current->tss);		\
+	(last) = alpha_switch_to(pcbb, (prev));		\
 } while (0)
 
-extern void alpha_switch_to(unsigned long pctxp);
+extern struct task_struct* alpha_switch_to(unsigned long, struct task_struct*);
 
 #define mb() \
 __asm__ __volatile__("mb": : :"memory")
@@ -119,6 +122,34 @@
 #define draina() \
 __asm__ __volatile__ ("call_pal %0 #draina" : : "i" (PAL_draina) : "memory")
 
+enum implver_enum {
+	IMPLVER_EV4,
+	IMPLVER_EV5,
+	IMPLVER_EV6
+};
+
+#ifdef CONFIG_ALPHA_GENERIC
+#define implver()				\
+({ unsigned long __implver;			\
+   __asm__ ("implver %0" : "=r"(__implver));	\
+   (enum implver_enum) __implver; })
+#else
+/* Try to eliminate some dead code.  */
+#ifdef CONFIG_ALPHA_EV4
+#define implver() IMPLVER_EV4
+#endif
+#ifdef CONFIG_ALPHA_EV5
+#define implver() IMPLVER_EV5
+#endif
+#ifdef CONFIG_ALPHA_EV6
+#define implver() IMPLVER_EV6
+#endif
+#endif
+
+#define amask(mask)						\
+({ unsigned long __amask, __input = (mask);			\
+   __asm__ ("amask %1,%0" : "=r"(__amask) : "rI"(__input));	\
+   __amask; })
 
 static inline unsigned long 
 wrperfmon(unsigned long perf_fun, unsigned long arg)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/a.out.h linux/include/asm-arm/a.out.h
--- v2.2.7/linux/include/asm-arm/a.out.h	Fri Jan  8 22:36:15 1999
+++ linux/include/asm-arm/a.out.h	Sat May  8 11:06:57 1999
@@ -26,7 +26,9 @@
 
 #define M_ARM 103
 
+#ifdef __KERNEL__
 #include <asm/arch/a.out.h>
+#endif
 
 #ifndef LIBRARY_START_TEXT
 #define LIBRARY_START_TEXT	(0x00c00000)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/a.out.h linux/include/asm-arm/arch-arc/a.out.h
--- v2.2.7/linux/include/asm-arm/arch-arc/a.out.h	Fri Jan  8 22:36:17 1999
+++ linux/include/asm-arm/arch-arc/a.out.h	Sat May  8 11:06:57 1999
@@ -1,16 +1,14 @@
 /*
  * linux/include/asm-arm/arch-arc/a.out.h
  *
- * Copyright (C) 1996 Russell King
- *
- * Acorn Archimedes/A5000 a.out.h specs
+ * Copyright (C) 1996-1999 Russell King
  */
 #ifndef __ASM_ARCH_A_OUT_H
 #define __ASM_ARCH_A_OUT_H
 
-#ifdef __KERNEL__
-#define STACK_TOP		(0x01a00000)
-#endif
+#include <asm/arch/memory.h>
+
+#define STACK_TOP	TASK_SIZE
 
 #endif
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/hardware.h linux/include/asm-arm/arch-arc/hardware.h
--- v2.2.7/linux/include/asm-arm/arch-arc/hardware.h	Fri Jan  8 22:36:18 1999
+++ linux/include/asm-arm/arch-arc/hardware.h	Sat May  8 11:06:57 1999
@@ -1,7 +1,7 @@
 /*
  * linux/include/asm-arm/arch-arc/hardware.h
  *
- * Copyright (C) 1996 Russell King.
+ * Copyright (C) 1996-1999 Russell King.
  *
  * This file contains the hardware definitions of the
  * Acorn Archimedes/A5000 machines.
@@ -9,21 +9,20 @@
  * Modifications:
  *  04-04-1998	PJB/RMK	Merged arc and a5k versions
  */
-
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
 #include <linux/config.h>
 
+#include <asm/arch/memory.h>
+
 /*
  * What hardware must be present - these can be tested by the kernel
  * source.
  */
 #define HAS_IOC
-#include <asm/ioc.h>
 #define HAS_MEMC
 #include <asm/memc.h>
-#define HAS_MEMC1A
 #define HAS_VIDC
 
 /*
@@ -56,6 +55,12 @@
  * for use with inb/outb
  */
 #define IO_VIDC_BASE		0x80100000
+#ifdef CONFIG_ARCH_A5K
+#define IOEB_VID_CTL		0x800d4012
+#define IOEB_PRESENT		0x800d4014
+#define IOEB_PSCLR		0x800d4016
+#define IOEB_MONTYPE		0x800d401c
+#endif
 #ifdef CONFIG_ARCH_ARC
 #define LATCHAADDR		0x80094010
 #define LATCHBADDR		0x80094006
@@ -66,6 +71,14 @@
 #define IO_EC_IOC_BASE		0x80090000
 #define IO_EC_MEMC_BASE		0x80000000
 
+#ifdef CONFIG_ARCH_ARC
+/* A680 hardware */
+#define WD1973_BASE		0x03290000
+#define WD1973_LATCH		0x03350000
+#define Z8530_BASE		0x032b0008
+#define SCSI_BASE		0x03100000
+#endif
+
 /*
  * IO definitions
  */
@@ -77,11 +90,8 @@
 /*
  * RAM definitions
  */
-#define MAPTOPHYS(a)		(((unsigned long)a & 0x007fffff) + PAGE_OFFSET)
-#define KERNTOPHYS(a)		((((unsigned long)(&a)) & 0x007fffff) + PAGE_OFFSET)
 #define GET_MEMORY_END(p)	(PAGE_OFFSET + (p->u1.s.page_size) * (p->u1.s.nr_pages))
 #define PARAMS_BASE		(PAGE_OFFSET + 0x7c000)
-#define KERNEL_BASE		(PAGE_OFFSET + 0x80000)
 
 #else
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/irq.h linux/include/asm-arm/arch-arc/irq.h
--- v2.2.7/linux/include/asm-arm/arch-arc/irq.h	Wed Sep  9 14:51:10 1998
+++ linux/include/asm-arm/arch-arc/irq.h	Sat May  8 11:06:57 1999
@@ -10,6 +10,9 @@
  *   11-01-1998	RMK	Added mask_and_ack_irq
  *   22-08-1998	RMK	Restructured IRQ routines
  */
+#include <asm/ioc.h>
+
+#define fixup_irq(x) (x)
 
 static void arc_mask_irq_ack_a(unsigned int irq)
 {
@@ -108,10 +111,17 @@
 	outb(0, IOC_FIQMASK);
 
 	for (irq = 0; irq < NR_IRQS; irq++) {
-		switch (irq & 0xf8) {
+		switch (irq) {
 		case 0 ... 6:
 			irq_desc[irq].probe_ok = 1;
+			irq_desc[irq].valid    = 1;
+			irq_desc[irq].mask_ack = arc_mask_irq_ack_a;
+			irq_desc[irq].mask     = arc_mask_irq_a;
+			irq_desc[irq].unmask   = arc_unmask_irq_a;
+			break;
+
 		case 7:
+			irq_desc[irq].noautoenable = 1;
 			irq_desc[irq].valid    = 1;
 			irq_desc[irq].mask_ack = arc_mask_irq_ack_a;
 			irq_desc[irq].mask     = arc_mask_irq_a;
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/keyboard.h linux/include/asm-arm/arch-arc/keyboard.h
--- v2.2.7/linux/include/asm-arm/arch-arc/keyboard.h	Wed Apr 28 11:37:31 1999
+++ linux/include/asm-arm/arch-arc/keyboard.h	Sat May  8 11:06:57 1999
@@ -11,7 +11,6 @@
 
 #define NR_SCANCODES 128
 
-extern int a5kkbd_translate(unsigned char scancode, unsigned char *keycode_p, char *up_flag_p);
 extern void a5kkbd_leds(unsigned char leds);
 extern void a5kkbd_init_hw(void);
 extern unsigned char a5kkbd_sysrq_xlate[NR_SCANCODES];
@@ -19,11 +18,7 @@
 #define kbd_setkeycode(sc,kc)		(-EINVAL)
 #define kbd_getkeycode(sc)		(-EINVAL)
 
-/* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode)
- * Returns  : 0 to ignore scancode, *keycode set to keycode, *up_flag
- *            set to 0200 if scancode indicates release
- */
-#define kbd_translate(sc, kcp, ufp, rm)	a5kkbd_translate(sc, kcp, ufp)
+#define kbd_translate(sc, kcp, rm)	({ *(kcp) = (sc); 1; })
 #define kbd_unexpected_up(kc)		(0200)
 #define kbd_leds(leds)			a5kkbd_leds(leds)
 #define kbd_init_hw()			a5kkbd_init_hw()
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/memory.h linux/include/asm-arm/arch-arc/memory.h
--- v2.2.7/linux/include/asm-arm/arch-arc/memory.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-arc/memory.h	Sat May  8 11:06:57 1999
@@ -0,0 +1,41 @@
+/*
+ * linux/include/asm-arm/arch-arc/memory.h
+ *
+ * Copyright (c) 1996-1999 Russell King.
+ *
+ * Changelog:
+ *  22-Nov-1996	RMK	Created
+ *  21-Mar-1999	RMK	Renamed to memory.h
+ *		RMK	Moved PAGE_OFFSET and TASK_SIZE here
+ */
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * User space: 26MB
+ */
+#define TASK_SIZE	(0x01a00000UL)
+
+/*
+ * Page offset: 32MB
+ */
+#define PAGE_OFFSET	(0x02000000UL)
+
+#define __virt_to_phys__is_a_macro
+#define __virt_to_phys(vpage) vpage
+#define __phys_to_virt__is_a_macro
+#define __phys_to_virt(ppage) ppage
+
+/*
+ * Virtual view <-> DMA view memory address translations
+ * virt_to_bus: Used to translate the virtual address to an
+ *              address suitable to be passed to set_dma_addr
+ * bus_to_virt: Used to convert an address for DMA operations
+ *              to an address that the kernel can use.
+ */
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x)	(x)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x)	(x)
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/mmu.h linux/include/asm-arm/arch-arc/mmu.h
--- v2.2.7/linux/include/asm-arm/arch-arc/mmu.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-arc/mmu.h	Wed Dec 31 16:00:00 1969
@@ -1,29 +0,0 @@
-/*
- * linux/include/asm-arm/arch-arc/mmu.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  22-11-1996	RMK	Created
- */
-#ifndef __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
-
-#define __virt_to_phys__is_a_macro
-#define __virt_to_phys(vpage) vpage
-#define __phys_to_virt__is_a_macro
-#define __phys_to_virt(ppage) ppage
-
-/*
- * Virtual view <-> DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- *              address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- *              to an address that the kernel can use.
- */
-#define __virt_to_bus__is_a_macro
-#define __virt_to_bus(x)	(x)
-#define __bus_to_virt__is_a_macro
-#define __bus_to_virt(x)	(x)
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/oldlatches.h linux/include/asm-arm/arch-arc/oldlatches.h
--- v2.2.7/linux/include/asm-arm/arch-arc/oldlatches.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-arc/oldlatches.h	Sat May  8 11:06:57 1999
@@ -34,6 +34,8 @@
 /* newval=(oldval & mask)|newdata */
 void oldlatch_aupdate(unsigned char mask,unsigned char newdata);
 
+void oldlatch_init(void);
+
 #elif defined(CONFIG_ARCH_A5K)
 
 #ifdef __need_oldlatches
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/processor.h linux/include/asm-arm/arch-arc/processor.h
--- v2.2.7/linux/include/asm-arm/arch-arc/processor.h	Fri Jan  8 22:36:20 1999
+++ linux/include/asm-arm/arch-arc/processor.h	Sat May  8 11:06:57 1999
@@ -1,15 +1,18 @@
 /*
  * linux/include/asm-arm/arch-arc/processor.h
  *
- * Copyright (c) 1996 Russell King.
+ * Copyright (c) 1996-1999 Russell King.
  *
  * Changelog:
- *  10-09-1996	RMK	Created
+ *  10-Sep-1996	RMK	Created
+ *  21-Mar-1999	RMK	Added asm/arch/memory.h
  */
 
 #ifndef __ASM_ARCH_PROCESSOR_H
 #define __ASM_ARCH_PROCESSOR_H
 
+#include <asm/arch/memory.h>
+
 /*
  * Bus types
  */
@@ -18,17 +21,9 @@
 #define MCA_bus 0
 #define MCA_bus__is_a_macro /* for versions in ksyms.c */
 
-/*
- * User space: 26MB
- */
-#define TASK_SIZE	(0x01a00000UL)
-
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
 #define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
-
-#define INIT_MMAP \
-{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/time.h linux/include/asm-arm/arch-arc/time.h
--- v2.2.7/linux/include/asm-arm/arch-arc/time.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-arc/time.h	Sat May  8 11:06:57 1999
@@ -8,6 +8,9 @@
  *  10-Oct-1996	RMK	Brought up to date with arch-sa110eval
  *  04-Dec-1997	RMK	Updated for new arch/arm/time.c
  */
+#include <asm/ioc.h>
+
+static long last_rtc_update = 0;	/* last time the cmos clock got updated */
 
 extern __inline__ unsigned long gettimeoffset (void)
 {
@@ -51,46 +54,140 @@
 	return offset;
 }
 
-/*
- * No need to reset the timer at every irq
- */
-#define reset_timer() 1
+extern int iic_control (unsigned char, int, char *, int);
 
-/*
- * Updating of the RTC.  We don't currently write the time to the
- * CMOS clock.
- */
-#define update_rtc()
+static int set_rtc_time(unsigned long nowtime)
+{
+	char buf[5], ctrl;
+
+	if (iic_control(0xa1, 0, &ctrl, 1) != 0)
+		printk("RTC: failed to read control reg\n");
+
+	/*
+	 * Reset divider
+	 */
+	ctrl |= 0x80;
+
+	if (iic_control(0xa0, 0, &ctrl, 1) != 0)
+		printk("RTC: failed to stop the clock\n");
+
+	/*
+	 * We only set the time - we don't set the date.
+	 * This means that there is the possibility once
+	 * a day for the correction to disrupt the date.
+	 * We really ought to write the time and date, or
+	 * nothing at all.
+	 */
+	buf[0] = 0;
+	buf[1] = nowtime % 60;		nowtime /= 60;
+	buf[2] = nowtime % 60;		nowtime /= 60;
+	buf[3] = nowtime % 24;
+
+	BIN_TO_BCD(buf[1]);
+	BIN_TO_BCD(buf[2]);
+	BIN_TO_BCD(buf[3]);
+
+	if (iic_control(0xa0, 1, buf, 4) != 0)
+		printk("RTC: Failed to set the time\n");
+
+	/*
+	 * Re-enable divider
+	 */
+	ctrl &= ~0x80;
+
+	if (iic_control(0xa0, 0, &ctrl, 1) != 0)
+		printk("RTC: failed to start the clock\n");
+
+	return 0;
+}
+
+extern __inline__ unsigned long get_rtc_time(void)
+{
+	unsigned int year, i;
+	char buf[8];
+
+	/*
+	 * The year is not part of the RTC counter
+	 * registers, and is stored in RAM.  This
+	 * means that it will not be automatically
+	 * updated.
+	 */
+	if (iic_control(0xa1, 0xc0, buf, 1) != 0)
+		printk("RTC: failed to read the year\n");
+
+	/*
+	 * If the year is before 1970, then the year
+	 * is actually 100 in advance.  This gives us
+	 * a year 2070 bug...
+	 */
+	year = 1900 + buf[0];
+	if (year < 1970)
+		year += 100;
+
+	/*
+	 * Read the time and date in one go - this
+	 * will ensure that we don't get any effects
+	 * due to carry (the RTC latches the counters
+	 * during a read).
+	 */
+	if (iic_control(0xa1, 2, buf, 5) != 0) {
+		printk("RTC: failed to read the time and date\n");
+		memset(buf, 0, sizeof(buf));
+	}
+
+	/*
+	 * The RTC combines years with date and weekday
+	 * with month.  We need to mask off this extra
+	 * information before converting the date to
+	 * binary.
+	 */
+	buf[4] &= 0x1f;
+	buf[3] &= 0x3f;
+
+	for (i = 0; i < 5; i++)
+		BCD_TO_BIN(buf[i]);
+
+	return mktime(year, buf[4], buf[3], buf[2], buf[1], buf[0]);
+}
+
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	do_timer(regs);
+
+	/* If we have an externally synchronized linux clock, then update
+	 * CMOS clock accordingly every ~11 minutes.  Set_rtc_mmss() has to be
+	 * called as close as possible to 500 ms before the new second starts.
+	 */
+	if ((time_status & STA_UNSYNC) == 0 &&
+	    xtime.tv_sec > last_rtc_update + 660 &&
+	    xtime.tv_usec >= 50000 - (tick >> 1) &&
+	    xtime.tv_usec < 50000 + (tick >> 1)) {
+		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 */
+	}
+}
+
+static struct irqaction timerirq = {
+	timer_interrupt,
+	0,
+	0,
+	"timer",
+	NULL,
+	NULL
+};
 
 /*
  * Set up timer interrupt, and return the current time in seconds.
  */
-extern __inline__ unsigned long setup_timer (void)
+extern __inline__ void setup_timer(void)
 {
-	extern int iic_control (unsigned char, int, char *, int);
-	unsigned int year, mon, day, hour, min, sec;
-	char buf[8];
-
 	outb(LATCH & 255, IOC_T0LTCHL);
 	outb(LATCH >> 8, IOC_T0LTCHH);
 	outb(0, IOC_T0GO);
 
-	iic_control (0xa0, 0xc0, buf, 1);
-	year = buf[0];
-	if ((year += 1900) < 1970)
-		year += 100;
-
-	iic_control (0xa0, 2, buf, 5);
-	mon  = buf[4] & 0x1f;
-	day  = buf[3] & 0x3f;
-	hour = buf[2];
-	min  = buf[1];
-	sec  = buf[0];
-	BCD_TO_BIN(mon);
-	BCD_TO_BIN(day);
-	BCD_TO_BIN(hour);
-	BCD_TO_BIN(min);
-	BCD_TO_BIN(sec);
+	xtime.tv_sec = get_rtc_time();
 
-	return mktime(year, mon, day, hour, min, sec);
+	setup_arm_irq(IRQ_TIMER, &timerirq);
 }
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/uncompress.h linux/include/asm-arm/arch-arc/uncompress.h
--- v2.2.7/linux/include/asm-arm/arch-arc/uncompress.h	Wed Sep  9 14:51:10 1998
+++ linux/include/asm-arm/arch-arc/uncompress.h	Sat May  8 11:06:57 1999
@@ -5,8 +5,6 @@
  */
 #define VIDMEM ((char *)0x02000000)
  
-#include "../arch/arm/drivers/char/font.h"
-
 int video_num_columns, video_num_lines, video_size_row;
 int white, bytes_per_char_h;
 extern unsigned long con_charconvtable[256];
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa110/a.out.h linux/include/asm-arm/arch-ebsa110/a.out.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa110/a.out.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa110/a.out.h	Sat May  8 11:06:57 1999
@@ -1,15 +1,16 @@
 /*
  * linux/include/asm-arm/arch-ebsa110/a.out.h
  *
- * Copyright (C) 1996 Russell King
+ * Copyright (C) 1996-1999 Russell King
  */
-
 #ifndef __ASM_ARCH_A_OUT_H
 #define __ASM_ARCH_A_OUT_H
 
-#ifdef __KERNEL__
-#define STACK_TOP		((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
-#endif
+#include <asm/arch/memory.h>
+
+#define STACK_TOP \
+	((current->personality == PER_LINUX_32BIT) ? \
+	 TASK_SIZE : 0x04000000)
 
 #endif
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa110/hardware.h linux/include/asm-arm/arch-ebsa110/hardware.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa110/hardware.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa110/hardware.h	Sat May  8 11:06:57 1999
@@ -1,19 +1,13 @@
 /*
  * linux/include/asm-arm/arch-ebsa110/hardware.h
  *
- * Copyright (C) 1996,1997,1998 Russell King.
+ * Copyright (C) 1996-1999 Russell King.
  *
  * This file contains the hardware definitions of the EBSA-110.
  */
-
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
-/*
- * What hardware must be present
- */
-#define HAS_PCIO
-
 #ifndef __ASSEMBLER__
 
 /*
@@ -23,28 +17,28 @@
 #define PIT_T2			((volatile unsigned char *)0xf2000009)
 #define PIT_T1			((volatile unsigned char *)0xf2000005)
 #define PIT_T0			((volatile unsigned char *)0xf2000001)
-#define PCIO_BASE		0xf0000000
 
 /*
  * Mapping areas
  */
 #define IO_BASE			0xe0000000
-#define IO_SIZE			0x20000000
-#define IO_START		0xe0000000
 
 /*
  * RAM definitions
  */
-#define MAPTOPHYS(a)		((unsigned long)(a) - PAGE_OFFSET)
-#define KERNTOPHYS(a)		((unsigned long)(&a))
-#define KERNEL_BASE		(0xc0008000)
 #define FLUSH_BASE_PHYS		0x40000000
 
 #else
 
-#define PCIO_BASE		0xf0000000
 #define IO_BASE			0
 
 #endif
+
+#define IO_SIZE			0x20000000
+#define IO_START		0xe0000000
+
+#define FLUSH_BASE		0xdf000000
+#define PCIO_BASE		0xf0000000
+
 #endif
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa110/irq.h linux/include/asm-arm/arch-ebsa110/irq.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa110/irq.h	Wed Sep  9 14:51:10 1998
+++ linux/include/asm-arm/arch-ebsa110/irq.h	Sat May  8 11:06:57 1999
@@ -11,6 +11,8 @@
 #define IRQ_MSET	((volatile unsigned char *)0xf2c00000)
 #define IRQ_MASK	((volatile unsigned char *)0xf2c00000)
 
+#define fixup_irq(x) (x)
+
 static void ebsa110_mask_and_ack_irq(unsigned int irq)
 {
 	*IRQ_MCLR = 1 << irq;
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa110/memory.h linux/include/asm-arm/arch-ebsa110/memory.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa110/memory.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa110/memory.h	Sat May  8 11:06:57 1999
@@ -0,0 +1,35 @@
+/*
+ * linux/include/asm-arm/arch-ebsa110/memory.h
+ *
+ * Copyright (c) 1996-1999 Russell King.
+ *
+ * Changelog:
+ *  20-Oct-1996	RMK	Created
+ *  31-Dec-1997	RMK	Fixed definitions to reduce warnings
+ *  21-Mar-1999	RMK	Renamed to memory.h
+ *		RMK	Moved TASK_SIZE and PAGE_OFFSET here
+ */
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * Task size: 3GB
+ */
+#define TASK_SIZE	(0xc0000000UL)
+
+/*
+ * Page offset: 3GB
+ */
+#define PAGE_OFFSET	(0xc0000000UL)
+
+#define __virt_to_phys__is_a_macro
+#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET)
+#define __phys_to_virt__is_a_macro
+#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET)
+
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x)	__virt_to_phys(x)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x)	__phys_to_virt(x)
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa110/mm-init.h linux/include/asm-arm/arch-ebsa110/mm-init.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa110/mm-init.h	Wed Sep  9 14:51:10 1998
+++ linux/include/asm-arm/arch-ebsa110/mm-init.h	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/mmap.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa110/mmu.h linux/include/asm-arm/arch-ebsa110/mmu.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa110/mmu.h	Wed Sep  9 14:51:10 1998
+++ linux/include/asm-arm/arch-ebsa110/mmu.h	Wed Dec 31 16:00:00 1969
@@ -1,23 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/mmu.h
- *
- * Copyright (c) 1996,1997,1998 Russell King.
- *
- * Changelog:
- *  20-10-1996	RMK	Created
- *  31-12-1997	RMK	Fixed definitions to reduce warnings
- */
-#ifndef __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
-
-#define __virt_to_phys__is_a_macro
-#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET)
-#define __phys_to_virt__is_a_macro
-#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET)
-
-#define __virt_to_bus__is_a_macro
-#define __virt_to_bus(x)	__virt_to_phys(x)
-#define __bus_to_virt__is_a_macro
-#define __bus_to_virt(x)	__phys_to_virt(x)
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa110/oldlatches.h linux/include/asm-arm/arch-ebsa110/oldlatches.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa110/oldlatches.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-ebsa110/oldlatches.h	Wed Dec 31 16:00:00 1969
@@ -1,9 +0,0 @@
-/*
- * Dummy oldlatches.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifdef __need_oldlatches
-#error "Old latches not present in this (rpc) machine"
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa110/processor.h linux/include/asm-arm/arch-ebsa110/processor.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa110/processor.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa110/processor.h	Sat May  8 11:06:57 1999
@@ -1,12 +1,17 @@
 /*
  * linux/include/asm-arm/arch-ebsa110/processor.h
  *
- * Copyright (C) 1996,1997,1998 Russell King
+ * Copyright (C) 1996-1999 Russell King
+ *
+ * Changelog:
+ *  21-Mar-1999	RMK	Added asm/arch/memory.h
  */
 
 #ifndef __ASM_ARCH_PROCESSOR_H
 #define __ASM_ARCH_PROCESSOR_H
 
+#include <asm/arch/memory.h>
+
 /*
  * Bus types
  */
@@ -15,17 +20,9 @@
 #define MCA_bus 0
 #define MCA_bus__is_a_macro /* for versions in ksyms.c */
 
-/*
- * User space: 3GB
- */
-#define TASK_SIZE	(0xc0000000UL)
-
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
 #define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
-
-#define INIT_MMAP \
-{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa110/time.h linux/include/asm-arm/arch-ebsa110/time.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa110/time.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa110/time.h	Sat May  8 11:06:57 1999
@@ -38,63 +38,67 @@
 	return 0;
 }
 
-#ifndef DIVISOR
-extern __inline__ int reset_timer (void)
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	*PIT_T1 = (PIT1_COUNT) & 0xff;
 	*PIT_T1 = (PIT1_COUNT) >> 8;
-	return 1;
-}
-#else
-extern __inline__ int reset_timer (void)
-{
-	static unsigned int divisor;
-#ifdef CONFIG_LEDS	
-	static int count = 50;
-#endif
-
-	*PIT_T1 = (PIT1_COUNT) & 0xff;
-	*PIT_T1 = (PIT1_COUNT) >> 8;
 
 #ifdef CONFIG_LEDS
-	if (--count == 0) {
-		count = 50;
-		leds_event(led_timer);
+	{
+		static int count = 50;
+		if (--count == 0) {
+			count = 50;
+			leds_event(led_timer);
+		}
 	}
 #endif
 
-	if (divisor == 0) {
-		divisor = DIVISOR - 1;
-		return 1;
+	{
+#ifdef DIVISOR
+		static unsigned int divisor;
+
+		if (divisor-- == 0) {
+			divisor = DIVISOR - 1;
+#else
+		{
+#endif
+			do_timer(regs);
+		}
 	}
-	divisor -= 1;
-	return 0;
 }
-#endif
 
-/*
- * We don't have a RTC to update!
- */
-#define update_rtc()
+static struct irqaction timerirq = {
+	timer_interrupt,
+	0,
+	0,
+	"timer",
+	NULL,
+	NULL
+};
 
 /*
  * Set up timer interrupt, and return the current time in seconds.
  */
-extern __inline__ unsigned long setup_timer (void)
+extern __inline__ void setup_timer(void)
 {
 	/*
 	 * Timer 1, mode 0, 16-bit, autoreload
 	 */
 	*PIT_CTRL = 0x70;
+
 	/*
 	 * Refresh counter clocked at 47.8MHz/7 = 146.4ns
 	 * We want centi-second interrupts
 	 */
-	reset_timer ();
+	*PIT_T1 = (PIT1_COUNT) & 0xff;
+	*PIT_T1 = (PIT1_COUNT) >> 8;
+
 	/*
 	 * Default the date to 1 Jan 1970 0:0:0
 	 * You will have to run a time daemon to set the
 	 * clock correctly at bootup
 	 */
-	return mktime(1970, 1, 1, 0, 0, 0);
+	xtime.tv_sec = mktime(1970, 1, 1, 0, 0, 0);
+
+	setup_arm_irq(IRQ_TIMER, &timerirq);
 }
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/a.out.h linux/include/asm-arm/arch-ebsa285/a.out.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/a.out.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/a.out.h	Sat May  8 11:06:57 1999
@@ -1,15 +1,16 @@
 /*
  * linux/include/asm-arm/arch-ebsa110/a.out.h
  *
- * Copyright (C) 1996 Russell King
+ * Copyright (C) 1996-1999 Russell King
  */
-
 #ifndef __ASM_ARCH_A_OUT_H
 #define __ASM_ARCH_A_OUT_H
 
-#ifdef __KERNEL__
-#define STACK_TOP		((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
-#endif
+#include <asm/arch/memory.h>
+
+#define STACK_TOP \
+	((current->personality == PER_LINUX_32BIT) ? \
+	 TASK_SIZE : 0x04000000)
 
 #endif
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/dma.h linux/include/asm-arm/arch-ebsa285/dma.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/dma.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/dma.h	Sat May  8 11:06:57 1999
@@ -3,8 +3,8 @@
  *
  * Architecture DMA routines
  *
- * Copyright (C) 1998 Russell King
- * Copyright (C) 1998 Philip Blundell
+ * Copyright (C) 1998,1999 Russell King
+ * Copyright (C) 1998,1999 Philip Blundell
  */
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H
@@ -15,12 +15,16 @@
 #define MAX_DMA_ADDRESS		0xffffffff
 
 /*
- * The 21285 has two internal DMA channels; we call these 0 and 1.
+ * The 21285 has two internal DMA channels; we call these 8 and 9.
  * On CATS hardware we have an additional eight ISA dma channels
- * numbered 2..9.
+ * numbered 0..7.
  */
+#define _ISA_DMA(x)		(0+(x))
+#define _DC21285_DMA(x)		(8+(x))
+
 #define MAX_DMA_CHANNELS	10
-#define DMA_ISA_BASE		2
-#define DMA_FLOPPY		(DMA_ISA_BASE + 2)
+
+#define DMA_FLOPPY		_ISA_DMA(2)
+#define DMA_ISA_CASCADE		_ISA_DMA(4)
 
 #endif /* _ASM_ARCH_DMA_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/hardware.h linux/include/asm-arm/arch-ebsa285/hardware.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/hardware.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/hardware.h	Sat May  8 11:06:57 1999
@@ -1,47 +1,135 @@
 /*
  * linux/include/asm-arm/arch-ebsa285/hardware.h
  *
- * Copyright (C) 1998 Russell King.
+ * Copyright (C) 1998-1999 Russell King.
  *
  * This file contains the hardware definitions of the EBSA-285.
  */
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
 
+#include <linux/config.h>
+#include <asm/arch/memory.h>
 
-/*    Logical    Physical
+#ifdef CONFIG_HOST_FOOTBRIDGE
+/*   Virtual      Physical
  * 0xfff00000	0x40000000	X-Bus
- * 0xffe00000	0x7c000000	PCI I/O space
+ * 0xff000000	0x7c000000	PCI I/O space
  *
  * 0xfe000000	0x42000000	CSR
  * 0xfd000000	0x78000000	Outbound write flush
  * 0xfc000000	0x79000000	PCI IACK/special space
  *
- * 0xf9000000	0x7a010000	PCI Config type 1
- * 0xf8000000	0x7b010000	PCI Config type 0
+ * 0xf9000000	0x7a000000	PCI Config type 1
+ * 0xf8000000	0x7b000000	PCI Config type 0
  * 
  */
+#define XBUS_SIZE		0x00100000
+#define XBUS_BASE		0xfff00000
 
-#include <asm/dec21285.h>
- 
-#define IO_BASE			0xe0000000
-#define PCIO_BASE		0xffe00000
-#define PCI_IACK		0xfc000000 
+#define PCIO_SIZE		0x00100000
+#define PCIO_BASE		0xff000000
 
-#define XBUS_LEDS		((volatile unsigned char *)0xfff12000)
+#define ARMCSR_SIZE		0x01000000
+#define ARMCSR_BASE		0xfe000000
+
+#define WFLUSH_SIZE		0x01000000
+#define WFLUSH_BASE		0xfd000000
+
+#define PCIIACK_SIZE		0x01000000
+#define PCIIACK_BASE		0xfc000000
+
+#define PCICFG1_SIZE		0x01000000
+#define PCICFG1_BASE		0xf9000000
+
+#define PCICFG0_SIZE		0x01000000
+#define PCICFG0_BASE		0xf8000000
+
+#define PCIMEM_SIZE		0x18000000
+#define PCIMEM_BASE		0xe0000000
+
+#define FLUSH_SIZE		0x00100000
+#define FLUSH_BASE		0xdf000000
+
+#define FLASH_SIZE		0x00400000
+#define FLASH_BASE		0xd8000000
+
+#elif defined(CONFIG_ARCH_CO285)
+
+#define PCIMEM_SIZE		0x80000000
+#define PCIMEM_BASE		0x80000000
+
+#define FLASH_SIZE		0x01000000
+#define FLASH_BASE		0x7f000000
+
+#define FLUSH_SIZE		0x00100000
+#define FLUSH_BASE		0x7e000000
+
+#define WFLUSH_SIZE		0x01000000
+#define WFLUSH_BASE		0x7d000000
+
+#define ARMCSR_SIZE		0x00100000
+#define ARMCSR_BASE		0x7cf00000
+
+#define XBUS_SIZE		0x00020000
+#define XBUS_BASE		0x7cee0000
+
+#define PCIO_SIZE		0x00010000
+#define PCIO_BASE		0x7ced0000
+
+#else
+
+#error Add your add-in architecture here
+
+#endif
+
+#define XBUS_LEDS		((volatile unsigned char *)(XBUS_BASE + 0x12000))
 #define XBUS_LED_AMBER		(1 << 0)
 #define XBUS_LED_GREEN		(1 << 1)
 #define XBUS_LED_RED		(1 << 2)
 #define XBUS_LED_TOGGLE		(1 << 8)
 
-#define XBUS_SWITCH		((volatile unsigned char *)0xfff12000)
+#define XBUS_SWITCH		((volatile unsigned char *)(XBUS_BASE + 0x12000))
 #define XBUS_SWITCH_SWITCH	((*XBUS_SWITCH) & 15)
 #define XBUS_SWITCH_J17_13	((*XBUS_SWITCH) & (1 << 4))
 #define XBUS_SWITCH_J17_11	((*XBUS_SWITCH) & (1 << 5))
 #define XBUS_SWITCH_J17_9	((*XBUS_SWITCH) & (1 << 6))
 
-#define KERNTOPHYS(a)		((unsigned long)(&a))
-
 #define PARAMS_OFFSET		0x0100
 #define PARAMS_BASE		(PAGE_OFFSET + PARAMS_OFFSET)
 
 #define FLUSH_BASE_PHYS		0x50000000
 
+
+/* PIC irq control */
+#define PIC_LO			0x20
+#define PIC_MASK_LO		0x21
+#define PIC_HI			0xA0
+#define PIC_MASK_HI		0xA1
+
+/* GPIO pins */
+#define GPIO_CCLK		0x800
+#define GPIO_DSCLK		0x400
+#define GPIO_E2CLK		0x200
+#define GPIO_IOLOAD		0x100
+#define GPIO_RED_LED		0x080
+#define GPIO_WDTIMER		0x040
+#define GPIO_DATA		0x020
+#define GPIO_IOCLK		0x010
+#define GPIO_DONE		0x008
+#define GPIO_FAN		0x004
+#define GPIO_GREEN_LED		0x002
+#define GPIO_RESET		0x001
+
+/* CPLD pins */
+#define CPLD_DSRESET		8
+#define CPLD_UNMUTE		2
+
+#ifndef __ASSEMBLY__
+extern void gpio_modify_op(int mask, int set);
+extern void gpio_modify_io(int mask, int in);
+extern int  gpio_read(void);
+extern void cpld_modify(int mask, int set);
+#endif
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/io.h linux/include/asm-arm/arch-ebsa285/io.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/io.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/io.h	Sat May  8 11:06:57 1999
@@ -16,34 +16,37 @@
  * has the constant-optimised IO
  */
 #undef	ARCH_IO_DELAY
+#define ARCH_READWRITE
 
 /*
  * Dynamic IO functions - let the compiler
  * optimize the expressions
  */
-#define DECLARE_DYN_OUT(fnsuffix,instr,typ)					\
-extern __inline__ void __out##fnsuffix (unsigned int value, unsigned int port)	\
-{										\
-	__asm__ __volatile__(							\
-	"str%?" ##instr## "	%0, [%1, %2]		@ out"###fnsuffix	\
-	: 									\
-	: "r" (value), "r" (PCIO_BASE), typ (port));				\
-}
-
-#define DECLARE_DYN_IN(sz,fnsuffix,instr,typ)					\
-extern __inline__ unsigned sz __in##fnsuffix (unsigned int port)		\
-{										\
-	unsigned long value;							\
-	__asm__ __volatile__(							\
-	"ldr%?" ##instr## "	%0, [%1, %2]		@ in"###fnsuffix	\
-	: "=&r" (value)								\
-	: "r" (PCIO_BASE), typ (port));						\
-	return (unsigned sz)value;						\
-}
-
-extern __inline__ unsigned int __ioaddr (unsigned int port)			\
-{										\
-	return (unsigned int)(PCIO_BASE + port);				\
+#define DECLARE_DYN_OUT(fnsuffix,instr,typ)				\
+extern __inline__ void							\
+__out##fnsuffix (unsigned int value, unsigned int port)			\
+{									\
+	__asm__ __volatile__(						\
+	"str%?" ##instr## "	%0, [%1, %2]	@ out"###fnsuffix	\
+	: 								\
+	: "r" (value), "r" (PCIO_BASE), typ (port));			\
+}
+
+#define DECLARE_DYN_IN(sz,fnsuffix,instr,typ)				\
+extern __inline__ unsigned sz						\
+__in##fnsuffix (unsigned int port)					\
+{									\
+	unsigned long value;						\
+	__asm__ __volatile__(						\
+	"ldr%?" ##instr## "	%0, [%1, %2]	@ in"###fnsuffix	\
+	: "=&r" (value)							\
+	: "r" (PCIO_BASE), typ (port));					\
+	return (unsigned sz)value;					\
+}
+
+extern __inline__ unsigned int __ioaddr (unsigned int port)		\
+{									\
+	return (unsigned int)(PCIO_BASE + port);			\
 }
 
 #define DECLARE_IO(sz,fnsuffix,instr,typ)	\
@@ -64,65 +67,65 @@
  * These have to be macros for the 'J' constraint to work -
  * +/-4096 immediate operand.
  */
-#define __outbc(value,port)							\
-({										\
-	__asm__ __volatile__(							\
-	"str%?b	%0, [%1, %2]				@ outbc"		\
-	:									\
-	: "r" (value), "r" (PCIO_BASE), "Jr" (port));				\
-})
-
-#define __inbc(port)								\
-({										\
-	unsigned char result;							\
-	__asm__ __volatile__(							\
-	"ldr%?b	%0, [%1, %2]				@ inbc"			\
-	: "=r" (result)								\
-	: "r" (PCIO_BASE), "Jr" (port));					\
-	result;									\
-})
-
-#define __outwc(value,port)							\
-({										\
-	__asm__ __volatile__(							\
-	"str%?h	%0, [%1, %2]				@ outwc"		\
-	:									\
-	: "r" (value), "r" (PCIO_BASE), "r" (port));				\
-})
-
-#define __inwc(port)								\
-({										\
-	unsigned short result;							\
-	__asm__ __volatile__(							\
-	"ldr%?h	%0, [%1, %2]				@ inwc"			\
-	: "=r" (result)								\
-	: "r" (PCIO_BASE), "r" (port));						\
-	result & 0xffff;							\
-})
-
-#define __outlc(value,port)							\
-({										\
-	__asm__ __volatile__(							\
-	"str%?	%0, [%1, %2]				@ outlc"		\
-	:									\
-	: "r" (value), "r" (PCIO_BASE), "Jr" (port));				\
-})
-
-#define __inlc(port)								\
-({										\
-	unsigned long result;							\
-	__asm__ __volatile__(							\
-	"ldr%?	%0, [%1, %2]				@ inlc"			\
-	: "=r" (result)								\
-	: "r" (PCIO_BASE), "Jr" (port));					\
-	result;									\
-})
-
-#define __ioaddrc(port)								\
-({										\
-	unsigned long addr;							\
-	addr = PCIO_BASE + port;						\
-	addr;									\
+#define __outbc(value,port)						\
+({									\
+	__asm__ __volatile__(						\
+	"str%?b	%0, [%1, %2]				@ outbc"	\
+	:								\
+	: "r" (value), "r" (PCIO_BASE), "Jr" (port));			\
+})
+
+#define __inbc(port)							\
+({									\
+	unsigned char result;						\
+	__asm__ __volatile__(						\
+	"ldr%?b	%0, [%1, %2]				@ inbc"		\
+	: "=r" (result)							\
+	: "r" (PCIO_BASE), "Jr" (port));				\
+	result;								\
+})
+
+#define __outwc(value,port)						\
+({									\
+	__asm__ __volatile__(						\
+	"str%?h	%0, [%1, %2]				@ outwc"	\
+	:								\
+	: "r" (value), "r" (PCIO_BASE), "r" (port));			\
+})
+
+#define __inwc(port)							\
+({									\
+	unsigned short result;						\
+	__asm__ __volatile__(						\
+	"ldr%?h	%0, [%1, %2]				@ inwc"		\
+	: "=r" (result)							\
+	: "r" (PCIO_BASE), "r" (port));					\
+	result & 0xffff;						\
+})
+
+#define __outlc(value,port)						\
+({									\
+	__asm__ __volatile__(						\
+	"str%?	%0, [%1, %2]				@ outlc"	\
+	:								\
+	: "r" (value), "r" (PCIO_BASE), "Jr" (port));			\
+})
+
+#define __inlc(port)							\
+({									\
+	unsigned long result;						\
+	__asm__ __volatile__(						\
+	"ldr%?	%0, [%1, %2]				@ inlc"		\
+	: "=r" (result)							\
+	: "r" (PCIO_BASE), "Jr" (port));				\
+	result;								\
+})
+
+#define __ioaddrc(port)							\
+({									\
+	unsigned long addr;						\
+	addr = PCIO_BASE + port;					\
+	addr;								\
 })
 
 /*
@@ -130,20 +133,22 @@
  *
  * IO address has already been translated to a virtual address
  */
-#define outb_t(v,p)								\
+#define outb_t(v,p)							\
 	(*(volatile unsigned char *)(p) = (v))
 
-#define inb_t(p)								\
+#define inb_t(p)							\
 	(*(volatile unsigned char *)(p))
 
-#define outl_t(v,p)								\
+#define outl_t(v,p)							\
 	(*(volatile unsigned long *)(p) = (v))
 
-#define inl_t(p)								\
+#define inl_t(p)							\
 	(*(volatile unsigned long *)(p))
 
 /*
- * ioremap support
+ * ioremap support - validate a PCI memory address,
+ * and convert a PCI memory address to a physical
+ * address for the page tables.
  */
 #define valid_ioaddr(iomem,size) ((iomem) < 0x80000000 && (iomem) + (size) <= 0x80000000)
 #define io_to_phys(iomem)	((iomem) + DC21285_PCI_MEM)
@@ -153,58 +158,48 @@
  * is using read*() and so on with addresses they didn't get from ioremap
  * this can go away.
  */
-#define IO_FUDGE_FACTOR		0xe0000000
+#define IO_FUDGE_FACTOR		PCIMEM_BASE
 
-extern inline void *ioremap(unsigned long iomem_addr, unsigned long size)
-{
-	unsigned long phys_addr;
-
-	if (!valid_ioaddr(iomem_addr, size))
-		return NULL;
-
-	phys_addr = io_to_phys(iomem_addr & PAGE_MASK);
-
-	return (void *)((unsigned long)__ioremap(phys_addr, size, 0) 
-			- IO_FUDGE_FACTOR);
-}
+/*
+ * ioremap takes a PCI memory address, as specified in
+ * linux/Documentation/IO-mapping.txt
+ */
+#define ioremap(iomem_addr,size)					\
+({									\
+	unsigned long _addr = (iomem_addr), _size = (size);		\
+	void *_ret = NULL;						\
+	if (valid_ioaddr(_addr, _size)) {				\
+		_addr = io_to_phys(_addr);				\
+		_ret = __ioremap(_addr, _size, 0) - IO_FUDGE_FACTOR;	\
+	}								\
+	_ret; })
 
 #define ioremap_nocache(iomem_addr,size) ioremap((iomem_addr),(size))
 
 extern void iounmap(void *addr);
 
-/*
- * We'd probably be better off with these as macros rather than functions.
- * Firstly that would be more efficient and secondly we could do with the
- * ability to stop GCC whinging about type conversions.  --philb
- */
-static inline void writeb(unsigned char b, unsigned int addr)
-{
-	*(volatile unsigned char *)(IO_FUDGE_FACTOR + (addr)) = b;
-}
-
-static inline unsigned char readb(unsigned int addr)
-{
-	return *(volatile unsigned char *)(IO_FUDGE_FACTOR + (addr));
+#define DECLARE_PCI_WRITE(typ,fnsuffix)					\
+static inline void write##fnsuffix(unsigned typ val, unsigned int addr)	\
+{									\
+	*(volatile unsigned typ *)(IO_FUDGE_FACTOR + addr) = val;	\
 }
 
-static inline void writew(unsigned short b, unsigned int addr)
-{
-	*(volatile unsigned short *)(IO_FUDGE_FACTOR + (addr)) = b;
+#define DECLARE_PCI_READ(typ,fnsuffix)					\
+static inline unsigned typ read##fnsuffix (unsigned int addr)		\
+{									\
+	return *(volatile unsigned typ *)(IO_FUDGE_FACTOR + addr);	\
 }
 
-static inline unsigned short readw(unsigned int addr)
-{
-	return *(volatile unsigned short *)(IO_FUDGE_FACTOR + (addr));
-}
+#define DECLARE_PCI(typ,fnsuffix)					\
+	DECLARE_PCI_WRITE(typ,fnsuffix)					\
+	DECLARE_PCI_READ(typ,fnsuffix)
 
-static inline void writel(unsigned long b, unsigned int addr)
-{
-	*(volatile unsigned long *)(IO_FUDGE_FACTOR + (addr)) = b;
-}
+DECLARE_PCI(char,b)
+DECLARE_PCI(short,w)
+DECLARE_PCI(long,l)
 
-static inline unsigned short readl(unsigned int addr)
-{
-	return *(volatile unsigned long *)(IO_FUDGE_FACTOR + (addr));
-}
+#undef DECLARE_PCI
+#undef DECLARE_PCI_READ
+#undef DECLARE_PCI_WRITE
 
 #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/irq.h linux/include/asm-arm/arch-ebsa285/irq.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/irq.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/irq.h	Mon May 10 10:17:28 1999
@@ -4,136 +4,206 @@
  * Copyright (C) 1996-1998 Russell King
  *
  * Changelog:
- *   22-08-1998	RMK	Restructured IRQ routines
- *   03-09-1998	PJB	Merged CATS support
+ *  22-Aug-1998	RMK	Restructured IRQ routines
+ *  03-Sep-1998	PJB	Merged CATS support
+ *  20-Jan-1998	RMK	Started merge of EBSA286, CATS and NetWinder
+ *  26-Jan-1999	PJB	Don't use IACK on CATS
+ *  16-Mar-1999	RMK	Added autodetect of ISA PICs
  */
 #include <linux/config.h>
+#include <asm/hardware.h>
+#include <asm/dec21285.h>
+#include <asm/irq.h>
 
-static void ebsa285_mask_irq(unsigned int irq)
+/*
+ * Footbridge IRQ translation table
+ *  Converts from our IRQ numbers into FootBridge masks
+ */
+static int dc21285_irq_mask[] = {
+	IRQ_MASK_UART_RX,	/*  0 */
+	IRQ_MASK_UART_TX,	/*  1 */
+	IRQ_MASK_TIMER1,	/*  2 */
+	IRQ_MASK_TIMER2,	/*  3 */
+	IRQ_MASK_TIMER3,	/*  4 */
+	IRQ_MASK_IN0,		/*  5 */
+	IRQ_MASK_IN1,		/*  6 */
+	IRQ_MASK_IN2,		/*  7 */
+	IRQ_MASK_IN3,		/*  8 */
+	IRQ_MASK_DOORBELLHOST,	/*  9 */
+	IRQ_MASK_DMA1,		/* 10 */
+	IRQ_MASK_DMA2,		/* 11 */
+	IRQ_MASK_PCI,		/* 12 */
+	IRQ_MASK_SDRAMPARITY,	/* 13 */
+	IRQ_MASK_I2OINPOST,	/* 14 */
+	IRQ_MASK_PCI_ERR	/* 15 */
+};
+
+static int isa_irq = -1;
+
+static inline int fixup_irq(unsigned int irq)
+{
+#ifdef CONFIG_HOST_FOOTBRIDGE
+	if (irq == isa_irq)
+		irq = *(unsigned char *)PCIIACK_BASE;
+#endif
+
+	return irq;
+}
+
+static void dc21285_mask_irq(unsigned int irq)
 {
-	*CSR_IRQ_DISABLE = 1 << irq;
+	*CSR_IRQ_DISABLE = dc21285_irq_mask[irq & 15];
 }
 
-static void ebsa285_unmask_irq(unsigned int irq)
+static void dc21285_unmask_irq(unsigned int irq)
 {
-	*CSR_IRQ_ENABLE = 1 << irq;
+	*CSR_IRQ_ENABLE = dc21285_irq_mask[irq & 15];
 }
 
-#ifdef CONFIG_CATS
+static void isa_mask_pic_lo_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
 
-/*
- * This contains the irq mask for both 8259A irq controllers,
- */
-static unsigned int isa_irq_mask = 0xffff;
+	outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
+}
 
-#define cached_21	(isa_irq_mask & 0xff)
-#define cached_A1	((isa_irq_mask >> 8) & 0xff)
+static void isa_mask_ack_pic_lo_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
 
-#define update_8259(_irq)			\
-	if ((_irq) & 8)				\
-		outb(cached_A1, 0xa1);		\
-	else					\
-		outb(cached_21, 0x21);
-
-static void isa_interrupt(int irq, void *h, struct pt_regs *regs)
-{
-	asmlinkage void do_IRQ(int irq, struct pt_regs * regs);
-	unsigned int irqbits = inb(0x20) | (inb(0xa0) << 8), irqnr = 0;
-	irqbits &= ~(1<<2);	/* don't try to service the cascade */
-	while (irqbits) {
-		if (irqbits & 1)
-			do_IRQ(32 + irqnr, regs);
-		irqbits >>= 1;
-		irqnr++;
-	}
+	outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
+	outb(0x20, PIC_LO);
 }
 
-static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
+static void isa_unmask_pic_lo_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_LO) & ~mask, PIC_MASK_LO);
+}
 
-static struct irqaction irq_isa = 
-		{ isa_interrupt, SA_INTERRUPT, 0, "ISA PIC", NULL, NULL };
-static struct irqaction irq_cascade = 
-		{ no_action, 0, 0, "cascade", NULL, NULL };
-
-static void cats_mask_and_ack_isa_irq(unsigned int irq)
-{
-	isa_irq_mask |= (1 << (irq - 32));
-	update_8259(irq);
-	if (irq & 8) {
-		inb(0xA1);	/* DUMMY */
-		outb(cached_A1,0xA1);
-		outb(0x62,0x20);	/* Specific EOI to cascade */
-		outb(0x20,0xA0);
-	} else {
-		inb(0x21);	/* DUMMY */
-		outb(cached_21,0x21);
-		outb(0x20,0x20);
-	}
+static void isa_mask_pic_hi_irq(unsigned int irq)
+{
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
 }
 
-static void cats_mask_isa_irq(unsigned int irq)
+static void isa_mask_ack_pic_hi_irq(unsigned int irq)
 {
-	isa_irq_mask |= (1 << (irq - 32));
-	update_8259(irq);
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
+	outb(0x62, PIC_LO);
+	outb(0x20, PIC_HI);
 }
 
-static void cats_unmask_isa_irq(unsigned int irq)
+static void isa_unmask_pic_hi_irq(unsigned int irq)
 {
-	isa_irq_mask &= ~(1 << (irq - 32));
-	update_8259(irq);
+	unsigned int mask = 1 << (irq & 7);
+
+	outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI);
 }
- 
-#endif 
+
+static void no_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+}
+
+static struct irqaction irq_cascade = { no_action, 0, 0, "cascade", NULL, NULL };
 
 static __inline__ void irq_init_irq(void)
 {
 	int irq;
 
+	/*
+	 * setup DC21285 IRQs
+	 */
 	*CSR_IRQ_DISABLE = -1;
 	*CSR_FIQ_DISABLE = -1;
 
-	for (irq = 0; irq < NR_IRQS; irq++) {
+	for (irq = _DC21285_IRQ(0); irq < _DC21285_IRQ(16); irq++) {
 		irq_desc[irq].valid	= 1;
 		irq_desc[irq].probe_ok	= 1;
-#ifdef CONFIG_CATS
-		if (machine_is_cats() && IRQ_IS_ISA(irq)) {
-			irq_desc[irq].mask_ack	= cats_mask_and_ack_isa_irq;
-			irq_desc[irq].mask	= cats_mask_isa_irq;
-			irq_desc[irq].unmask	= cats_unmask_isa_irq;
+		irq_desc[irq].mask_ack	= dc21285_mask_irq;
+		irq_desc[irq].mask	= dc21285_mask_irq;
+		irq_desc[irq].unmask	= dc21285_unmask_irq;
+	}
+
+	/*
+	 * Determine the ISA settings for
+	 * the machine we're running on.
+	 */
+	switch (machine_arch_type) {
+	default:
+		isa_irq = -1;
+		break;
+
+	case MACH_TYPE_EBSA285:
+		/* The following is dependent on which slot
+		 * you plug the Southbridge card into.  We
+		 * currently assume that you plug it into
+		 * the right-hand most slot.
+		 */
+		isa_irq = IRQ_PCI;
+		break;
+
+	case MACH_TYPE_CATS:
+		isa_irq = IRQ_IN2;
+		break;
+
+	case MACH_TYPE_NETWINDER:
+		isa_irq = IRQ_IN3;
+		break;
+	}
+
+	if (isa_irq != -1) {
+		/*
+		 * Setup, and then probe for an ISA PIC
+		 */
+		outb(0x11, PIC_LO);
+		outb(_ISA_IRQ(0), PIC_MASK_LO);	/* IRQ number		*/
+		outb(0x04, PIC_MASK_LO);	/* Slave on Ch2		*/
+		outb(0x01, PIC_MASK_LO);	/* x86			*/
+		outb(0xf5, PIC_MASK_LO);	/* pattern: 11110101	*/
+
+		outb(0x11, PIC_HI);
+		outb(_ISA_IRQ(8), PIC_MASK_HI);	/* IRQ number		*/
+		outb(0x02, PIC_MASK_HI);	/* Slave on Ch1		*/
+		outb(0x01, PIC_MASK_HI);	/* x86			*/
+		outb(0xfa, PIC_MASK_HI);	/* pattern: 11111010	*/
+
+//		outb(0x68, PIC_LO);		/* enable special mode	*/
+//		outb(0x68, PIC_HI);		/* enable special mode	*/
+		outb(0x0b, PIC_LO);
+		outb(0x0b, PIC_HI);
+
+		if (inb(PIC_MASK_LO) == 0xf5 && inb(PIC_MASK_HI) == 0xfa) {
+			outb(0xff, PIC_MASK_LO);/* mask all IRQs	*/
+			outb(0xff, PIC_MASK_HI);/* mask all IRQs	*/
 		} else
-#endif
-		{
-			irq_desc[irq].mask_ack	= ebsa285_mask_irq;
-			irq_desc[irq].mask	= ebsa285_mask_irq;
-			irq_desc[irq].unmask	= ebsa285_unmask_irq;
-		}
+			isa_irq = -1;
 	}
 
-#ifdef CONFIG_CATS
-	if (machine_is_cats()) {
-		request_region(0x20, 2, "pic1");
-		request_region(0xa0, 2, "pic2");
-
-		/* set up master 8259 */
-		outb(0x11, 0x20);
-		outb(0, 0x21);
-		outb(1<<2, 0x21);
-		outb(0x1, 0x21);
-		outb(0xff, 0x21);
-		outb(0x68, 0x20);
-		outb(0xa, 0x20);
-		
-		/* set up slave 8259 */
-		outb(0x11, 0xa0);
-		outb(0, 0xa1);
-		outb(2, 0xa1);
-		outb(0x1, 0xa1);
-		outb(0xff, 0xa1);
-		outb(0x68, 0xa0);
-		outb(0xa, 0xa0);
+	if (isa_irq != -1) {
+		for (irq = _ISA_IRQ(0); irq < _ISA_IRQ(8); irq++) {
+			irq_desc[irq].valid	= 1;
+			irq_desc[irq].probe_ok	= 1;
+			irq_desc[irq].mask_ack	= isa_mask_ack_pic_lo_irq;
+			irq_desc[irq].mask	= isa_mask_pic_lo_irq;
+			irq_desc[irq].unmask	= isa_unmask_pic_lo_irq;
+		}
+
+		for (irq = _ISA_IRQ(8); irq < _ISA_IRQ(16); irq++) {
+			irq_desc[irq].valid	= 1;
+			irq_desc[irq].probe_ok	= 1;
+			irq_desc[irq].mask_ack	= isa_mask_ack_pic_hi_irq;
+			irq_desc[irq].mask	= isa_mask_pic_hi_irq;
+			irq_desc[irq].unmask	= isa_unmask_pic_hi_irq;
+		}
 
-		setup_arm_irq(IRQ_ISA_PIC, &irq_isa);
+		request_region(PIC_LO, 2, "pic1");
+		request_region(PIC_HI, 2, "pic2");
 		setup_arm_irq(IRQ_ISA_CASCADE, &irq_cascade);
+		setup_arm_irq(isa_irq, &irq_cascade);
 	}
-#endif
 }
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/irqs.h linux/include/asm-arm/arch-ebsa285/irqs.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/irqs.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/arch-ebsa285/irqs.h	Sat May  8 11:06:57 1999
@@ -3,55 +3,85 @@
  *
  * Copyright (C) 1998 Russell King
  * Copyright (C) 1998 Phil Blundell
+ *
+ * Changelog:
+ *  20-Jan-1998	RMK	Started merge of EBSA286, CATS and NetWinder
+ *  01-Feb-1999	PJB	ISA IRQs start at 0 not 16
  */
 
-#define NR_IRQS			48
+#define NR_IRQS			32
+#define NR_DC21285_IRQS		16
+
+#define _ISA_IRQ(x)		(0 + (x))
+#define _DC21285_IRQ(x)		(16 + (x))
 
 /*
  * This is a list of all interrupts that the 21285
- * can generate
+ * can generate and we handle.
  */
-#define IRQ_RESERVED		0
-#define IRQ_SOFTIRQ		1
-#define IRQ_CONRX		2
-#define IRQ_CONTX		3
-#define IRQ_TIMER1		4
-#define IRQ_TIMER2		5
-#define IRQ_TIMER3		6
-#define IRQ_TIMER4		7
-#define IRQ_IN0			8
-#define IRQ_IN1			9
-#define IRQ_IN2			10
-#define IRQ_IN3			11
-#define IRQ_XCS0		12
-#define IRQ_XCS1		13
-#define IRQ_XCS2		14
-#define IRQ_DOORBELLHOST	15
-#define IRQ_DMA1		16
-#define IRQ_DMA2		17
-#define IRQ_PCI			18
-#define IRQ_BIST		22
-#define IRQ_SERR		23
-#define IRQ_SDRAMPARITY		24
-#define IRQ_I2OINPOST		25
-#define IRQ_DISCARDTIMER	27
-#define IRQ_PCIDATAPARITY	28
-#define IRQ_PCIMASTERABORT	29
-#define IRQ_PCITARGETABORT	30
-#define IRQ_PCIPARITY		31
-
-/* IRQs 32-47 are the 16 ISA interrupts on a CATS board.  */
-#define IRQ_ISA_PIC	IRQ_IN2
-#define IRQ_IS_ISA(_x)	(((_x) >= 32) && ((_x) <= 47))
-#define IRQ_ISA(_x)	((_x) + 0x20)
-#define IRQ_ISA_CASCADE		IRQ_ISA(2)
+#define IRQ_CONRX		_DC21285_IRQ(0)
+#define IRQ_CONTX		_DC21285_IRQ(1)
+#define IRQ_TIMER1		_DC21285_IRQ(2)
+#define IRQ_TIMER2		_DC21285_IRQ(3)
+#define IRQ_TIMER3		_DC21285_IRQ(4)
+#define IRQ_IN0			_DC21285_IRQ(5)
+#define IRQ_IN1			_DC21285_IRQ(6)
+#define IRQ_IN2			_DC21285_IRQ(7)
+#define IRQ_IN3			_DC21285_IRQ(8)
+#define IRQ_DOORBELLHOST	_DC21285_IRQ(9)
+#define IRQ_DMA1		_DC21285_IRQ(10)
+#define IRQ_DMA2		_DC21285_IRQ(11)
+#define IRQ_PCI			_DC21285_IRQ(12)
+#define IRQ_SDRAMPARITY		_DC21285_IRQ(13)
+#define IRQ_I2OINPOST		_DC21285_IRQ(14)
+#define IRQ_PCI_ERR		_DC21285_IRQ(15)
+
+#define IRQ_ISA_TIMER		_ISA_IRQ(0)
+#define IRQ_ISA_KEYBOARD	_ISA_IRQ(1)
+#define IRQ_ISA_CASCADE		_ISA_IRQ(2)
+#define IRQ_ISA_UART2		_ISA_IRQ(3)
+#define IRQ_ISA_UART		_ISA_IRQ(4)
+#define IRQ_ISA_FLOPPY		_ISA_IRQ(6)
+#define IRQ_ISA_PRINTER		_ISA_IRQ(7)
+#define IRQ_ISA_RTC_ALARM	_ISA_IRQ(8)
+#define IRQ_ISA_2		_ISA_IRQ(9)
+#define IRQ_ISA_PS2MOUSE	_ISA_IRQ(12)
+#define IRQ_ISA_HARDDISK1	_ISA_IRQ(14)
+#define IRQ_ISA_HARDDISK2	_ISA_IRQ(15)
+
+#define IRQ_MASK_UART_RX	(1 << 2)
+#define IRQ_MASK_UART_TX	(1 << 3)
+#define IRQ_MASK_TIMER1		(1 << 4)
+#define IRQ_MASK_TIMER2		(1 << 5)
+#define IRQ_MASK_TIMER3		(1 << 6)
+#define IRQ_MASK_IN0		(1 << 8)
+#define IRQ_MASK_IN1		(1 << 9)
+#define IRQ_MASK_IN2		(1 << 10)
+#define IRQ_MASK_IN3		(1 << 11)
+#define IRQ_MASK_DOORBELLHOST	(1 << 15)
+#define IRQ_MASK_DMA1		(1 << 16)
+#define IRQ_MASK_DMA2		(1 << 17)
+#define IRQ_MASK_PCI		(1 << 18)
+#define IRQ_MASK_SDRAMPARITY	(1 << 24)
+#define IRQ_MASK_I2OINPOST	(1 << 25)
+#define IRQ_MASK_PCI_ERR	((1 <<23) | (1 << 27) | (1 << 28) | (1 << 29) | (1 << 30) | (1 << 31))
 
 /*
- * Now map them to the Linux interrupts
+ * Netwinder interrupt allocations
  */
-#define IRQ_TIMER		IRQ_TIMER1
-#define IRQ_FLOPPYDISK		IRQ_ISA(6)
-#define IRQ_HARDDISK		IRQ_ISA(14)
-#define IRQ_HARDDISK_SECONDARY	IRQ_ISA(15)
+#define IRQ_NETWINDER_ETHER10	IRQ_IN0
+#define IRQ_NETWINDER_ETHER100	IRQ_IN1
+#define IRQ_NETWINDER_VIDCOMP	IRQ_IN2
+#define IRQ_NETWINDER_PS2MOUSE	_ISA_IRQ(5)
+#define IRQ_NETWINDER_IR	_ISA_IRQ(6)
+#define IRQ_NETWINDER_BUTTON	_ISA_IRQ(10)
+#define IRQ_NETWINDER_VGA	_ISA_IRQ(11)
+#define IRQ_NETWINDER_SOUND	_ISA_IRQ(12)
+
+#undef RTC_IRQ
+#define RTC_IRQ		IRQ_ISA_RTC_ALARM
+#undef AUX_IRQ
+#define AUX_IRQ		(machine_is_netwinder() ? IRQ_NETWINDER_PS2MOUSE : IRQ_ISA_PS2MOUSE)
+#define IRQ_FLOPPYDISK	IRQ_ISA_FLOPPY
 
-#define irq_cannonicalize(_i)	(((_i) == IRQ_ISA_CASCADE) ? IRQ_ISA(9) : _i)
+#define irq_cannonicalize(_i)	(((_i) == IRQ_ISA_CASCADE) ? IRQ_ISA_2 : _i)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/keyboard.h linux/include/asm-arm/arch-ebsa285/keyboard.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/keyboard.h	Wed Apr 28 11:37:31 1999
+++ linux/include/asm-arm/arch-ebsa285/keyboard.h	Sat May  8 11:06:57 1999
@@ -6,16 +6,10 @@
  * (C) 1998 Russell King
  * (C) 1998 Phil Blundell
  */
-
-#include <linux/config.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 
-#define NR_SCANCODES 128
-
-#ifdef CONFIG_CATS
-
-#define KEYBOARD_IRQ		IRQ_ISA(1)
+extern int have_isa_bridge;
 
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
@@ -26,40 +20,52 @@
 extern void pckbd_init_hw(void);
 extern unsigned char pckbd_sysrq_xlate[128];
 
-#define kbd_setkeycode			pckbd_setkeycode
-#define kbd_getkeycode			pckbd_getkeycode
-#define kbd_translate(sc, kcp, ufp, rm) ({ *ufp = sc & 0200; \
-		pckbd_translate(sc & 0x7f, kcp, rm);})
+#define KEYBOARD_IRQ			IRQ_ISA_KEYBOARD
 
-#define kbd_unexpected_up		pckbd_unexpected_up
-#define kbd_leds			pckbd_leds
-#define kbd_init_hw()			\
-		do { if (machine_is_cats()) pckbd_init_hw(); } while (0)
-#define kbd_sysrq_xlate			pckbd_sysrq_xlate
-#define kbd_disable_irq()
-#define kbd_enable_irq()
+#define NR_SCANCODES 128
 
-#define SYSRQ_KEY	0x54
+#define kbd_setkeycode(sc,kc)				\
+	({						\
+		int __ret;				\
+		if (have_isa_bridge)			\
+			__ret = pckbd_setkeycode(sc,kc);\
+		else					\
+			__ret = -EINVAL;		\
+		__ret;					\
+	})
+
+#define kbd_getkeycode(sc)				\
+	({						\
+		int __ret;				\
+		if (have_isa_bridge)			\
+			__ret = pckbd_getkeycode(sc);	\
+		else					\
+			__ret = -EINVAL;		\
+		__ret;					\
+	})
+
+#define kbd_translate(sc, kcp, rm)			\
+	({						\
+		pckbd_translate(sc, kcp, rm);		\
+	})
 
-#else
+#define kbd_unexpected_up		pckbd_unexpected_up
 
-/* Dummy keyboard definitions */
+#define kbd_leds(leds)					\
+	do {						\
+		if (have_isa_bridge)			\
+			pckbd_leds(leds);		\
+	} while (0)
+
+#define kbd_init_hw()					\
+	do {						\
+		if (have_isa_bridge)			\
+			pckbd_init_hw();		\
+	} while (0)
 
-#define kbd_setkeycode(sc,kc)		(-EINVAL)
-#define kbd_getkeycode(sc)		(-EINVAL)
+#define kbd_sysrq_xlate			pckbd_sysrq_xlate
 
-/* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode)
- * Returns  : 0 to ignore scancode, *keycode set to keycode, *up_flag
- *            set to 0200 if scancode indicates release
- */
-#define kbd_translate(sc, kcp, ufp, rm)	(1)
-#define kbd_unexpected_up(kc)		(0200)
-#define kbd_leds(leds)
-#define kbd_init_hw()
-//#define kbd_sysrq_xlate			ps2kbd_sysrq_xlate
 #define kbd_disable_irq()
 #define kbd_enable_irq()
 
-#define SYSRQ_KEY	13
-
-#endif
+#define SYSRQ_KEY	0x54
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/memory.h linux/include/asm-arm/arch-ebsa285/memory.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/memory.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-ebsa285/memory.h	Mon May 10 10:17:28 1999
@@ -0,0 +1,74 @@
+/*
+ * linux/include/asm-arm/arch-ebsa285/memory.h
+ *
+ * Copyright (c) 1996-1999 Russell King.
+ *
+ * Changelog:
+ *  20-Oct-1996	RMK	Created
+ *  31-Dec-1997	RMK	Fixed definitions to reduce warnings.
+ *  17-May-1998	DAG	Added __virt_to_bus and __bus_to_virt functions.
+ *  21-Nov-1998	RMK	Changed __virt_to_bus and __bus_to_virt to macros.
+ *  21-Mar-1999	RMK	Added PAGE_OFFSET for co285 architecture.
+ *			Renamed to memory.h
+ *			Moved PAGE_OFFSET and TASK_SIZE here
+ */
+#ifndef __ASM_ARCH_MMU_H
+#define __ASM_ARCH_MMU_H
+
+#include <linux/config.h>
+
+#if defined(CONFIG_HOST_FOOTBRIDGE)
+
+/*
+ * Task size: 3GB
+ */
+#define TASK_SIZE		(0xc0000000UL)
+
+/*
+ * Page offset: 3GB
+ */
+#define PAGE_OFFSET		(0xc0000000UL)
+
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x)	((x) - 0xe0000000)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x)	((x) + 0xe0000000)
+
+#elif defined(CONFIG_ADDIN_FOOTBRIDGE)
+
+#if defined(CONFIG_ARCH_CO285)
+
+/*
+ * Task size: 1.5GB
+ */
+#define TASK_SIZE		(0x60000000UL)
+
+/*
+ * Page offset: 1.5GB
+ */
+#define PAGE_OFFSET		(0x60000000UL)
+
+#else
+
+#error Add in your architecture here
+
+#endif
+
+#ifndef __ASSEMBLY__
+extern unsigned long __virt_to_bus(unsigned long);
+extern unsigned long __bus_to_virt(unsigned long);
+#endif
+
+#endif
+
+/*
+ * On Footbridge machines, the dram is contiguous.
+ * On Host Footbridge, these conversions are constant.
+ * On an add-in footbridge, these depend on register settings.
+ */
+#define __virt_to_phys__is_a_macro
+#define __virt_to_phys(vpage) ((unsigned long)(vpage) - PAGE_OFFSET)
+#define __phys_to_virt__is_a_macro
+#define __phys_to_virt(ppage) ((unsigned long)(ppage) + PAGE_OFFSET)
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/mm-init.h linux/include/asm-arm/arch-ebsa285/mm-init.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/mm-init.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-ebsa285/mm-init.h	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/mmap.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/mmu.h linux/include/asm-arm/arch-ebsa285/mmu.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/mmu.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/mmu.h	Wed Dec 31 16:00:00 1969
@@ -1,28 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa285/mmu.h
- *
- * Copyright (c) 1996,1997,1998 Russell King.
- *
- * Changelog:
- *  20-10-1996	RMK	Created
- *  31-12-1997	RMK	Fixed definitions to reduce warnings
- *  17-05-1998	DAG	Added __virt_to_bus and __bus_to_virt functions.
- *  21-11-1998	RMK	Changed __virt_to_bus and __bus_to_virt to macros.
- */
-#ifndef __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
-
-/*
- * On ebsa285, the dram is contiguous
- */
-#define __virt_to_phys__is_a_macro
-#define __virt_to_phys(vpage) ((unsigned long)(vpage) - PAGE_OFFSET)
-#define __phys_to_virt__is_a_macro
-#define __phys_to_virt(ppage) ((unsigned long)(ppage) + PAGE_OFFSET)
-
-#define __virt_to_bus__is_a_macro
-#define __virt_to_bus(x)	((x) - 0xe0000000)
-#define __bus_to_virt__is_a_macro
-#define __bus_to_virt(x)	((x) + 0xe0000000)
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/oldlatches.h linux/include/asm-arm/arch-ebsa285/oldlatches.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/oldlatches.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-ebsa285/oldlatches.h	Wed Dec 31 16:00:00 1969
@@ -1,9 +0,0 @@
-/*
- * Dummy oldlatches.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifdef __need_oldlatches
-#error "Old latches not present in this (rpc) machine"
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/processor.h linux/include/asm-arm/arch-ebsa285/processor.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/processor.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/processor.h	Sat May  8 11:06:57 1999
@@ -1,12 +1,17 @@
 /*
  * linux/include/asm-arm/arch-ebsa110/processor.h
  *
- * Copyright (C) 1996,1997,1998 Russell King
+ * Copyright (C) 1996-1999 Russell King
+ *
+ * Changelog:
+ *  21-Mar-1999	RMK	Added asm/arch/memory.h
  */
 
 #ifndef __ASM_ARCH_PROCESSOR_H
 #define __ASM_ARCH_PROCESSOR_H
 
+#include <asm/arch/memory.h>
+
 /*
  * Bus types
  */
@@ -15,17 +20,9 @@
 #define MCA_bus 0
 #define MCA_bus__is_a_macro /* for versions in ksyms.c */
 
-/*
- * User space: 3GB
- */
-#define TASK_SIZE	(0xc0000000UL)
-
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
 #define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
-
-#define INIT_MMAP \
-{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/serial.h linux/include/asm-arm/arch-ebsa285/serial.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/serial.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/serial.h	Sat May  8 11:06:57 1999
@@ -10,8 +10,6 @@
 #ifndef __ASM_ARCH_SERIAL_H
 #define __ASM_ARCH_SERIAL_H
 
-#include <linux/config.h>
-
 #include <asm/irq.h>
 
 /*
@@ -23,13 +21,8 @@
  */
 #define BASE_BAUD (1843200 / 16)
 
-#ifdef CONFIG_CATS
-#define _SER_IRQ0	IRQ_ISA(4)
-#define _SER_IRQ1	IRQ_ISA(3)
-#else
-#define _SER_IRQ0	0
-#define _SER_IRQ1	0
-#endif
+#define _SER_IRQ0	IRQ_ISA_UART
+#define _SER_IRQ1	IRQ_ISA_UART2
 
 #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/system.h linux/include/asm-arm/arch-ebsa285/system.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/system.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/system.h	Sat May  8 11:06:57 1999
@@ -3,6 +3,8 @@
  *
  * Copyright (c) 1996,1997,1998 Russell King.
  */
+#include <asm/dec21285.h>
+#include <asm/io.h>
 #include <asm/hardware.h>
 #include <asm/leds.h>
 
@@ -16,14 +18,37 @@
 		 mov	r0, #0x130
 		 mcr	p15, 0, r0, c1, c0	@ MMU off
 		 mcr	p15, 0, ip, c7, c7	@ flush caches
-		 mov	pc, lr");
+		 mov	pc, lr" : : : "cc");
 	} else {
-		/* To reboot, we set up the 21285 watchdog and enable it.
-		 * We then wait for it to timeout.
-		 */
-		*CSR_TIMER4_LOAD = 0x8000;
-		*CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16;
-		*CSR_SA110_CNTL |= 1 << 13;
+		if (machine_is_ebsa285() || machine_is_co285()) {
+			/* To reboot, we set up the 21285 watchdog and
+			 * enable it.  We then wait for it to timeout.
+			 */
+			*CSR_TIMER4_LOAD = 0x8000;
+			*CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE |
+					   TIMER_CNTL_AUTORELOAD |
+					   TIMER_CNTL_DIV16;
+			*CSR_SA110_CNTL |= 1 << 13;
+		} else if (machine_is_netwinder()) {
+			/* open up the SuperIO chip
+			 */
+			outb(0x87, 0x370);
+			outb(0x87, 0x370);
+
+			/* aux function group 1 (logical device 7)
+			 */
+			outb(0x07, 0x370);
+			outb(0x07, 0x371);
+
+			/* set GP16 for WD-TIMER output
+			 */
+			outb(0xe6, 0x370);
+			outb(0x00, 0x371);
+
+			/* set a RED LED and toggle WD_TIMER for rebooting
+			 */
+			outb(0xc4, 0x338);
+		}
 	}
 }
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/time.h linux/include/asm-arm/arch-ebsa285/time.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/time.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/time.h	Sat May  8 11:06:57 1999
@@ -10,116 +10,346 @@
  *  21-Mar-1998	RMK	Created
  *  27-Aug-1998	PJB	CATS support
  *  28-Dec-1998	APH	Made leds optional
+ *  20-Jan-1999	RMK	Started merge of EBSA285, CATS and NetWinder
+ *  16-Mar-1999	RMK	More support for EBSA285-like machines with RTCs in
  */
 
-#define RTC_PORT(x)		(0x72+(x))
-#define RTC_ALWAYS_BCD		1
+#define RTC_PORT(x)		(rtc_base+(x))
+#define RTC_ALWAYS_BCD		0
 
 #include <linux/config.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/dec21285.h>
 #include <asm/leds.h>
 #include <asm/system.h>
-#include <linux/mc146818rtc.h>
 
-extern __inline__ unsigned long gettimeoffset (void)
+static int rtc_base;
+static unsigned long (*gettimeoffset)(void);
+static int (*set_rtc_mmss)(unsigned long nowtime);
+static long last_rtc_update = 0;	/* last time the cmos clock got updated */
+
+#ifdef CONFIG_LEDS
+static void do_leds(void)
+{
+	static unsigned int count = 50;
+	static int last_pid;
+
+	if (current->pid != last_pid) {
+		last_pid = current->pid;
+		if (last_pid)
+			leds_event(led_idle_end);
+		else
+			leds_event(led_idle_start);
+	}
+		
+	if (--count == 0) {
+		count = 50;
+		leds_event(led_timer);
+	}
+}
+#else
+#define do_leds()
+#endif
+
+#define mSEC_10_from_14 ((14318180 + 100) / 200)
+
+static unsigned long isa_gettimeoffset(void)
+{
+	int count;
+
+	static int count_p = (mSEC_10_from_14/6);    /* for the first call after boot */
+	static unsigned long jiffies_p = 0;
+
+	/*
+	 * cache volatile jiffies temporarily; we have IRQs turned off. 
+	 */
+	unsigned long jiffies_t;
+
+	/* timer count may underflow right here */
+	outb_p(0x00, 0x43);	/* latch the count ASAP */
+
+	count = inb_p(0x40);	/* read the latched count */
+
+	/*
+	 * We do this guaranteed double memory access instead of a _p 
+	 * postfix in the previous port access. Wheee, hackady hack
+	 */
+ 	jiffies_t = jiffies;
+
+	count |= inb_p(0x40) << 8;
+
+	/* Detect timer underflows.  If we haven't had a timer tick since 
+	   the last time we were called, and time is apparently going
+	   backwards, the counter must have wrapped during this routine. */
+	if ((jiffies_t == jiffies_p) && (count > count_p))
+		count -= (mSEC_10_from_14/6);
+	else
+		jiffies_p = jiffies_t;
+
+	count_p = count;
+
+	count = (((mSEC_10_from_14/6)-1) - count) * tick;
+	count = (count + (mSEC_10_from_14/6)/2) / (mSEC_10_from_14/6);
+
+	return count;
+}
+
+static void isa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	if (machine_is_netwinder())
+		do_leds();
+
+	do_timer(regs);
+
+	/* If we have an externally synchronized linux clock, then update
+	 * CMOS clock accordingly every ~11 minutes.  Set_rtc_mmss() has to be
+	 * called as close as possible to 500 ms before the new second starts.
+	 */
+	if ((time_status & STA_UNSYNC) == 0 &&
+	    xtime.tv_sec > last_rtc_update + 660 &&
+	    xtime.tv_usec > 50000 - (tick >> 1) &&
+	    xtime.tv_usec < 50000 + (tick >> 1)) {
+		if (set_rtc_mmss(xtime.tv_sec) == 0)
+			last_rtc_update = xtime.tv_sec;
+		else
+			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
+	}
+}
+
+static struct irqaction isa_timer_irq = {
+	isa_timer_interrupt,
+	0,
+	0,
+	"timer",
+	NULL,
+	NULL
+};
+
+__initfunc(static unsigned long
+get_isa_cmos_time(void))
+{
+	unsigned int year, mon, day, hour, min, sec;
+	int i;
+
+	// check to see if the RTC makes sense.....
+	if ((CMOS_READ(RTC_VALID) & RTC_VRT) == 0)
+		return mktime(1970, 1, 1, 0, 0, 0);
+
+	/* The Linux interpretation of the CMOS clock register contents:
+	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+	 * RTC registers show the second which has precisely just started.
+	 * Let's hope other operating systems interpret the RTC the same way.
+	 */
+	/* read RTC exactly on falling edge of update flag */
+	for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
+		if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+			break;
+
+	for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
+		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+			break;
+
+	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) {
+		BCD_TO_BIN(sec);
+		BCD_TO_BIN(min);
+		BCD_TO_BIN(hour);
+		BCD_TO_BIN(day);
+		BCD_TO_BIN(mon);
+		BCD_TO_BIN(year);
+	}
+	if ((year += 1900) < 1970)
+		year += 100;
+	return mktime(year, mon, day, hour, min, sec);
+}
+
+static int
+set_isa_cmos_time(unsigned long nowtime)
+{
+	int retval = 0;
+	int real_seconds, real_minutes, cmos_minutes;
+	unsigned char save_control, save_freq_select;
+
+	save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
+	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+
+	save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
+	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+	cmos_minutes = CMOS_READ(RTC_MINUTES);
+	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+		BCD_TO_BIN(cmos_minutes);
+
+	/*
+	 * since we're only adjusting minutes and seconds,
+	 * don't interfere with hour overflow. This avoids
+	 * messing with unknown time zones but requires your
+	 * RTC not to be off by more than 15 minutes
+	 */
+	real_seconds = nowtime % 60;
+	real_minutes = nowtime / 60;
+	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+		real_minutes += 30;		/* correct for half hour time zone */
+	real_minutes %= 60;
+
+	if (abs(real_minutes - cmos_minutes) < 30) {
+		if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+			BIN_TO_BCD(real_seconds);
+			BIN_TO_BCD(real_minutes);
+		}
+		CMOS_WRITE(real_seconds,RTC_SECONDS);
+		CMOS_WRITE(real_minutes,RTC_MINUTES);
+	} else
+		retval = -1;
+
+	/* The following flags have to be released exactly in this order,
+	 * otherwise the DS12887 (popular MC146818A clone with integrated
+	 * battery and quartz) will not reset the oscillator and will not
+	 * update precisely 500 ms later. You won't find this mentioned in
+	 * the Dallas Semiconductor data sheets, but who believes data
+	 * sheets anyway ...                           -- Markus Kuhn
+	 */
+	CMOS_WRITE(save_control, RTC_CONTROL);
+	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+	return retval;
+}
+
+
+
+static unsigned long __ebsa285_text timer1_gettimeoffset (void)
 {
 	unsigned long value = LATCH - *CSR_TIMER1_VALUE;
 
 	return (tick * value) / LATCH;
 }
 
-extern __inline__ int reset_timer (void)
+static void __ebsa285_text timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	*CSR_TIMER1_CLR = 0;
 
-#ifdef CONFIG_LEDS
-	/*
-	 * Do the LEDs thing on EBSA-285 hardware.
+	/* Do the LEDs things on non-CATS hardware.
 	 */
-	if (!machine_is_cats()) {
-		static unsigned int count = 50;
-		static int last_pid;
-
-		if (current->pid != last_pid) {
-			last_pid = current->pid;
-			if (last_pid)
-				leds_event(led_idle_end);
-			else
-				leds_event(led_idle_start);
-		}
-		
-		if (--count == 0) {
-			count = 50;
-			leds_event(led_timer);
-		}
+	if (!machine_is_cats())
+		do_leds();
+
+	do_timer(regs);
+
+	/* If we have an externally synchronized linux clock, then update
+	 * CMOS clock accordingly every ~11 minutes.  Set_rtc_mmss() has to be
+	 * called as close as possible to 500 ms before the new second starts.
+	 */
+	if ((time_status & STA_UNSYNC) == 0 &&
+	    xtime.tv_sec > last_rtc_update + 660 &&
+	    xtime.tv_usec > 50000 - (tick >> 1) &&
+	    xtime.tv_usec < 50000 + (tick >> 1)) {
+		if (set_rtc_mmss(xtime.tv_sec) == 0)
+			last_rtc_update = xtime.tv_sec;
+		else
+			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
 	}
-#endif
-	
-	return 1;
 }
 
-/*
- * We don't have a RTC to update!
- */
-#define update_rtc()
+static struct irqaction __ebsa285_data timer1_irq = {
+	timer1_interrupt,
+	0,
+	0,
+	"timer",
+	NULL,
+	NULL
+};
+
+static int
+set_dummy_time(unsigned long secs)
+{
+	return 1;
+}
 
 /*
  * Set up timer interrupt, and return the current time in seconds.
  */
-extern __inline__ unsigned long setup_timer (void)
+extern __inline__ void setup_timer(void)
 {
-	int year, mon, day, hour, min, sec;
+	switch(machine_arch_type) {
+	case MACH_TYPE_CO285:
+		/*
+		 * Add-in 21285s shouldn't access the RTC
+		 */
+		rtc_base = 0;
+		break;
 
-	/*
-	 * Default the date to 1 Jan 1970 0:0:0
-	 */
-	year = 1970; mon = 1; day = 1;
-	hour = 0; min = 0; sec = 0;
+	default:
+		rtc_base = 0x70;
+		break;
+	}
+
+	if (rtc_base) {
+		int reg_d, reg_b;
+
+		reg_d = CMOS_READ(RTC_REG_D);
 
-	*CSR_TIMER1_CLR  = 0;
-	*CSR_TIMER1_LOAD = LATCH;
-	*CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16;
-
-	if (machine_is_cats()) 
-	{
-		int i;
 		/*
-		 * Read the real time from the Dallas chip.  (Code borrowed
-		 * from arch/i386/kernel/time.c).
+		 * make sure the divider is set
 		 */
-		
-		/* The Linux interpretation of the CMOS clock register contents:
-		 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-		 * RTC registers show the second which has precisely just started.
-		 * Let's hope other operating systems interpret the RTC the same way.
+		CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_REG_A);
+
+		/*
+		 * Set control reg B
+		 *   (24 hour mode, update enabled)
 		 */
+		reg_b = CMOS_READ(RTC_REG_B) & 0x7f;
+		reg_b |= 2;
+		CMOS_WRITE(reg_b, RTC_REG_B);
+
+		if ((CMOS_READ(RTC_REG_A) & 0x7f) == RTC_REF_CLCK_32KHZ &&
+		    CMOS_READ(RTC_REG_B) == reg_b) {
+
+			/*
+			 * Check the battery
+			 */
+			if ((reg_d & 0x80) == 0)
+				printk(KERN_WARNING "RTC: *** warning: CMOS battery bad\n");
+
+			xtime.tv_sec = get_isa_cmos_time();
+			set_rtc_mmss = set_isa_cmos_time;
+		} else
+			rtc_base = 0;
+	}
 
-		/* read RTC exactly on falling edge of update flag */
-		for (i = 0 ; i < 1000000 ; i++)	/* may take up to 1 second... */
-			if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
-				break;
-		for (i = 0 ; i < 1000000 ; i++)	/* must try at least 2.228 ms */
-			if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
-				break;
-		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)
-		{
-			BCD_TO_BIN(sec);
-			BCD_TO_BIN(min);
-			BCD_TO_BIN(hour);
-			BCD_TO_BIN(day);
-			BCD_TO_BIN(mon);
-			BCD_TO_BIN(year);
-		}
-		if ((year += 1900) < 1970)
-			year += 100;
+	if (!rtc_base) {
+		/*
+		 * Default the date to 1 Jan 1970 0:0:0
+		 */
+		xtime.tv_sec = mktime(1970, 1, 1, 0, 0, 0);
+		set_rtc_mmss = set_dummy_time;
 	}
 
-	return mktime(year, mon, day, hour, min, sec);
+	if (machine_is_ebsa285()) {
+		gettimeoffset = timer1_gettimeoffset;
+
+		*CSR_TIMER1_CLR  = 0;
+		*CSR_TIMER1_LOAD = LATCH;
+		*CSR_TIMER1_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD | TIMER_CNTL_DIV16;
+
+		setup_arm_irq(IRQ_TIMER1, &timer1_irq);
+	} else {
+		/* enable PIT timer */
+		/* set for periodic (4) and LSB/MSB write (0x30) */
+		outb(0x34, 0x43);
+		outb((mSEC_10_from_14/6) & 0xFF, 0x40);
+		outb((mSEC_10_from_14/6) >> 8, 0x40);
+
+		gettimeoffset = isa_gettimeoffset;
+
+		setup_arm_irq(IRQ_ISA_TIMER, &isa_timer_irq);
+	}
 }
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/timex.h linux/include/asm-arm/arch-ebsa285/timex.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/timex.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-ebsa285/timex.h	Sat May  8 11:06:57 1999
@@ -7,8 +7,8 @@
  */
 
 /*
- * On the EBSA, the clock ticks at weird rates.
- * This is therefore not used to calculate the
- * divisor.
+ * On EBSA285 boards, the clock runs at 50MHz and is
+ * divided by a 4-bit prescaler.  Other boards use an
+ * ISA derived timer, and this is unused.
  */
 #define CLOCK_TICK_RATE		(50000000 / 16)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-ebsa285/uncompress.h linux/include/asm-arm/arch-ebsa285/uncompress.h
--- v2.2.7/linux/include/asm-arm/arch-ebsa285/uncompress.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-ebsa285/uncompress.h	Sat May  8 11:06:57 1999
@@ -1,9 +1,12 @@
 /*
- * linux/include/asm-arm/arch-ebsa110/uncompress.h
+ * linux/include/asm-arm/arch-ebsa285/uncompress.h
  *
  * Copyright (C) 1996,1997,1998 Russell King
  */
 
+/*
+ * Note! This could cause problems on the NetWinder
+ */
 #define BASE 0x42000160
 
 static __inline__ void putc(char c)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-nexuspci/a.out.h linux/include/asm-arm/arch-nexuspci/a.out.h
--- v2.2.7/linux/include/asm-arm/arch-nexuspci/a.out.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-nexuspci/a.out.h	Sat May  8 11:06:57 1999
@@ -1,15 +1,16 @@
 /*
  * linux/include/asm-arm/arch-nexuspci/a.out.h
  *
- * Copyright (C) 1996 Russell King
+ * Copyright (C) 1996-1999 Russell King
  */
-
 #ifndef __ASM_ARCH_A_OUT_H
 #define __ASM_ARCH_A_OUT_H
 
-#ifdef __KERNEL__
-#define STACK_TOP		((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
-#endif
+#include <asm/arch/memory.h>
+
+#define STACK_TOP \
+	((current->personality == PER_LINUX_32BIT) ? \
+	 TASK_SIZE : 0x04000000)
 
 #endif
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-nexuspci/hardware.h linux/include/asm-arm/arch-nexuspci/hardware.h
--- v2.2.7/linux/include/asm-arm/arch-nexuspci/hardware.h	Fri Jan  8 22:36:21 1999
+++ linux/include/asm-arm/arch-nexuspci/hardware.h	Sat May  8 11:06:57 1999
@@ -1,10 +1,12 @@
 /*
  * linux/include/asm-arm/arch-nexuspci/hardware.h
  *
- * Copyright (C) 1998 Philip Blundell
+ * Copyright (C) 1998-1999 Philip Blundell
  *
  * This file contains the hardware definitions of the Nexus PCI card.
  */
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
 
 /*    Logical    Physical
  * 0xfff00000	0x10000000	SCC2691 DUART
@@ -13,27 +15,17 @@
  * 0xffc00000	0x60000000	PLX registers
  * 0xfe000000	0x70000000	PCI I/O
  */
- 
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-/*
- * What hardware must be present
- */
-
-#define HAS_PCIO
-#define PCIO_BASE		0xfe000000
 
 /*
  * Mapping areas
  */
-#define IO_BASE			0xfe000000
+#define PCIO_BASE		0xfe000000
+#define FLUSH_BASE		0xdf000000
 
 /*
  * RAM definitions
  */
 #define RAM_BASE		0x40000000
-#define KERNTOPHYS(a)		((unsigned long)(&a))
 #define FLUSH_BASE_PHYS		0x40000000
 
 #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-nexuspci/irq.h linux/include/asm-arm/arch-nexuspci/irq.h
--- v2.2.7/linux/include/asm-arm/arch-nexuspci/irq.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/arch-nexuspci/irq.h	Sat May  8 11:06:57 1999
@@ -9,6 +9,8 @@
 
 #include <asm/io.h>
 
+#define fixup_irq(x) (x)
+
 #define INTCONT		0xffe00000
 
 extern unsigned long soft_irq_mask;
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-nexuspci/memory.h linux/include/asm-arm/arch-nexuspci/memory.h
--- v2.2.7/linux/include/asm-arm/arch-nexuspci/memory.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-nexuspci/memory.h	Sat May  8 11:06:57 1999
@@ -0,0 +1,37 @@
+/*
+ * linux/include/asm-arm/arch-nexuspci/memory.h
+ *
+ * Copyright (c) 1997, 1998 Philip Blundell.
+ * Copyright (c) 1999 Russell King
+ *
+ */
+#ifndef __ASM_ARCH_MMU_H
+#define __ASM_ARCH_MMU_H
+
+/*
+ * Task size: 3GB
+ */
+#define TASK_SIZE	(0xc0000000UL)
+
+/*
+ * Page offset: 3GB
+ */
+#define PAGE_OFFSET	(0xc0000000UL)
+
+/*
+ * On NexusPCI, the DRAM is contiguous
+ */
+#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET + 0x40000000)
+#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET - 0x40000000)
+#define __virt_to_phys__is_a_macro
+#define __phys_to_virt__is_a_macro
+
+/*
+ * On the PCI bus the DRAM appears at address 0
+ */
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x) ((x) - PAGE_OFFSET)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x) ((x) + PAGE_OFFSET)
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-nexuspci/mm-init.h linux/include/asm-arm/arch-nexuspci/mm-init.h
--- v2.2.7/linux/include/asm-arm/arch-nexuspci/mm-init.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-nexuspci/mm-init.h	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-/*
- * linux/include/asm-arm/arch-nexuspci/mmap.h
- *
- * Copyright (C) 1998 Philip Blundell
- */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-nexuspci/mmu.h linux/include/asm-arm/arch-nexuspci/mmu.h
--- v2.2.7/linux/include/asm-arm/arch-nexuspci/mmu.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-nexuspci/mmu.h	Wed Dec 31 16:00:00 1969
@@ -1,26 +0,0 @@
-/*
- * linux/include/asm-arm/arch-nexuspci/mmu.h
- *
- * Copyright (c) 1997, 1998 Philip Blundell.
- *
- */
-#ifndef __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
-
-/*
- * On NexusPCI, the DRAM is contiguous
- */
-#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET + 0x40000000)
-#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET - 0x40000000)
-#define __virt_to_phys__is_a_macro
-#define __phys_to_virt__is_a_macro
-
-/*
- * On the PCI bus the DRAM appears at address 0
- */
-#define __virt_to_bus__is_a_macro
-#define __virt_to_bus(x) ((x) - PAGE_OFFSET)
-#define __bus_to_virt__is_a_macro
-#define __bus_to_virt(x) ((x) + PAGE_OFFSET)
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-nexuspci/processor.h linux/include/asm-arm/arch-nexuspci/processor.h
--- v2.2.7/linux/include/asm-arm/arch-nexuspci/processor.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-nexuspci/processor.h	Sat May  8 11:06:57 1999
@@ -1,13 +1,18 @@
 /*
- * linux/include/asm-arm/arch-ebsa110/processor.h
+ * linux/include/asm-arm/arch-nexuspci/processor.h
  *  from linux/include/asm-arm/arch-ebsa110/processor.h
  *
- * Copyright (C) 1996,1997,1998 Russell King
+ * Copyright (C) 1996-1999 Russell King
+ *
+ * Changelog:
+ *  21-Mar-1999	RMK	Added asm/arch/memory.h
  */
 
 #ifndef __ASM_ARCH_PROCESSOR_H
 #define __ASM_ARCH_PROCESSOR_H
 
+#include <asm/arch/memory.h>
+
 /*
  * Bus types
  */
@@ -16,17 +21,9 @@
 #define MCA_bus 0
 #define MCA_bus__is_a_macro /* for versions in ksyms.c */
 
-/*
- * User space: 3GB
- */
-#define TASK_SIZE	(0xc0000000UL)
-
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
 #define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
-
-#define INIT_MMAP \
-{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-nexuspci/time.h linux/include/asm-arm/arch-nexuspci/time.h
--- v2.2.7/linux/include/asm-arm/arch-nexuspci/time.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-nexuspci/time.h	Sat May  8 11:06:57 1999
@@ -17,37 +17,53 @@
 	return 0;
 }
 
-extern __inline__ int reset_timer (void)
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	static int count = 50;
+
 	writeb(0x90, UART_BASE + 8);
-	if (--count == 0)
-	{
+
+	if (--count == 0) {
 		static int state = 1;
 		state ^= 1;
 		writeb(0x1a + state, INTCONT);
 		count = 50;
 	}
+
 	readb(UART_BASE + 0x14);
 	readb(UART_BASE + 0x14);
 	readb(UART_BASE + 0x14);
 	readb(UART_BASE + 0x14);
 	readb(UART_BASE + 0x14);
 	readb(UART_BASE + 0x14);
-	return 1;
+
+	do_timer(regs);	
 }
 
-extern __inline__ unsigned long setup_timer (void)
+static struct irqaction timerirq = {
+	timer_interrupt,
+	0,
+	0,
+	"timer",
+	NULL,
+	NULL
+};
+
+extern __inline__ void setup_timer(void)
 {
 	int tick = 3686400 / 16 / 2 / 100;
+
 	writeb(tick & 0xff, UART_BASE + 0x1c);
 	writeb(tick >> 8, UART_BASE + 0x18);
 	writeb(0x80, UART_BASE + 8);
 	writeb(0x10, UART_BASE + 0x14);
+
 	/*
 	 * Default the date to 1 Jan 1970 0:0:0
 	 * You will have to run a time daemon to set the
 	 * clock correctly at bootup
 	 */
-	return mktime(1970, 1, 1, 0, 0, 0);
+	xtime.tv_sec = mktime(1970, 1, 1, 0, 0, 0);
+
+	setup_arm_irq(IRQ_TIMER, &timerirq);
 }
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/a.out.h linux/include/asm-arm/arch-rpc/a.out.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/a.out.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-rpc/a.out.h	Sat May  8 11:06:57 1999
@@ -1,15 +1,16 @@
 /*
  * linux/include/asm-arm/arch-rpc/a.out.h
  *
- * Copyright (C) 1996 Russell King
+ * Copyright (C) 1996-1999 Russell King
  */
-
 #ifndef __ASM_ARCH_A_OUT_H
 #define __ASM_ARCH_A_OUT_H
 
-#ifdef __KERNEL__
-#define STACK_TOP		((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
-#endif
+#include <asm/arch/memory.h>
+
+#define STACK_TOP \
+	((current->personality == PER_LINUX_32BIT) ? \
+	 TASK_SIZE : 0x04000000)
 
 #endif
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/hardware.h linux/include/asm-arm/arch-rpc/hardware.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/hardware.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-rpc/hardware.h	Sat May  8 11:06:57 1999
@@ -1,19 +1,19 @@
 /*
  * linux/include/asm-arm/arch-rpc/hardware.h
  *
- * Copyright (C) 1996 Russell King.
+ * Copyright (C) 1996-1999 Russell King.
  *
  * This file contains the hardware definitions of the RiscPC series machines.
  */
-
 #ifndef __ASM_ARCH_HARDWARE_H
 #define __ASM_ARCH_HARDWARE_H
 
+#include <asm/arch/memory.h>
+
 /*
  * What hardware must be present
  */
 #define HAS_IOMD
-#include <asm/iomd.h>
 #define HAS_VIDC20
 
 /* Hardware addresses of major areas.
@@ -26,7 +26,7 @@
 
 #define EASI_SIZE		0x08000000	/* EASI I/O */
 #define EASI_START		0x08000000
-#define EASI_BASE		0xe8000000
+#define EASI_BASE		0xe5000000
 
 #define IO_START		0x03000000	/* I/O */
 #define IO_SIZE			0x01000000
@@ -38,6 +38,8 @@
 #define SCREEN1_END		0xd8000000
 #define SCREEN1_BASE		0xd0000000
 
+#define FLUSH_BASE		0xdf000000
+
 
 #ifndef __ASSEMBLER__
 
@@ -47,8 +49,9 @@
 #define IO_VIDC_AUDIO_BASE	0x80140000
 #define IO_VIDC_BASE		0x80100000
 #define IO_IOMD_BASE		0x80080000
+#define IOC_BASE		0x80080000
 
-#define IO_EC_EASI_BASE		0x82000000
+#define IO_EC_EASI_BASE		0x81400000
 #define IO_EC_IOC4_BASE		0x8009c000
 #define IO_EC_IOC_BASE		0x80090000
 #define IO_EC_MEMC8_BASE	0x8000ac00
@@ -59,7 +62,6 @@
  */
 #define EXPMASK_BASE		((volatile unsigned char *)0xe0360000)
 #define IOEB_BASE		((volatile unsigned char *)0xe0350050)
-#define IOC_BASE		((volatile unsigned char *)0xe0200000)
 #define PCIO_FLOPPYDMABASE	((volatile unsigned char *)0xe002a000)
 #define PCIO_BASE		0xe0010000
 
@@ -67,23 +69,19 @@
  * Offsets from RAM base
  */
 #define PARAMS_OFFSET		0x0100
-#define KERNEL_OFFSET		0x8000
 
 /*
  * RAM definitions
  */
-#define MAPTOPHYS(x)		(x)
-#define KERNTOPHYS(x)		((unsigned long)(&x))
 #define GET_MEMORY_END(p)	(PAGE_OFFSET + p->u1.s.page_size * \
 						(p->u1.s.pages_in_bank[0] + \
 						 p->u1.s.pages_in_bank[1] + \
 						 p->u1.s.pages_in_bank[2] + \
 						 p->u1.s.pages_in_bank[3]))
 
-#define KERNEL_BASE		(PAGE_OFFSET + KERNEL_OFFSET)
 #define PARAMS_BASE		(PAGE_OFFSET + PARAMS_OFFSET)
 #define Z_PARAMS_BASE		(RAM_START + PARAMS_OFFSET)
-#define SAFE_ADDR		0x00000000	/* ROM */
+#define FLUSH_BASE_PHYS		0x00000000	/* ROM */
 
 #else
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/irq.h linux/include/asm-arm/arch-rpc/irq.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/irq.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/arch-rpc/irq.h	Sat May  8 11:06:57 1999
@@ -7,6 +7,9 @@
  *   10-10-1996	RMK	Brought up to date with arch-sa110eval
  *   22-08-1998	RMK	Restructured IRQ routines
  */
+#include <asm/iomd.h>
+
+#define fixup_irq(x) (x)
 
 static void rpc_mask_irq_ack_a(unsigned int irq)
 {
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/keyboard.h linux/include/asm-arm/arch-rpc/keyboard.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/keyboard.h	Wed Apr 28 11:37:31 1999
+++ linux/include/asm-arm/arch-rpc/keyboard.h	Sat May  8 11:06:57 1999
@@ -10,7 +10,6 @@
 
 #define NR_SCANCODES 128
 
-extern int ps2kbd_translate(unsigned char scancode, unsigned char *keycode_p, char *up_flag_p);
 extern void ps2kbd_leds(unsigned char leds);
 extern void ps2kbd_init_hw(void);
 extern unsigned char ps2kbd_sysrq_xlate[NR_SCANCODES];
@@ -18,15 +17,7 @@
 #define kbd_setkeycode(sc,kc)		(-EINVAL)
 #define kbd_getkeycode(sc)		(-EINVAL)
 
-/* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode)
- * Returns  : 0 to ignore scancode, *keycode set to keycode, *up_flag
- *            set to 0200 if scancode indicates release
- */
-#ifdef NEW_KEYBOARD
-#define kbd_translate(sc, kcp, ufp, rm)	ps2kbd_translate(sc, kcp, ufp)
-#else
-#define kbd_translate(sc, kcp, rm) ({ unsigned int up_flag; ps2kbd_translate(sc, kcp, &up_flag); })
-#endif
+#define kbd_translate(sc, kcp, rm)	({ *(kcp) = (sc); 1; })
 #define kbd_unexpected_up(kc)		(0200)
 #define kbd_leds(leds)			ps2kbd_leds(leds)
 #define kbd_init_hw()			ps2kbd_init_hw()
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/memory.h linux/include/asm-arm/arch-rpc/memory.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/memory.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/arch-rpc/memory.h	Sat May  8 11:06:57 1999
@@ -0,0 +1,41 @@
+/*
+ * linux/include/asm-arm/arch-rpc/memory.h
+ *
+ * Copyright (c) 1996,1997,1998 Russell King.
+ *
+ * Changelog:
+ *  20-Oct-1996	RMK	Created
+ *  31-Dec-1997	RMK	Fixed definitions to reduce warnings
+ *  11-Jan-1998	RMK	Uninlined to reduce hits on cache
+ *  08-Feb-1998	RMK	Added __virt_to_bus and __bus_to_virt
+ *  21-Mar-1999	RMK	Renamed to memory.h
+ *		RMK	Added TASK_SIZE and PAGE_OFFSET
+ */
+#ifndef __ASM_ARCH_MMU_H
+#define __ASM_ARCH_MMU_H
+
+/*
+ * Task size: 3GB
+ */
+#define TASK_SIZE	(0xc0000000UL)
+
+/*
+ * Page offset: 3GB
+ */
+#define PAGE_OFFSET	(0xc0000000UL)
+
+#ifndef __ASSEMBLY__
+extern unsigned long __virt_to_phys(unsigned long vpage);
+extern unsigned long __phys_to_virt(unsigned long ppage);
+#endif
+
+/*
+ * These are exactly the same on the RiscPC as the
+ * physical memory view.
+ */
+#define __virt_to_bus__is_a_macro
+#define __virt_to_bus(x) __virt_to_phys(x)
+#define __bus_to_virt__is_a_macro
+#define __bus_to_virt(x) __phys_to_virt(x)
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/mmu.h linux/include/asm-arm/arch-rpc/mmu.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/mmu.h	Tue Apr 14 14:29:25 1998
+++ linux/include/asm-arm/arch-rpc/mmu.h	Wed Dec 31 16:00:00 1969
@@ -1,27 +0,0 @@
-/*
- * linux/include/asm-arm/arch-rpc/mmu.h
- *
- * Copyright (c) 1996,1997,1998 Russell King.
- *
- * Changelog:
- *  20-10-1996	RMK	Created
- *  31-12-1997	RMK	Fixed definitions to reduce warnings
- *  11-01-1998	RMK	Uninlined to reduce hits on cache
- *  08-02-1998	RMK	Added __virt_to_bus and __bus_to_virt
- */
-#ifndef __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
-
-extern unsigned long __virt_to_phys(unsigned long vpage);
-extern unsigned long __phys_to_virt(unsigned long ppage);
-
-/*
- * These are exactly the same on the RiscPC as the
- * physical memory view.
- */
-#define __virt_to_bus__is_a_macro
-#define __virt_to_bus(x) __virt_to_phys(x)
-#define __bus_to_virt__is_a_macro
-#define __bus_to_virt(x) __phys_to_virt(x)
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/oldlatches.h linux/include/asm-arm/arch-rpc/oldlatches.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/oldlatches.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-rpc/oldlatches.h	Wed Dec 31 16:00:00 1969
@@ -1,9 +0,0 @@
-/*
- * Dummy oldlatches.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifdef __need_oldlatches
-#error "Old latches not present in this (rpc) machine"
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/processor.h linux/include/asm-arm/arch-rpc/processor.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/processor.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-rpc/processor.h	Sat May  8 11:06:57 1999
@@ -1,15 +1,18 @@
 /*
  * linux/include/asm-arm/arch-rpc/processor.h
  *
- * Copyright (c) 1996 Russell King.
+ * Copyright (c) 1996-1999 Russell King.
  *
  * Changelog:
- *  10-09-1996	RMK	Created
+ *  10-Sep-1996	RMK	Created
+ *  21-Mar-1999	RMK	Added asm/arch/memory.h
  */
 
 #ifndef __ASM_ARCH_PROCESSOR_H
 #define __ASM_ARCH_PROCESSOR_H
 
+#include <asm/arch/memory.h>
+
 /*
  * Bus types
  */
@@ -18,17 +21,9 @@
 #define MCA_bus 0
 #define MCA_bus__is_a_macro /* for versions in ksyms.c */
 
-/*
- * User space: 3GB
- */
-#define TASK_SIZE	(0xc0000000UL)
-
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
 #define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
-
-#define INIT_MMAP \
-{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
 
 #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/system.h linux/include/asm-arm/arch-rpc/system.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/system.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-rpc/system.h	Sat May  8 11:06:57 1999
@@ -6,7 +6,7 @@
 #ifndef __ASM_ARCH_SYSTEM_H
 #define __ASM_ARCH_SYSTEM_H
 
-#include <asm/proc-fns.h>
+#include <asm/iomd.h>
 
 #define arch_reset(mode) {						\
 	extern void ecard_reset (int card);				\
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/time.h linux/include/asm-arm/arch-rpc/time.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/time.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/arch-rpc/time.h	Sat May  8 11:06:57 1999
@@ -8,6 +8,9 @@
  *  10-Oct-1996	RMK	Brought up to date with arch-sa110eval
  *  04-Dec-1997	RMK	Updated for new arch/arm/time.c
  */
+#include <asm/iomd.h>
+
+static long last_rtc_update = 0;	/* last time the cmos clock got updated */
 
 extern __inline__ unsigned long gettimeoffset (void)
 {
@@ -51,46 +54,148 @@
 	return offset;
 }
 
-/*
- * No need to reset the timer at every irq
- */
-#define reset_timer() 1
+extern int iic_control(unsigned char, int, char *, int);
 
-/*
- * Updating of the RTC.  We don't currently write the time to the
- * CMOS clock.
- */
-#define update_rtc()
+static int set_rtc_time(unsigned long nowtime)
+{
+	char buf[5], ctrl;
+
+	if (iic_control(0xa1, 0, &ctrl, 1) != 0)
+		printk("RTC: failed to read control reg\n");
+
+	/*
+	 * Reset divider
+	 */
+	ctrl |= 0x80;
+
+	if (iic_control(0xa0, 0, &ctrl, 1) != 0)
+		printk("RTC: failed to stop the clock\n");
+
+	/*
+	 * We only set the time - we don't set the date.
+	 * This means that there is the possibility once
+	 * a day for the correction to disrupt the date.
+	 * We really ought to write the time and date, or
+	 * nothing at all.
+	 */
+	buf[0] = 0;
+	buf[1] = nowtime % 60;		nowtime /= 60;
+	buf[2] = nowtime % 60;		nowtime /= 60;
+	buf[3] = nowtime % 24;
+
+	BIN_TO_BCD(buf[1]);
+	BIN_TO_BCD(buf[2]);
+	BIN_TO_BCD(buf[3]);
+
+	if (iic_control(0xa0, 1, buf, 4) != 0)
+		printk("RTC: Failed to set the time\n");
+
+	/*
+	 * Re-enable divider
+	 */
+	ctrl &= ~0x80;
+
+	if (iic_control(0xa0, 0, &ctrl, 1) != 0)
+		printk("RTC: failed to start the clock\n");
+
+	return 0;
+}
+
+extern __inline__ unsigned long get_rtc_time(void)
+{
+	unsigned int year, i;
+	char buf[8];
+
+	/*
+	 * The year is not part of the RTC counter
+	 * registers, and is stored in RAM.  This
+	 * means that it will not be automatically
+	 * updated.
+	 */
+	if (iic_control(0xa1, 0xc0, buf, 1) != 0)
+		printk("RTC: failed to read the year\n");
+
+	/*
+	 * If the year is before 1970, then the year
+	 * is actually 100 in advance.  This gives us
+	 * a year 2070 bug...
+	 */
+	year = 1900 + buf[0];
+	if (year < 1970)
+		year += 100;
+
+	/*
+	 * Read the time and date in one go - this
+	 * will ensure that we don't get any effects
+	 * due to carry (the RTC latches the counters
+	 * during a read).
+	 */
+	if (iic_control(0xa1, 2, buf, 5) != 0) {
+		printk("RTC: failed to read the time and date\n");
+		memset(buf, 0, sizeof(buf));
+	}
+
+	/*FIXME:
+	 * This doesn't seem to work.  Does RISC OS
+	 * actually use the RTC year?  It doesn't
+	 * seem to.  In that case, how does it update
+	 * the CMOS year?
+	 */
+	/*year += (buf[3] >> 6) & 3;*/
+
+	/*
+	 * The RTC combines years with date and weekday
+	 * with month.  We need to mask off this extra
+	 * information before converting the date to
+	 * binary.
+	 */
+	buf[4] &= 0x1f;
+	buf[3] &= 0x3f;
+printk("Year %4d mon %02X day %02X hour %02X min %02X sec %02X\n", year, buf[4], buf[3], buf[2], buf[1], buf[0]);
+	for (i = 0; i < 5; i++)
+		BCD_TO_BIN(buf[i]);
+
+	return mktime(year, buf[4], buf[3], buf[2], buf[1], buf[0]);
+}
+
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	do_timer(regs);
+
+	/* If we have an externally synchronized linux clock, then update
+	 * CMOS clock accordingly every ~11 minutes.  Set_rtc_mmss() has to be
+	 * called as close as possible to 500 ms before the new second starts.
+	 */
+	if ((time_status & STA_UNSYNC) == 0 &&
+	    xtime.tv_sec > last_rtc_update + 660 &&
+	    xtime.tv_usec >= 50000 - (tick >> 1) &&
+	    xtime.tv_usec < 50000 + (tick >> 1)) {
+		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 */
+	}
+}
+
+static struct irqaction timerirq = {
+	timer_interrupt,
+	0,
+	0,
+	"timer",
+	NULL,
+	NULL
+};
 
 /*
  * Set up timer interrupt, and return the current time in seconds.
  */
-extern __inline__ unsigned long setup_timer (void)
+extern __inline__ void setup_timer(void)
 {
-	extern int iic_control (unsigned char, int, char *, int);
-	unsigned int year, mon, day, hour, min, sec;
-	char buf[8];
-
 	outb(LATCH & 255, IOMD_T0LTCHL);
 	outb(LATCH >> 8, IOMD_T0LTCHH);
 	outb(0, IOMD_T0GO);
 
-	iic_control (0xa0, 0xc0, buf, 1);
-	year = buf[0];
-	if ((year += 1900) < 1970)
-		year += 100;
-
-	iic_control (0xa0, 2, buf, 5);
-	mon  = buf[4] & 0x1f;
-	day  = buf[3] & 0x3f;
-	hour = buf[2];
-	min  = buf[1];
-	sec  = buf[0];
-	BCD_TO_BIN(mon);
-	BCD_TO_BIN(day);
-	BCD_TO_BIN(hour);
-	BCD_TO_BIN(min);
-	BCD_TO_BIN(sec);
+	xtime.tv_sec = get_rtc_time();
 
-	return mktime(year, mon, day, hour, min, sec);
+	setup_arm_irq(IRQ_TIMER, &timerirq);
 }
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-rpc/uncompress.h linux/include/asm-arm/arch-rpc/uncompress.h
--- v2.2.7/linux/include/asm-arm/arch-rpc/uncompress.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/arch-rpc/uncompress.h	Sat May  8 11:06:57 1999
@@ -5,7 +5,6 @@
  */
 #define VIDMEM ((char *)SCREEN_START)
  
-#include "../arch/arm/drivers/char/font.h"
 #include <asm/hardware.h>
 #include <asm/io.h>
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/a.out.h linux/include/asm-arm/arch-vnc/a.out.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/a.out.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-vnc/a.out.h	Wed Dec 31 16:00:00 1969
@@ -1,14 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/a.out.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifndef __ASM_ARCH_A_OUT_H
-#define __ASM_ARCH_A_OUT_H
-
-#ifdef __KERNEL__
-#define STACK_TOP		((current->personality==PER_LINUX_32BIT)? 0xc0000000 : 0x04000000)
-#endif
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/dma.h linux/include/asm-arm/arch-vnc/dma.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/dma.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-vnc/dma.h	Wed Dec 31 16:00:00 1969
@@ -1,19 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/dma.h
- *
- * Architecture DMA routes
- *
- * Copyright (C) 1997.1998 Russell King
- */
-#ifndef __ASM_ARCH_DMA_H
-#define __ASM_ARCH_DMA_H
-
-/*
- * This is the maximum DMA address that can be DMAd to.
- * There should not be more than (0xd0000000 - 0xc0000000)
- * bytes of RAM.
- */
-#define MAX_DMA_ADDRESS		0xd0000000
-#define MAX_DMA_CHANNELS	8
-
-#endif /* _ASM_ARCH_DMA_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/hardware.h linux/include/asm-arm/arch-vnc/hardware.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/hardware.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-vnc/hardware.h	Wed Dec 31 16:00:00 1969
@@ -1,74 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/hardware.h
- *
- * Copyright (C) 1998 Corel Computer/Russell King.
- *
- * This file contains the hardware definitions of the VNC.
- */
-
-/*    Logical    Physical
- * 0xffe00000	0x7c000000	PCI I/O space
- * 0xfe000000	0x42000000	CSR
- * 0xfd000000	0x78000000	Outbound write flush
- * 0xfc000000	0x79000000	PCI IACK/special space
- * 0xf9000000	0x7a000000	PCI Config type 1
- * 0xf8000000	0x7b000000	PCI Config type 0
- * 
- */
-
-#include <asm/dec21285.h>
-
-#define IO_BASE_ARM_CSR		0xfe000000
-#define PCI_IACK		0xfc000000
- 
-/* LEDs */
-#define XBUS_LEDS		((volatile unsigned char *)0xfff12000)
-#define XBUS_LED_AMBER		(1 << 0)
-#define XBUS_LED_GREEN		(1 << 1)
-#define XBUS_LED_RED		(1 << 2)
-#define XBUS_LED_TOGGLE		(1 << 8)
-
-/* PIC irq control */
-#define PIC_LO			0x20
-#define PIC_MASK_LO		0x21
-#define PIC_HI			0xA0
-#define PIC_MASK_HI		0xA1
-
-#define IO_END			0xffffffff
-#define IO_BASE			0xe0000000
-#define IO_SIZE			(IO_END - IO_BASE)
-
-#define HAS_PCIO
-#define PCIO_BASE		0xffe00000
-
-#define KERNTOPHYS(a)		((unsigned long)(&a))
-
-//#define PARAMS_OFFSET		0x0100
-//#define PARAMS_BASE		(PAGE_OFFSET + PARAMS_OFFSET)
-
-#define FLUSH_BASE_PHYS		0x50000000
-
-/* GPIO pins */
-#define GPIO_CCLK		0x800
-#define GPIO_DSCLK		0x400
-#define GPIO_E2CLK		0x200
-#define GPIO_IOLOAD		0x100
-#define GPIO_RED_LED		0x080
-#define GPIO_WDTIMER		0x040
-#define GPIO_DATA		0x020
-#define GPIO_IOCLK		0x010
-#define GPIO_DONE		0x008
-#define GPIO_FAN		0x004
-#define GPIO_GREEN_LED		0x002
-#define GPIO_RESET		0x001
-
-/* CPLD pins */
-#define CPLD_DSRESET		8
-#define CPLD_UNMUTE		2
-
-#ifndef __ASSEMBLY__
-extern void gpio_modify_op(int mask, int set);
-extern void gpio_modify_io(int mask, int in);
-extern int  gpio_read(void);
-extern void cpld_modify(int mask, int set);
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/ide.h linux/include/asm-arm/arch-vnc/ide.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/ide.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/arch-vnc/ide.h	Wed Dec 31 16:00:00 1969
@@ -1,42 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/ide.h
- *
- * Copyright (c) 1998 Russell King
- *
- * Modifications:
- *  29-07-1998	RMK	Major re-work of IDE architecture specific code
- */
-#include <asm/irq.h>
-
-/*
- * Set up a hw structure for a specified data port, control port and IRQ.
- * This should follow whatever the default interface uses.
- */
-static __inline__ void
-ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int irq)
-{
-	ide_ioreg_t reg = (ide_ioreg_t) data_port;
-	int i;
-
-	memset(hw, 0, sizeof(*hw));
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
-		hw->io_ports[i] = reg;
-		reg += 1;
-	}
-	hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
-	hw->irq = irq;
-}
-
-/*
- * This registers the standard ports for this architecture with the IDE
- * driver.
- */
-static __inline__ void
-ide_init_default_hwifs(void)
-{
-	hw_regs_t hw;
-
-	ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, IRQ_HARDDISK);
-	ide_register_hw(&hw, NULL);
-}
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/io.h linux/include/asm-arm/arch-vnc/io.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/io.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-vnc/io.h	Wed Dec 31 16:00:00 1969
@@ -1,176 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/io.h
- *
- * Copyright (C) 1997,1998 Russell King
- *
- * Modifications:
- *  06-Dec-1997	RMK	Created.
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-/*
- * This architecture does not require any delayed IO, and
- * has the constant-optimised IO
- */
-#undef	ARCH_IO_DELAY
-
-/*
- * Dynamic IO functions - let the compiler
- * optimize the expressions
- */
-#define DECLARE_DYN_OUT(fnsuffix,instr,typ)					\
-extern __inline__ void __out##fnsuffix (unsigned int value, unsigned int port)	\
-{										\
-	__asm__ __volatile__(							\
-	"str%?" ##instr## "	%0, [%1, %2]		@ out"###fnsuffix	\
-	: 									\
-	: "r" (value), "r" (PCIO_BASE), typ (port));				\
-}
-
-#define DECLARE_DYN_IN(sz,fnsuffix,instr,typ)					\
-extern __inline__ unsigned sz __in##fnsuffix (unsigned int port)		\
-{										\
-	unsigned long value;							\
-	__asm__ __volatile__(							\
-	"ldr%?" ##instr## "	%0, [%1, %2]		@ in"###fnsuffix	\
-	: "=&r" (value)								\
-	: "r" (PCIO_BASE), typ (port));						\
-	return (unsigned sz)value;						\
-}
-
-extern __inline__ unsigned int __ioaddr (unsigned int port)			\
-{										\
-	return (unsigned int)(PCIO_BASE + port);				\
-}
-
-#define DECLARE_IO(sz,fnsuffix,instr,typ)	\
-	DECLARE_DYN_OUT(fnsuffix,instr,typ)	\
-	DECLARE_DYN_IN(sz,fnsuffix,instr,typ)
-
-DECLARE_IO(char,b,"b","Jr")
-DECLARE_IO(short,w,"h","r")
-DECLARE_IO(long,l,"","Jr")
-
-#undef DECLARE_IO
-#undef DECLARE_DYN_OUT
-#undef DECLARE_DYN_IN
-
-/*
- * Constant address IO functions
- *
- * These have to be macros for the 'J' constraint to work -
- * +/-4096 immediate operand.
- */
-#define __outbc(value,port)							\
-({										\
-	__asm__ __volatile__(							\
-	"strb	%0, [%1, %2]				@ outbc"		\
-	:									\
-	: "r" (value), "r" (PCIO_BASE), "Jr" (port));				\
-})
-
-#define __inbc(port)								\
-({										\
-	unsigned char result;							\
-	__asm__ __volatile__(							\
-	"ldrb	%0, [%1, %2]				@ inbc"			\
-	: "=r" (result)								\
-	: "r" (PCIO_BASE), "Jr" (port));					\
-	result;									\
-})
-
-#define __outwc(value,port)							\
-({										\
-	__asm__ __volatile__(							\
-	"strh	%0, [%1, %2]				@ outwc"		\
-	:									\
-	: "r" (value), "r" (PCIO_BASE), "r" (port));				\
-})
-
-#define __inwc(port)								\
-({										\
-	unsigned short result;							\
-	__asm__ __volatile__(							\
-	"ldrh	%0, [%1, %2]				@ inwc"			\
-	: "=r" (result)								\
-	: "r" (PCIO_BASE), "r" (port));						\
-	result & 0xffff;							\
-})
-
-#define __outlc(value,port)							\
-({										\
-	__asm__ __volatile__(							\
-	"str	%0, [%1, %2]				@ outlc"		\
-	:									\
-	: "r" (value), "r" (PCIO_BASE), "Jr" (port));				\
-})
-
-#define __inlc(port)								\
-({										\
-	unsigned long result;							\
-	__asm__ __volatile__(							\
-	"ldr	%0, [%1, %2]				@ inlc"			\
-	: "=r" (result)								\
-	: "r" (PCIO_BASE), "Jr" (port));					\
-	result;									\
-})
-
-#define __ioaddrc(port)								\
-({										\
-	unsigned long addr;							\
-	addr = PCIO_BASE + port;						\
-	addr;									\
-})
-
-/*
- * Translated address IO functions
- *
- * IO address has already been translated to a virtual address
- */
-#define outb_t(v,p)								\
-	(*(volatile unsigned char *)(p) = (v))
-
-#define inb_t(p)								\
-	(*(volatile unsigned char *)(p))
-
-#define outl_t(v,p)								\
-	(*(volatile unsigned long *)(p) = (v))
-
-#define inl_t(p)								\
-	(*(volatile unsigned long *)(p))
-
-/*
- * This is not sufficient... (and it's a hack anyway)
- */
-static inline void writeb(unsigned char b, unsigned int addr)
-{
-	*(volatile unsigned char *)(0xe0000000 + (addr)) = b;
-}
-
-static inline unsigned char readb(unsigned int addr)
-{
-	return *(volatile unsigned char *)(0xe0000000 + (addr));
-}
-
-static inline void writew(unsigned short b, unsigned int addr)
-{
-	*(volatile unsigned short *)(0xe0000000 + (addr)) = b;
-}
-
-static inline unsigned short readw(unsigned int addr)
-{
-	return *(volatile unsigned short *)(0xe0000000 + (addr));
-}
-
-static inline void writel(unsigned long b, unsigned int addr)
-{
-	*(volatile unsigned long *)(0xe0000000 + (addr)) = b;
-}
-
-static inline unsigned long readl(unsigned int addr)
-{
-	return *(volatile unsigned long *)(0xe0000000 + (addr));
-}
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/irq.h linux/include/asm-arm/arch-vnc/irq.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/irq.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/arch-vnc/irq.h	Wed Dec 31 16:00:00 1969
@@ -1,156 +0,0 @@
-/*
- * include/asm-arm/arch-vnc/irq.h
- *
- * Copyright (C) 1998 Russell King
- *
- * Changelog:
- *   22-08-1998	RMK	Restructured IRQ routines
- */
-
-#include <asm/dec21285.h>
-#include <asm/irq.h>
-
-/*
- * FootBridge IRQ translation table
- *  Converts form our IRQ numbers into FootBridge masks (defined in irqs.h)
- */
-static int fb_irq_mask[16] = {
-	0,
-	IRQ_MASK_SOFTIRQ,
-	IRQ_MASK_UART_DEBUG,
-	0,
-	IRQ_MASK_TIMER0,
-	IRQ_MASK_TIMER1,
-	IRQ_MASK_TIMER2,
-	IRQ_MASK_WATCHDOG,
-	IRQ_MASK_ETHER10,
-	IRQ_MASK_ETHER100,
-	IRQ_MASK_VIDCOMP,
-	IRQ_MASK_EXTERN_IRQ,
-	IRQ_MASK_DMA1,
-	0,
-	0,
-	IRQ_MASK_PCI_ERR
-};
-
-static void vnc_mask_csr_irq(unsigned int irq)
-{
-	*CSR_IRQ_DISABLE = fb_irq_mask[irq];
-}
-
-static void vnc_unmask_csr_irq(unsigned int irq)
-{
-	*CSR_IRQ_ENABLE = fb_irq_mask[irq];
-}
-
-static void vnc_mask_pic_lo_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
-}
-
-static void vnc_mask_ack_pic_lo_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_LO) | mask, PIC_MASK_LO);
-	outb(0x20, PIC_LO);
-}
-
-static void vnc_unmask_pic_lo_irq(unsigned int irq)
-{
-	unsigned int mask = ~(1 << (irq & 7));
-
-	outb(inb(PIC_MASK_LO) & mask, PIC_MASK_LO);
-}
-
-static void vnc_mask_pic_hi_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
-}
-
-static void vnc_mask_ack_pic_hi_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_HI) | mask, PIC_MASK_HI);
-	outb(0x62, PIC_LO);
-	outb(0x20, PIC_HI);
-}
-
-static void vnc_unmask_pic_hi_irq(unsigned int irq)
-{
-	unsigned int mask = 1 << (irq & 7);
-
-	outb(inb(PIC_MASK_HI) & ~mask, PIC_MASK_HI);
-}
-
-static void no_action(int irq, void *dev_id, struct pt_regs *regs)
-{
-}
-
-static struct irqaction irq_cascade = { no_action, 0, 0, "cascade", NULL, NULL };
-
-static __inline__ void irq_init_irq(void)
-{
-	unsigned int irq;
-
-	outb(0x11, PIC_LO);
-	outb(0x10, PIC_MASK_LO);
-	outb(0x04, PIC_MASK_LO);
-	outb(1, PIC_MASK_LO);
-
-	outb(0x11, PIC_HI);
-	outb(0x18, PIC_MASK_HI);
-	outb(0x02, PIC_MASK_HI);
-	outb(1, PIC_MASK_HI);
-
-	*CSR_IRQ_DISABLE = ~IRQ_MASK_EXTERN_IRQ;
-	*CSR_IRQ_ENABLE  = IRQ_MASK_EXTERN_IRQ;
-	*CSR_FIQ_DISABLE = -1;
-
-	for (irq = 0; irq < NR_IRQS; irq++) {
-		irq_desc[irq].valid	= 1;
-		irq_desc[irq].probe_ok	= 1;
-
-		if (irq < 16) {
-			irq_desc[irq].mask_ack	= vnc_mask_csr_irq;
-			irq_desc[irq].mask	= vnc_mask_csr_irq;
-			irq_desc[irq].unmask	= vnc_unmask_csr_irq;
-		} else if (irq < 24) {
-irq_desc[irq].probe_ok = 0;
-			irq_desc[irq].mask_ack	= vnc_mask_ack_pic_lo_irq;
-			irq_desc[irq].mask	= vnc_mask_pic_lo_irq;
-			irq_desc[irq].unmask	= vnc_unmask_pic_lo_irq;
-		} else {
-irq_desc[irq].probe_ok = 0;
-			irq_desc[irq].mask_ack	= vnc_mask_ack_pic_hi_irq;
-			irq_desc[irq].mask	= vnc_mask_pic_hi_irq;
-			irq_desc[irq].unmask	= vnc_unmask_pic_hi_irq;
-		}
-	}
-
-	irq_desc[0].probe_ok = 0;
-	irq_desc[IRQ_SOFTIRQ].probe_ok = 0;
-	irq_desc[IRQ_CONRX].probe_ok = 0;
-	irq_desc[IRQ_CONTX].probe_ok = 0;
-	irq_desc[IRQ_TIMER0].probe_ok = 0;
-	irq_desc[IRQ_TIMER1].probe_ok = 0;
-	irq_desc[IRQ_TIMER2].probe_ok = 0;
-	irq_desc[IRQ_WATCHDOG].probe_ok = 0;
-	irq_desc[IRQ_DMA1].probe_ok = 0;
-	irq_desc[13].probe_ok = 0;
-	irq_desc[14].probe_ok = 0;
-	irq_desc[IRQ_PCI_ERR].probe_ok = 0;
-	irq_desc[IRQ_PIC_HI].probe_ok = 0;
-	irq_desc[29].probe_ok = 0;
-	irq_desc[31].probe_ok = 0;
-
-	outb(0xff, PIC_MASK_LO);
-	outb(0xff, PIC_MASK_HI);
-
-	setup_arm_irq(IRQ_PIC_HI, &irq_cascade);
-}
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/irqs.h linux/include/asm-arm/arch-vnc/irqs.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/irqs.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-vnc/irqs.h	Wed Dec 31 16:00:00 1969
@@ -1,67 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/irqs.h
- *
- * Copyright (C) 1998 Russell King
- */
-
-#define NR_IRQS			32
-
-/*
- * This is a list of all interrupts that the 21285
- * can generate
- */
-#define IRQ_SOFTIRQ		1	/* from FB.1 */
-#define IRQ_CONRX		2	/* from FB.2 */
-#define IRQ_CONTX		3	/* from FB.3 */
-#define IRQ_TIMER0		4	/* from FB.4 */
-#define IRQ_TIMER1		5	/* from FB.5 */
-#define IRQ_TIMER2		6	/* from FB.6 */
-#define IRQ_WATCHDOG		7	/* from FB.7 */
-#define IRQ_ETHER10		8	/* from FB.8 */
-#define IRQ_ETHER100		9	/* from FB.9 */
-#define IRQ_VIDCOMP		10	/* from FB.10 */
-#define IRQ_EXTERN_IRQ		11	/* from FB.11: chain to IDE irq's */
-#define IRQ_DMA1		12	/* from future */
-#define IRQ_PCI_ERR		15	/* from FB.[28:31] */
-
-#define IRQ_TIMER4		16	/* from 553.0 */
-#define IRQ_KEYBOARD		17	/* from 553.1 */
-#define IRQ_PIC_HI		18	/* from 533.2: chained to 553.[8:15] */
-#define IRQ_UART2		19	/* from 553.3 */
-#define IRQ_UART		20	/* from 553.4 */
-#define IRQ_MOUSE		21	/* from 553.5 */
-#define IRQ_UART_IR		22	/* from 553.6 */
-#define IRQ_PRINTER		23	/* from 553.7 */
-#define IRQ_RTC_ALARM		24	/* from 553.8 */
-#define IRQ_POWERLOW		26	/* from 553.10 */
-#define IRQ_VGA			27	/* from 553.11 */
-#define IRQ_SOUND		28	/* from 553.12 */
-#define IRQ_HARDDISK		30	/* from 553.14 */
-
-/* These defines handle the translation from the above FB #defines
- * into physical bits for the FootBridge IRQ registers
- */
-#define IRQ_MASK_SOFTIRQ	0x00000002
-#define IRQ_MASK_UART_DEBUG	0x0000000C
-#define IRQ_MASK_TIMER0		0x00000010
-#define IRQ_MASK_TIMER1		0x00000020
-#define IRQ_MASK_TIMER2		0x00000040
-#define IRQ_MASK_WATCHDOG	0x00000080
-#define IRQ_MASK_ETHER10	0x00000100
-#define IRQ_MASK_ETHER100	0x00000200
-#define IRQ_MASK_VIDCOMP	0x00000400
-#define IRQ_MASK_EXTERN_IRQ	0x00000800
-#define IRQ_MASK_DMA1		0x00030000
-#define IRQ_MASK_PCI_ERR	0xf8800000
-
-/*
- * Now map them to the Linux interrupts
- */
-#undef IRQ_TIMER
-#define IRQ_TIMER		IRQ_TIMER0
-#undef RTC_IRQ
-#define RTC_IRQ			IRQ_RTC_ALARM
-#undef AUX_IRQ
-#define AUX_IRQ			IRQ_MOUSE
-
-#define irq_cannonicalize(i)	(i)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/keyboard.h linux/include/asm-arm/arch-vnc/keyboard.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/keyboard.h	Wed Apr 28 11:37:31 1999
+++ linux/include/asm-arm/arch-vnc/keyboard.h	Wed Dec 31 16:00:00 1969
@@ -1,36 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/keyboard.h
- *
- * Keyboard driver definitions for VNC architecture
- *
- * (C) 1998 Russell King
- */
-
-#include <asm/irq.h>
-
-#define NR_SCANCODES 128
-
-#define KEYBOARD_IRQ			IRQ_KEYBOARD
-
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-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
-#define kbd_translate(sc, kcp, ufp, rm) ({ *ufp = sc & 0200; \
-		pckbd_translate(sc & 0x7f, kcp, rm);})
-
-#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
-#define kbd_disable_irq()
-#define kbd_enable_irq()
-
-#define SYSRQ_KEY 0x54
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/mm-init.h linux/include/asm-arm/arch-vnc/mm-init.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/mm-init.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-vnc/mm-init.h	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/mmap.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/mmu.h linux/include/asm-arm/arch-vnc/mmu.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/mmu.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/arch-vnc/mmu.h	Wed Dec 31 16:00:00 1969
@@ -1,26 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/mmu.h
- *
- * Copyright (c) 1996,1997,1998 Russell King.
- *
- * Changelog:
- *  20-10-1996	RMK	Created
- *  31-12-1997	RMK	Fixed definitions to reduce warnings
- */
-#ifndef __ASM_ARCH_MMU_H
-#define __ASM_ARCH_MMU_H
-
-/*
- * On ebsa, the dram is contiguous
- */
-#define __virt_to_phys__is_a_macro
-#define __virt_to_phys(vpage) ((vpage) - PAGE_OFFSET)
-#define __phys_to_virt__is_a_macro
-#define __phys_to_virt(ppage) ((ppage) + PAGE_OFFSET)
-
-#define __virt_to_bus__is_a_macro
-#define __virt_to_bus(x)	(x - 0xe0000000)
-#define __bus_to_virt__is_a_macro
-#define __bus_to_virt(x)	(x + 0xe0000000)
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/oldlatches.h linux/include/asm-arm/arch-vnc/oldlatches.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/oldlatches.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-vnc/oldlatches.h	Wed Dec 31 16:00:00 1969
@@ -1,9 +0,0 @@
-/*
- * Dummy oldlatches.h
- *
- * Copyright (C) 1996 Russell King
- */
-
-#ifdef __need_oldlatches
-#error "Old latches not present in this (rpc) machine"
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/param.h linux/include/asm-arm/arch-vnc/param.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/param.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/arch-vnc/param.h	Wed Dec 31 16:00:00 1969
@@ -1,8 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/param.h
- *
- * Copyright (C) 1996 Russell King
- * Copyright (C) 1998 Philip Blundell
- */
-
-#define HZ 100
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/processor.h linux/include/asm-arm/arch-vnc/processor.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/processor.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-vnc/processor.h	Wed Dec 31 16:00:00 1969
@@ -1,31 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/processor.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
-
-#ifndef __ASM_ARCH_PROCESSOR_H
-#define __ASM_ARCH_PROCESSOR_H
-
-/*
- * Bus types
- */
-#define EISA_bus 0
-#define EISA_bus__is_a_macro /* for versions in ksyms.c */
-#define MCA_bus 0
-#define MCA_bus__is_a_macro /* for versions in ksyms.c */
-
-/*
- * User space: 3GB
- */
-#define TASK_SIZE	(0xc0000000UL)
-
-/* This decides where the kernel will search for a free chunk of vm
- * space during mmap's.
- */
-#define TASK_UNMAPPED_BASE	(TASK_SIZE / 3)
-
-#define INIT_MMAP \
-{ &init_mm, 0, 0, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, NULL, &init_mm.mmap }
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/serial.h linux/include/asm-arm/arch-vnc/serial.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/serial.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-vnc/serial.h	Wed Dec 31 16:00:00 1969
@@ -1,43 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/serial.h
- *
- * Copyright (c) 1996 Russell King.
- *
- * Changelog:
- *  15-10-1996	RMK	Created
- *  03-05-1998	RMK	Modified for Corel Video NC
- */
-#ifndef __ASM_ARCH_SERIAL_H
-#define __ASM_ARCH_SERIAL_H
-
-#include <asm/irq.h>
-
-/*
- * This assumes you have a 1.8432 MHz clock for your UART.
- *
- * It'd be nice if someone built a serial card with a 24.576 MHz
- * clock, since the 16550A is capable of handling a top speed of 1.5
- * megabits/second; but this requires the faster clock.
- */
-#define BASE_BAUD (1843200 / 16)
-
-#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-
-     /* UART CLK        PORT  IRQ     FLAGS        */
-#define SERIAL_PORT_DFNS \
-	{ 0, BASE_BAUD, 0x3F8, IRQ_UART	, STD_COM_FLAGS },	/* ttyS0 */	\
-	{ 0, BASE_BAUD, 0x2F8, IRQ_UART2, STD_COM_FLAGS },	/* ttyS1 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS2 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS3 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS }, 	/* ttyS4 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS5 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS6 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS7 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS8 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS9 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS10 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS11 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS12 */	\
-	{ 0, BASE_BAUD, 0    , 0	, STD_COM_FLAGS },	/* ttyS13 */
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/shmparam.h linux/include/asm-arm/arch-vnc/shmparam.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/shmparam.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-vnc/shmparam.h	Wed Dec 31 16:00:00 1969
@@ -1,5 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/shmparam.h
- *
- * Copyright (c) 1996 Russell King.
- */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/system.h linux/include/asm-arm/arch-vnc/system.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/system.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-vnc/system.h	Wed Dec 31 16:00:00 1969
@@ -1,37 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/system.h
- *
- * Copyright (c) 1996,1997,1998 Russell King.
- * Copyright (c) 1998 Corel Computer Corp.
- */
-#include <asm/hardware.h>
-#include <asm/dec21285.h>
-#include <asm/leds.h>
-#include <asm/io.h>
-
-extern __inline__ void arch_reset(char mode)
-{
-	cli();
-
-	/* open up the SuperIO chip
-	 */
-	outb(0x87, 0x370);
-	outb(0x87, 0x370);
-
-	/* aux function group 1 (Logical Device 7)
-	 */
-	outb(0x07, 0x370);
-	outb(0x07, 0x371);
-
-	/* set GP16 for WD-TIMER output
-	 */
-	outb(0xE6, 0x370);
-	outb(0x00, 0x371);
-
-	/* set a RED LED and toggle WD_TIMER for rebooting...
-	 */
-	outb(0xC4, 0x338);
-}
-
-#define arch_start_idle()	leds_event(led_idle_start)
-#define arch_end_idle()		leds_event(led_idle_end)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/time.h linux/include/asm-arm/arch-vnc/time.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/time.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/arch-vnc/time.h	Wed Dec 31 16:00:00 1969
@@ -1,232 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/time.h
- *
- * Copyright (c) 1997 Corel Computer Corp.
- * Slight modifications to bring in line with ebsa285 port.
- *  -- Russell King.
- *  Added LED driver (based on the ebsa285 code) - Alex Holden 28/12/98.
- */
-
-#include <linux/config.h>
-#include <linux/mc146818rtc.h>
-
-#include <asm/leds.h>
-#include <asm/system.h>
-
-#undef IRQ_TIMER
-#define IRQ_TIMER		IRQ_TIMER4
-
-#define mSEC_10_from_14 ((14318180 + 100) / 200)
-
-extern __inline__ unsigned long gettimeoffset (void)
-{
-	int count;
-
-	static int count_p = (mSEC_10_from_14/6);    /* for the first call after boot */
-	static unsigned long jiffies_p = 0;
-
-	/*
-	 * cache volatile jiffies temporarily; we have IRQs turned off. 
-	 */
-	unsigned long jiffies_t;
-
-	/* timer count may underflow right here */
-	outb_p(0x00, 0x43);	/* latch the count ASAP */
-
-	count = inb_p(0x40);	/* read the latched count */
-
-	/*
-	 * We do this guaranteed double memory access instead of a _p 
-	 * postfix in the previous port access. Wheee, hackady hack
-	 */
- 	jiffies_t = jiffies;
-
-	count |= inb_p(0x40) << 8;
-
-	/* Detect timer underflows.  If we haven't had a timer tick since 
-	   the last time we were called, and time is apparently going
-	   backwards, the counter must have wrapped during this routine. */
-	if ((jiffies_t == jiffies_p) && (count > count_p))
-		count -= (mSEC_10_from_14/6);
-	else
-		jiffies_p = jiffies_t;
-
-	count_p = count;
-
-	count = (((mSEC_10_from_14/6)-1) - count) * tick;
-	count = (count + (mSEC_10_from_14/6)/2) / (mSEC_10_from_14/6);
-
-	return count;
-}
-
-extern __inline__ int reset_timer (void)
-{
-#ifdef CONFIG_LEDS
-	static unsigned int count = 50;
-	static int last_pid;
-
-	if (current->pid != last_pid) {
-		last_pid = current->pid;
-		if (last_pid)
-			leds_event(led_idle_end);
-		else
-			leds_event(led_idle_start);
-	}
-
-	if (--count == 0) {
-		count = 50;
-		leds_event(led_timer);
-	}
-#endif
-	return 1;
-}
-
-unsigned long set_rtc_mmss(unsigned long nowtime)
-{
-	int retval = 0;
-	int real_seconds, real_minutes, cmos_minutes;
-	unsigned char save_control, save_freq_select;
-
-	save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
-	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
-
-	save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
-	CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
-	cmos_minutes = CMOS_READ(RTC_MINUTES);
-	if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-		BCD_TO_BIN(cmos_minutes);
-
-	/*
-	 * since we're only adjusting minutes and seconds,
-	 * don't interfere with hour overflow. This avoids
-	 * messing with unknown time zones but requires your
-	 * RTC not to be off by more than 15 minutes
-	 */
-	real_seconds = nowtime % 60;
-	real_minutes = nowtime / 60;
-	if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
-		real_minutes += 30;		/* correct for half hour time zone */
-	real_minutes %= 60;
-
-	if (abs(real_minutes - cmos_minutes) < 30) {
-		if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-			BIN_TO_BCD(real_seconds);
-			BIN_TO_BCD(real_minutes);
-		}
-		CMOS_WRITE(real_seconds,RTC_SECONDS);
-		CMOS_WRITE(real_minutes,RTC_MINUTES);
-	} else
-		retval = -1;
-
-	/* The following flags have to be released exactly in this order,
-	 * otherwise the DS12887 (popular MC146818A clone with integrated
-	 * battery and quartz) will not reset the oscillator and will not
-	 * update precisely 500 ms later. You won't find this mentioned in
-	 * the Dallas Semiconductor data sheets, but who believes data
-	 * sheets anyway ...                           -- Markus Kuhn
-	 */
-	CMOS_WRITE(save_control, RTC_CONTROL);
-	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
-
-	return retval;
-}
-
-/*
- * We don't have a RTC to update!
- */
-extern __inline__ void update_rtc(void)
-{
-	static long last_rtc_update = 0;	/* last time the cmos clock got updated */
-
-	/* If we have an externally synchronized linux clock, then update
-	 * CMOS clock accordingly every ~11 minutes.  Set_rtc_mmss() has to be
-	 * called as close as possible to 500 ms before the new second starts.
-	 */
-	if (time_state != TIME_BAD && xtime.tv_sec > last_rtc_update + 660 &&
-	    xtime.tv_usec > 50000 - (tick >> 1) &&
-	    xtime.tv_usec < 50000 + (tick >> 1)) {
-		if (set_rtc_mmss(xtime.tv_sec) == 0)
-			last_rtc_update = xtime.tv_sec;
-		else
-			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
-	}
-}
-
-extern __inline__ unsigned long get_cmos_time(void)
-{
-	unsigned int year, mon, day, hour, min, sec;
-	int i;
-
-	// check to see if the RTC makes sense.....
-	if ((CMOS_READ(RTC_VALID) & RTC_VRT) == 0)
-		return mktime(1970, 1, 1, 0, 0, 0);
-
-	/* The Linux interpretation of the CMOS clock register contents:
-	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-	 * RTC registers show the second which has precisely just started.
-	 * Let's hope other operating systems interpret the RTC the same way.
-	 */
-	/* read RTC exactly on falling edge of update flag */
-	for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
-		if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
-			break;
-
-	for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */
-		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
-			break;
-
-	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) {
-		BCD_TO_BIN(sec);
-		BCD_TO_BIN(min);
-		BCD_TO_BIN(hour);
-		BCD_TO_BIN(day);
-		BCD_TO_BIN(mon);
-		BCD_TO_BIN(year);
-	}
-	if ((year += 1900) < 1970)
-		year += 100;
-	return mktime(year, mon, day, hour, min, sec);
-}
-
-/*
- * Set up timer interrupt, and return the current time in seconds.
- */
-extern __inline__ unsigned long setup_timer (void)
-{
-	unsigned int c;
-
-	/* Turn on the RTC */
-	outb(13, 0x70);
-	if ((inb(0x71) & 0x80) == 0)
-		printk("RTC: *** warning: CMOS battery bad\n");
-
-	outb(10, 0x70);		/* select control reg */
-	outb(32, 0x71);		/* make sure the divider is set */
-	outb(11, 0x70);		/* select other control reg */
-	c = inb(0x71) & 0xfb;	/* read it */
-	outb(11, 0x70);
-	outb(c | 2, 0x71);	/* turn on BCD counting and 24 hour clock mode */
-	
-	/* enable PIT timer */
-	/* set for periodic (4) and LSB/MSB write (0x30) */
-	outb(0x34, 0x43);
-	outb((mSEC_10_from_14/6) & 0xFF, 0x40);
-	outb((mSEC_10_from_14/6) >> 8, 0x40);
-
-	/*
-	 * Default the date to 1 Jan 1970 00:00:00
-	 * You will have to run a time daemon to set the
-	 * clock correctly at bootup
-	 */
-	return get_cmos_time();
-}
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/timex.h linux/include/asm-arm/arch-vnc/timex.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/timex.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-arm/arch-vnc/timex.h	Wed Dec 31 16:00:00 1969
@@ -1,13 +0,0 @@
-/*
- * linux/include/asm-arm/arch-vnc/timex.h
- *
- * Corel Video NC architecture timex specifications
- *
- * Copyright (C) 1998 Corel Computer/Russell King
- */
-
-/*
- * On the VNC, the clock runs at 66MHz and is divided
- * by a 4-bit prescaler.
- */
-#define CLOCK_TICK_RATE		(66000000 / 16)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-vnc/uncompress.h linux/include/asm-arm/arch-vnc/uncompress.h
--- v2.2.7/linux/include/asm-arm/arch-vnc/uncompress.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/arch-vnc/uncompress.h	Wed Dec 31 16:00:00 1969
@@ -1,34 +0,0 @@
-/*
- * linux/include/asm-arm/arch-ebsa110/uncompress.h
- *
- * Copyright (C) 1996,1997,1998 Russell King
- */
-
-/*
- * This does not append a newline
- */
-static void puts(const char *s)
-{
-	__asm__ __volatile__("
-	ldrb	%0, [%2], #1
-	teq	%0, #0
-	beq	3f
-1:	strb	%0, [%3]
-2:	ldrb	%1, [%3, #0x14]
-	and	%1, %1, #0x60
-	teq	%1, #0x60
-	bne	2b
-	teq	%0, #'\n'
-	moveq	%0, #'\r'
-	beq	1b
-	ldrb	%0, [%2], #1
-	teq	%0, #0
-	bne	1b
-3:	" : : "r" (0), "r" (0), "r" (s), "r" (0xf0000be0) : "cc");
-}
-
-/*
- * nothing to do
- */
-#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/dec21285.h linux/include/asm-arm/dec21285.h
--- v2.2.7/linux/include/asm-arm/dec21285.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/dec21285.h	Sat May  8 11:06:57 1999
@@ -15,17 +15,20 @@
 #define DC21285_PCI_MEM			0x80000000
 
 #ifndef __ASSEMBLY__
-#define DC21285_IO(x)		((volatile unsigned long *)(0xfe000000+(x)))
+#include <asm/arch/hardware.h>
+#define DC21285_IO(x)		((volatile unsigned long *)(ARMCSR_BASE+(x)))
 #else
 #define DC21285_IO(x)		(x)
 #endif
 
 #define CSR_PCICMD		DC21285_IO(0x0004)
+#define CSR_CLASSREV		DC21285_IO(0x0008)
 #define CSR_PCICACHELINESIZE	DC21285_IO(0x000c)
 #define CSR_PCICSRBASE		DC21285_IO(0x0010)
 #define CSR_PCICSRIOBASE	DC21285_IO(0x0014)
 #define CSR_PCISDRAMBASE	DC21285_IO(0x0018)
 #define CSR_PCIROMBASE		DC21285_IO(0x0030)
+#define CSR_ROMWRITEREG		DC21285_IO(0x0068)
 #define CSR_CSRBASEMASK		DC21285_IO(0x00f8)
 #define CSR_CSRBASEOFFSET	DC21285_IO(0x00fc)
 #define CSR_SDRAMBASEMASK	DC21285_IO(0x0100)
@@ -44,6 +47,33 @@
 #define CSR_I2O_OUTPOSTCOUNT	DC21285_IO(0x0134)
 #define CSR_I2O_INPOSTCOUNT	DC21285_IO(0x0138)
 #define CSR_SA110_CNTL		DC21285_IO(0x013c)
+#define SA110_CNTL_INITCMPLETE		(1 << 0)
+#define SA110_CNTL_ASSERTSERR		(1 << 1)
+#define SA110_CNTL_RXSERR		(1 << 3)
+#define SA110_CNTL_SA110DRAMPARITY	(1 << 4)
+#define SA110_CNTL_PCISDRAMPARITY	(1 << 5)
+#define SA110_CNTL_DMASDRAMPARITY	(1 << 6)
+#define SA110_CNTL_DISCARDTIMER		(1 << 8)
+#define SA110_CNTL_PCINRESET		(1 << 9)
+#define SA110_CNTL_I2O_256		(0 << 10)
+#define SA110_CNTL_I20_512		(1 << 10)
+#define SA110_CNTL_I2O_1024		(2 << 10)
+#define SA110_CNTL_I2O_2048		(3 << 10)
+#define SA110_CNTL_I2O_4096		(4 << 10)
+#define SA110_CNTL_I2O_8192		(5 << 10)
+#define SA110_CNTL_I2O_16384		(6 << 10)
+#define SA110_CNTL_I2O_32768		(7 << 10)
+#define SA110_CNTL_WATCHDOG		(1 << 13)
+#define SA110_CNTL_ROMWIDTH_UNDEF	(0 << 14)
+#define SA110_CNTL_ROMWIDTH_16		(1 << 14)
+#define SA110_CNTL_ROMWIDTH_32		(2 << 14)
+#define SA110_CNTL_ROMWIDTH_8		(3 << 14)
+#define SA110_CNTL_ROMACCESSTIME(x)	((x)<<16)
+#define SA110_CNTL_ROMBURSTTIME(x)	((x)<<20)
+#define SA110_CNTL_ROMTRISTATETIME(x)	((x)<<24)
+#define SA110_CNTL_XCSDIR(x)		((x)<<28)
+#define SA110_CNTL_PCICFN		(1 << 31)
+
 #define CSR_PCIADDR_EXTN	DC21285_IO(0x0140)
 #define CSR_PREFETCHMEMRANGE	DC21285_IO(0x0144)
 #define CSR_XBUS_CYCLE		DC21285_IO(0x0148)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/dma.h linux/include/asm-arm/dma.h
--- v2.2.7/linux/include/asm-arm/dma.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/dma.h	Sat May  8 11:07:16 1999
@@ -6,20 +6,20 @@
 #include <linux/config.h>
 #include <linux/kernel.h>
 #include <asm/irq.h>
-#include <asm/system.h>
 #include <asm/spinlock.h>
 #include <asm/arch/dma.h>
 
 /*
- * DMA modes - we have two, IN and OUT
+ * DMA modes
  */
 typedef unsigned int dmamode_t;
 
-#define DMA_MODE_MASK	1
+#define DMA_MODE_MASK	3
 
-#define DMA_MODE_READ	0
-#define DMA_MODE_WRITE	1
-#define DMA_AUTOINIT	2
+#define DMA_MODE_READ	 0
+#define DMA_MODE_WRITE	 1
+#define DMA_MODE_CASCADE 2
+#define DMA_AUTOINIT	 4
 
 typedef struct {
 	unsigned long address;
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/ecard.h linux/include/asm-arm/ecard.h
--- v2.2.7/linux/include/asm-arm/ecard.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/ecard.h	Sat May  8 11:06:57 1999
@@ -47,6 +47,9 @@
 #define MANU_ICS		0x003c
 #define PROD_ICS_IDE			0x00ae
 
+#define MANU_ICS2		0x003d
+#define PROD_ICS2_IDE			0x00ae
+
 #define MANU_SERPORT		0x003f
 #define PROD_SERPORT_DSPORT		0x00b9
 
@@ -76,7 +79,7 @@
 #define CONST const
 #endif
 
-#define MAX_ECARDS	8
+#define MAX_ECARDS	9
 
 typedef enum {				/* Cards address space		*/
 	ECARD_IOC,
@@ -116,14 +119,18 @@
 typedef struct {			/* Card handler routines	*/
 	void (*irqenable)(ecard_t *ec, int irqnr);
 	void (*irqdisable)(ecard_t *ec, int irqnr);
+	int  (*irqpending)(ecard_t *ec);
 	void (*fiqenable)(ecard_t *ec, int fiqnr);
 	void (*fiqdisable)(ecard_t *ec, int fiqnr);
+	int  (*fiqpending)(ecard_t *ec);
 } expansioncard_ops_t;
 
 /*
  * This contains all the info needed on an expansion card
  */
 struct expansion_card {
+	struct expansion_card  *next;
+
 	/* Public data */
 	volatile unsigned char *irqaddr;	/* address of IRQ register	*/
 	volatile unsigned char *fiqaddr;	/* address of FIQ register	*/
@@ -135,10 +142,10 @@
 	void			*fiq_data;	/* Data for use for FIQ by card	*/
 	expansioncard_ops_t	*ops;		/* Enable/Disable Ops for card	*/
 
-	CONST unsigned char	slot_no;	/* Slot number			*/
-	CONST unsigned char	dma;		/* DMA number (for request_dma)	*/
-	CONST unsigned char	irq;		/* IRQ number (for request_irq)	*/
-	CONST unsigned char	fiq;		/* FIQ number (for request_irq)	*/
+	CONST unsigned int	slot_no;	/* Slot number			*/
+	CONST unsigned int	dma;		/* DMA number (for request_dma)	*/
+	CONST unsigned int	irq;		/* IRQ number (for request_irq)	*/
+	CONST unsigned int	fiq;		/* FIQ number (for request_irq)	*/
 	CONST card_type_t	type;		/* Type of card			*/
 	CONST struct in_ecid	cid;		/* Card Identification		*/
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/fiq.h linux/include/asm-arm/fiq.h
--- v2.2.7/linux/include/asm-arm/fiq.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/fiq.h	Sat May  8 11:06:57 1999
@@ -30,5 +30,6 @@
 extern void release_fiq(struct fiq_handler *f);
 extern void set_fiq_handler(void *start, unsigned int length);
 extern void set_fiq_regs(struct pt_regs *regs);
+extern void get_fiq_regs(struct pt_regs *regs);
 
 #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/floppy.h linux/include/asm-arm/floppy.h
--- v2.2.7/linux/include/asm-arm/floppy.h	Tue Jun 23 10:01:26 1998
+++ linux/include/asm-arm/floppy.h	Sat May  8 11:06:57 1999
@@ -120,5 +120,20 @@
 #define FLOPPY_MOTOR_MASK 0xf0
 
 #define CROSS_64KB(a,s) (0)
+
+/*
+ * This allows people to reverse the order of
+ * fd0 and fd1, in case their hardware is
+ * strangely connected (as some RiscPCs
+ * and A5000s seem to be).
+ */
+static void driveswap(int *ints, int dummy, int dummy2)
+{
+	floppy_selects[0][0] ^= floppy_selects[0][1];
+	floppy_selects[0][1] ^= floppy_selects[0][0];
+	floppy_selects[0][0] ^= floppy_selects[0][1];
+}
+
+#define EXTRA_FLOPPY_PARAMS ,{ "driveswap", &driveswap, NULL, 0, 0 }
 	
 #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/hardware.h linux/include/asm-arm/hardware.h
--- v2.2.7/linux/include/asm-arm/hardware.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/hardware.h	Sat May  8 11:06:57 1999
@@ -11,10 +11,6 @@
 
 #include <asm/arch/hardware.h>
 
-#ifndef FLUSH_BASE
-#define FLUSH_BASE	0xdf000000
-#endif
-
 #ifdef HAS_EXPMASK
 #ifndef __ASSEMBLER__
 #define __EXPMASK(offset)	(((volatile unsigned char *)EXPMASK_BASE)[offset])
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/init.h linux/include/asm-arm/init.h
--- v2.2.7/linux/include/asm-arm/init.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/init.h	Sat May  8 11:06:57 1999
@@ -5,7 +5,7 @@
 
 /* C routines */
 
-#ifdef CONFIG_TEXT_INIT_SECTION
+#ifdef CONFIG_TEXT_SECTIONS
 
 #define __init __attribute__ ((__section__ (".text.init")))
 #define __initfunc(__arginit) \
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/io.h linux/include/asm-arm/io.h
--- v2.2.7/linux/include/asm-arm/io.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/io.h	Sat May  8 11:06:57 1999
@@ -8,12 +8,35 @@
  *			constant addresses and variable addresses.
  *  04-Dec-1997	RMK	Moved a lot of this stuff to the new architecture
  *			specific IO header files.
+ *  27-Mar-1999	PJB	Second parameter of memcpy_toio is const..
+ *  04-Apr-1999	PJB	Added check_signature.
  */
 #ifndef __ASM_ARM_IO_H
 #define __ASM_ARM_IO_H
 
+#ifdef __KERNEL__
+
+#ifndef NULL
+#define NULL	((void *) 0)
+#endif
+
+extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+
+/*
+ * String version of IO memory access ops:
+ */
+extern void _memcpy_fromio(void *, unsigned long, unsigned long);
+extern void _memcpy_toio(unsigned long, const void *, unsigned long);
+extern void _memset_io(unsigned long, int, unsigned long);
+
+#define memcpy_fromio(to,from,len)	_memcpy_fromio((to),(unsigned long)(from),(len))
+#define memcpy_toio(to,from,len)	_memcpy_toio((unsigned long)(to),(from),(len))
+#define memset_io(addr,c,len)		_memset_io((unsigned long)(addr),(c),(len))
+
+#endif
+
 #include <asm/hardware.h>
-#include <asm/arch/mmu.h>
+#include <asm/arch/memory.h>
 #include <asm/arch/io.h>
 #include <asm/proc/io.h>
 
@@ -168,25 +191,43 @@
 
 #endif
 
-#undef ARCH_IO_DELAY
-#undef ARCH_IO_CONSTANT
+#ifndef ARCH_READWRITE
 
-#ifdef __KERNEL__
+/* for panic */
+#include <linux/kernel.h>
 
-extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+#define readb(p)	(panic("readb called, but not implemented"),0)
+#define readw(p)	(panic("readw called, but not implemented"),0)
+#define readl(p)	(panic("readl called, but not implemented"),0)
+#define writeb(v,p)	panic("writeb called, but not implemented")
+#define writew(v,p)	panic("writew called, but not implemented")
+#define writel(v,p)	panic("writel called, but not implemented")
 
-/*
- * String version of IO memory access ops:
- */
-extern void _memcpy_fromio(void *, unsigned long, unsigned long);
-extern void _memcpy_toio(unsigned long, void *, unsigned long);
-extern void _memset_io(unsigned long, int, unsigned long);
+#endif
 
-#define memcpy_fromio(to,from,len)	_memcpy_fromio((to),(unsigned long)(from),(len))
-#define memcpy_toio(to,from,len)	_memcpy_toio((unsigned long)(to),(from),(len))
-#define memset_io(addr,c,len)		_memset_io((unsigned long)(addr),(c),(len))
+/*
+ * This isn't especially architecture dependent so it seems like it
+ * might as well go here as anywhere.
+ */
+static inline int check_signature(unsigned long io_addr,
+                                  const unsigned char *signature, int length)
+{
+	int retval = 0;
+	do {
+		if (readb(io_addr) != *signature)
+			goto out;
+		io_addr++;
+		signature++;
+		length--;
+	} while (length);
+	retval = 1;
+out:
+	return retval;
+}
 
-#endif
+#undef ARCH_READWRITE
+#undef ARCH_IO_DELAY
+#undef ARCH_IO_CONSTANT
 
 #endif
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/ioc.h linux/include/asm-arm/ioc.h
--- v2.2.7/linux/include/asm-arm/ioc.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/ioc.h	Sat May  8 11:06:57 1999
@@ -3,6 +3,8 @@
  * read/write.
  */
 
+#ifndef IOC_CONTROL
+
 #ifndef __ASSEMBLER__
 #define __IOC(offset)	(IOC_BASE + (offset >> 2))
 #else
@@ -54,3 +56,4 @@
 #define IOC_T3GO	__IOC(0x78)
 #define IOC_T3LATCH	__IOC(0x7c)
 
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/iomd.h linux/include/asm-arm/iomd.h
--- v2.2.7/linux/include/asm-arm/iomd.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/iomd.h	Sat May  8 11:06:57 1999
@@ -125,6 +125,8 @@
 #define DMA_ST_OFL	4
 #define DMA_ST_INT	2
 #define DMA_ST_AB	1
+
+#ifndef IOC_CONTROL
 /*
  * IOC compatability
  */
@@ -155,6 +157,7 @@
 #define IOC_T1LTCHH	IOMD_T1LTCHH
 #define IOC_T1GO	IOMD_T1GO
 #define IOC_T1LATCH	IOMD_T1LATCH
+#endif
 
 /*
  * DMA (MEMC) compatability
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/irq.h linux/include/asm-arm/irq.h
--- v2.2.7/linux/include/asm-arm/irq.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/irq.h	Sat May  8 11:07:16 1999
@@ -16,8 +16,10 @@
  * capability
  */
 #ifndef NO_IRQ
-#define NO_IRQ	255
+#define NO_IRQ	((unsigned int)(-1))
 #endif
+
+#define disable_irq_nosync(i) disable_irq(i)
 
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/leds.h linux/include/asm-arm/leds.h
--- v2.2.7/linux/include/asm-arm/leds.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/leds.h	Sat May  8 11:06:57 1999
@@ -10,15 +10,32 @@
 #ifndef ASM_ARM_LEDS_H
 #define ASM_ARM_LEDS_H
 
+#include <linux/config.h>
+
 typedef enum {
 	led_idle_start,
 	led_idle_end,
 	led_timer,
 	led_start,
-	led_stop
+	led_stop,
+	led_claim,		/* override idle & timer leds */
+	led_release,		/* restore idle & timer leds */
+	led_green_on,
+	led_green_off,
+	led_amber_on,
+	led_amber_off,
+	led_red_on,
+	led_red_off
 } led_event_t;
 
 /* Use this routine to handle LEDs */
-extern void leds_event(led_event_t);
+
+#ifdef CONFIG_LEDS
+extern void (*leds_event)(led_event_t);
+#define set_leds_event(r)	leds_event = r
+#else
+#define leds_event(e)
+#define set_leds_event(r)
+#endif
 
 #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/memc.h linux/include/asm-arm/memc.h
--- v2.2.7/linux/include/asm-arm/memc.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/memc.h	Sat May  8 11:06:57 1999
@@ -4,6 +4,9 @@
 #define VDMA_START	1
 #define VDMA_END	2
 
+#ifndef __ASSEMBLER__
+extern void memc_write(unsigned int reg, unsigned long val);
+
 #define video_set_dma(start,end,offset)				\
 do {								\
 	memc_write (VDMA_START, (start >> 2));			\
@@ -11,3 +14,4 @@
 	memc_write (VDMA_INIT, (offset >> 2));			\
 } while (0)
 
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/mm-init.h linux/include/asm-arm/mm-init.h
--- v2.2.7/linux/include/asm-arm/mm-init.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/mm-init.h	Wed Dec 31 16:00:00 1969
@@ -1,46 +0,0 @@
-/*
- * linux/include/asm-arm/mm-init.h
- *
- * Copyright (C) 1997,1998 Russell King
- *
- * Contained within are structures to describe how to set up the
- * initial memory map.  It includes both a processor-specific header
- * for parsing these structures, and an architecture-specific header
- * to fill out the structures.
- */
-#ifndef __ASM_MM_INIT_H
-#define __ASM_MM_INIT_H
-
-typedef enum {
-	// physical address is absolute
-	init_mem_map_absolute,
-	/* physical address is relative to start_mem
-	 *  as passed in paging_init
-	 */
-	init_mem_map_relative_start_mem
-} init_memmap_type_t;
-
-typedef struct {
-	init_memmap_type_t type;
-	unsigned long physical_address;
-	unsigned long virtual_address;
-	unsigned long size;
-} init_memmap_t;
-
-#define INIT_MEM_MAP_SENTINEL { init_mem_map_absolute, 0, 0, 0 }
-#define INIT_MEM_MAP_ABSOLUTE(p,l,s) { init_mem_map_absolute,p,l,s }
-#define INIT_MEM_MAP_RELATIVE(o,l,s) { init_mem_map_relative_start_mem,o,l,s }
-
-/*
- * Within this file, initialise an array of init_mem_map_t's
- * to describe your initial memory mapping structure.
- */
-#include <asm/arch/mm-init.h>
-
-/*
- * Contained within this file is code to read the array
- * of init_mem_map_t's created above.
- */
-#include <asm/proc/mm-init.h>
-
-#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/page.h linux/include/asm-arm/page.h
--- v2.2.7/linux/include/asm-arm/page.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/page.h	Sat May  8 11:06:57 1999
@@ -1,15 +1,15 @@
 #ifndef _ASMARM_PAGE_H
 #define _ASMARM_PAGE_H
 
-#include <asm/arch/mmu.h>
+#include <asm/arch/memory.h>
 #include <asm/proc/page.h>
 
 #ifdef __KERNEL__
 
 #define get_user_page(vaddr)		__get_free_page(GFP_KERNEL)
 #define free_user_page(page, addr)	free_page(addr)
-#define clear_page(page)	memzero((void *)(page), PAGE_SIZE)
-#define copy_page(to,from)	memcpy((void *)(to), (void *)(from), PAGE_SIZE)
+#define clear_page(page)		memzero((void *)(page), PAGE_SIZE)
+#define copy_page(to,from)		memcpy((void *)(to), (void *)(from), PAGE_SIZE)
 
 #endif
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/posix_types.h linux/include/asm-arm/posix_types.h
--- v2.2.7/linux/include/asm-arm/posix_types.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/posix_types.h	Sat May  8 11:06:57 1999
@@ -45,6 +45,8 @@
 #endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
 } __kernel_fsid_t;
 
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
 #undef	__FD_SET
 #define __FD_SET(fd, fdsetp) \
 		(((fd_set *)fdsetp)->fds_bits[fd >> 5] |= (1<<(fd & 31)))
@@ -60,5 +62,7 @@
 #undef	__FD_ZERO
 #define __FD_ZERO(fdsetp) \
 		(memset (fdsetp, 0, sizeof (*(fd_set *)fdsetp)))
+
+#endif
 
 #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armo/mm-init-flat.h linux/include/asm-arm/proc-armo/mm-init-flat.h
--- v2.2.7/linux/include/asm-arm/proc-armo/mm-init-flat.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/proc-armo/mm-init-flat.h	Wed Dec 31 16:00:00 1969
@@ -1,82 +0,0 @@
-/*
- * linux/include/asm-arm/proc-armo/mmap.h
- *
- * Copyright (C) 1996 Russell King
- *
- * This contains the code to setup the memory map on an ARM2/ARM250/ARM3
- * machine. This is both processor & architecture specific, and requires
- * some more work to get it to fit into our separate processor and
- * architecture structure.
- */
-
-static unsigned long phys_screen_end;
-int page_nr;
-
-#define setup_processor_functions()
-
-/*
- * This routine needs more work to make it dynamically release/allocate mem!
- */
-unsigned long map_screen_mem(unsigned long log_start, unsigned long kmem, int update)
-{
-	static int updated = 0;
-	unsigned long address = SCREEN_START, i;
-	pgd_t *pg_dir;
-	pmd_t *pm_dir;
-	pte_t *pt_entry;
-
-	if (updated)
-		return 0;
-	updated = update;
-
-	pg_dir = swapper_pg_dir + (SCREEN1_BASE >> PGDIR_SHIFT);
-	pm_dir = pmd_offset(pg_dir, SCREEN1_BASE);
-	pt_entry = pte_offset(pm_dir, SCREEN1_BASE);
-
-	for (i = SCREEN1_BASE; i < SCREEN1_END; i += PAGE_SIZE) {
-		if (i >= log_start) {
-			*pt_entry = mk_pte(address, __pgprot(_PAGE_PRESENT));
-			address += PAGE_SIZE;
-		} else
-			*pt_entry = mk_pte(0, __pgprot(0));
-		pt_entry++;
-	}
-	phys_screen_end = address;
-	if (update)
-		flush_tlb_all ();
-	return kmem;
-}
-
-static inline unsigned long setup_pagetables(unsigned long start_mem, unsigned long end_mem)
-{
-	unsigned long address;
-	unsigned int spi;
-
-	page_nr = MAP_NR(end_mem);
-
-	/* Allocate zero page */
-	address = PAGE_OFFSET + 480*1024;
-	for (spi = 0; spi < 32768 >> PAGE_SHIFT; spi++) {
-		pgd_val(swapper_pg_dir[spi]) = pte_val(mk_pte(address, PAGE_READONLY));
-		address += PAGE_SIZE;
-	}
-
-	while (spi < (PAGE_OFFSET >> PGDIR_SHIFT))
-		pgd_val(swapper_pg_dir[spi++]) = 0;
-
-	map_screen_mem (SCREEN1_END - 480*1024, 0, 0);
-	return start_mem;
-}
-
-static inline void mark_usable_memory_areas(unsigned long *start_mem, unsigned long end_mem)
-{
-	unsigned long smem = PAGE_ALIGN(*start_mem);
-
-	while (smem < end_mem) {
-		clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags);
-		smem += PAGE_SIZE;
-	}
-
-	for (smem = phys_screen_end; smem < SCREEN2_END; smem += PAGE_SIZE)
-		clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags);
-}
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armo/mm-init.h linux/include/asm-arm/proc-armo/mm-init.h
--- v2.2.7/linux/include/asm-arm/proc-armo/mm-init.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/proc-armo/mm-init.h	Sat May  8 11:06:57 1999
@@ -8,8 +8,8 @@
  * some more work to get it to fit into our separate processor and
  * architecture structure.
  */
-extern unsigned long phys_screen_end;
-extern unsigned long map_screen_mem(unsigned long log_start, unsigned long kmem, int update);
+#include <asm/arch/memory.h>
+
 int page_nr;
 
 #define setup_processor_functions()
@@ -20,10 +20,11 @@
 	set_pmd (pmd_offset (swapper_pg_dir + index, 0), mk_pmd (ptep));
 }
 
-static inline unsigned long setup_pagetables(unsigned long start_mem, unsigned long end_mem)
+static inline unsigned long
+setup_pagetables(unsigned long start_mem, unsigned long end_mem)
 {
 	unsigned int i;
-	union {unsigned long l; pte_t *pte; } u;
+	union { unsigned long l; pte_t *pte; } u;
 
 	page_nr = MAP_NR(end_mem);
 
@@ -37,14 +38,11 @@
 	for (i = 1; i < PTRS_PER_PGD; i++)
 		pgd_val(swapper_pg_dir[i]) = 0;
 
-	/* now map screen mem in */
-	phys_screen_end = SCREEN2_END;
-	map_screen_mem (SCREEN1_END - 480*1024, 0, 0);
-
 	return start_mem;
 }
 
-static inline void mark_usable_memory_areas(unsigned long *start_mem, unsigned long end_mem)
+static inline void
+mark_usable_memory_areas(unsigned long *start_mem, unsigned long end_mem)
 {
 	unsigned long smem;
 
@@ -54,7 +52,4 @@
 		clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags);
 		smem += PAGE_SIZE;
 	}
-
-	for (smem = phys_screen_end; smem < SCREEN2_END; smem += PAGE_SIZE)
-		clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags);
 }
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armo/page.h linux/include/asm-arm/proc-armo/page.h
--- v2.2.7/linux/include/asm-arm/proc-armo/page.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-arm/proc-armo/page.h	Sat May  8 11:06:57 1999
@@ -68,7 +68,6 @@
 #define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
 /* This handles the memory map.. */
-#define PAGE_OFFSET		0x02000000
 #define MAP_NR(addr)		(((unsigned long)(addr) - PAGE_OFFSET) >> PAGE_SHIFT)
 
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armo/pgtable-flat.h linux/include/asm-arm/proc-armo/pgtable-flat.h
--- v2.2.7/linux/include/asm-arm/proc-armo/pgtable-flat.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/proc-armo/pgtable-flat.h	Wed Dec 31 16:00:00 1969
@@ -1,307 +0,0 @@
-/*
- * linux/include/asm-arm/proc-armo/pgtable.h
- *
- * Copyright (C) 1995, 1996 Russell King
- */
-#ifndef __ASM_PROC_PGTABLE_H
-#define __ASM_PROC_PGTABLE_H
-
-#include <asm/arch/mmu.h>
-
-#define LIBRARY_TEXT_START 0x0c000000
-
-/*
- * Cache flushing...
- */
-#define flush_cache_all()			do { } while (0)
-#define flush_cache_mm(mm)			do { } while (0)
-#define flush_cache_range(mm,start,end)		do { } while (0)
-#define flush_cache_page(vma,vmaddr)		do { } while (0)
-#define flush_page_to_ram(page)			do { } while (0)
-
-/*
- * TLB flushing:
- *
- *  - flush_tlb() flushes the current mm struct TLBs
- *  - flush_tlb_all() flushes all processes TLBs
- *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
- *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
- */
-
-#define flush_tlb() flush_tlb_mm(current->mm)
-
-extern __inline__ void flush_tlb_all(void)
-{
-	struct task_struct *p;
-
-	p = &init_task;
-	do {
-		processor.u.armv2._update_map(p);
-		p = p->next_task;
-	} while (p != &init_task);
-
-	processor.u.armv2._remap_memc (current);
-}
-
-extern __inline__ void flush_tlb_mm(struct mm_struct *mm)
-{
-	struct task_struct *p;
-
-	p = &init_task;
-	do {
-		if (p->mm == mm)
-			processor.u.armv2._update_map(p);
-		p = p->next_task;
-	} while (p != &init_task);
-
-	if (current->mm == mm)
-		processor.u.armv2._remap_memc (current);
-}
-
-#define flush_tlb_range(mm, start, end) flush_tlb_mm(mm)
-#define flush_tlb_page(vma, vmaddr) flush_tlb_mm(vma->vm_mm)
-
-#define __flush_entry_to_ram(entry)
-
-/* Certain architectures need to do special things when pte's
- * within a page table are directly modified.  Thus, the following
- * hook is made available.
- */
-#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
-
-/* PMD_SHIFT determines the size of the area a second-level page table can map */
-#define PMD_SHIFT       PAGE_SHIFT
-#define PMD_SIZE        (1UL << PMD_SHIFT)
-#define PMD_MASK        (~(PMD_SIZE-1))
-
-/* PGDIR_SHIFT determines what a third-level page table entry can map */
-#define PGDIR_SHIFT     PAGE_SHIFT
-#define PGDIR_SIZE      (1UL << PGDIR_SHIFT)
-#define PGDIR_MASK      (~(PGDIR_SIZE-1))
-
-/*
- * entries per page directory level: the arm3 is one-level, so
- * we don't really have any PMD or PTE directory physically.
- */
-#define PTRS_PER_PTE    1
-#define PTRS_PER_PMD    1
-#define PTRS_PER_PGD    1024
-
-/* Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts.  That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-#define VMALLOC_START	0x01a00000
-#define VMALLOC_VMADDR(x) ((unsigned long)(x))
-
-#define _PAGE_PRESENT   0x001
-#define _PAGE_RW        0x002
-#define _PAGE_USER      0x004
-#define _PAGE_PCD       0x010
-#define _PAGE_ACCESSED  0x020
-#define _PAGE_DIRTY     0x040
-
-#define _PAGE_TABLE     (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
-#define _PAGE_CHG_MASK  (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
-
-#define PAGE_NONE       __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
-#define PAGE_SHARED     __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_COPY       __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_READONLY   __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED)
-#define PAGE_KERNEL     __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED)
-
-/*
- * The arm can't do page protection for execute, and considers that the same are read.
- * Also, write permissions imply read permissions. This is the closest we can get..
- */
-#define __P000  PAGE_NONE
-#define __P001  PAGE_READONLY
-#define __P010  PAGE_COPY
-#define __P011  PAGE_COPY
-#define __P100  PAGE_READONLY
-#define __P101  PAGE_READONLY
-#define __P110  PAGE_COPY
-#define __P111  PAGE_COPY
-
-#define __S000  PAGE_NONE
-#define __S001  PAGE_READONLY
-#define __S010  PAGE_SHARED
-#define __S011  PAGE_SHARED
-#define __S100  PAGE_READONLY
-#define __S101  PAGE_READONLY
-#define __S110  PAGE_SHARED
-#define __S111  PAGE_SHARED
-
-#undef TEST_VERIFY_AREA
-
-/*
- * BAD_PAGE is used for a bogus page.
- *
- * ZERO_PAGE is a global shared page that is always zero: used
- * for zero-mapped memory areas etc..
- */
-extern pte_t __bad_page(void);
-extern unsigned long *empty_zero_page;
-
-#define BAD_PAGE __bad_page()
-#define ZERO_PAGE ((unsigned long) empty_zero_page)
-
-/* number of bits that fit into a memory pointer */
-#define BYTES_PER_PTR			(sizeof(unsigned long))
-#define BITS_PER_PTR                    (8*BYTES_PER_PTR)
-
-/* to align the pointer to a pointer address */
-#define PTR_MASK                        (~(sizeof(void*)-1))
-
-/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
-#define SIZEOF_PTR_LOG2                 2
-
-/* to find an entry in a page-table */
-#define PAGE_PTR(address) \
-((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
-
-/* to set the page-dir */
-#define SET_PAGE_DIR(tsk,pgdir)						\
-do {									\
-	tsk->tss.memmap = (unsigned long)pgdir;				\
-	processor.u.armv2._update_map(tsk);				\
-	if ((tsk) == current)						\
-		processor.u.armv2._remap_memc (current);		\
-} while (0)
-
-extern unsigned long physical_start;
-extern unsigned long physical_end;
-
-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 *ptep)       { pte_val(*ptep) = 0; }
-
-extern inline int pmd_none(pmd_t pmd)           { return 0; }
-extern inline int pmd_bad(pmd_t pmd)            { return 0; }
-extern inline int pmd_present(pmd_t pmd)        { return 1; }
-extern inline void pmd_clear(pmd_t * pmdp)      { }
-
-/*
- * The "pgd_xxx()" functions here are trivial for a folded two-level
- * setup: the pgd is never bad, and a pmd always exists (as it's folded
- * into the pgd entry)
- */
-extern inline int pgd_none(pgd_t pgd)           { return 0; }
-extern inline int pgd_bad(pgd_t pgd)            { return 0; }
-extern inline int pgd_present(pgd_t pgd)        { return 1; }
-extern inline void pgd_clear(pgd_t * pgdp)      { }
-
-/*
- * The following only work if pte_present() is true.
- * Undefined behaviour if not..
- */
-extern inline int pte_read(pte_t pte)           { return pte_val(pte) & _PAGE_USER; }
-extern inline int pte_write(pte_t pte)          { return pte_val(pte) & _PAGE_RW; }
-extern inline int pte_exec(pte_t pte)           { return pte_val(pte) & _PAGE_USER; }
-extern inline int pte_dirty(pte_t pte)          { return pte_val(pte) & _PAGE_DIRTY; }
-extern inline int pte_young(pte_t pte)          { return pte_val(pte) & _PAGE_ACCESSED; }
-#define pte_cacheable(pte) 1
-
-extern inline pte_t pte_nocache(pte_t pte)	{ return pte; }
-extern inline pte_t pte_wrprotect(pte_t pte)    { pte_val(pte) &= ~_PAGE_RW; return pte; }
-extern inline pte_t pte_rdprotect(pte_t pte)    { pte_val(pte) &= ~_PAGE_USER; return pte; }
-extern inline pte_t pte_exprotect(pte_t pte)    { pte_val(pte) &= ~_PAGE_USER; return pte; }
-extern inline pte_t pte_mkclean(pte_t pte)      { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkold(pte_t pte)        { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
-extern inline pte_t pte_mkwrite(pte_t pte)      { pte_val(pte) |= _PAGE_RW; return pte; }
-extern inline pte_t pte_mkread(pte_t pte)       { pte_val(pte) |= _PAGE_USER; return pte; }
-extern inline pte_t pte_mkexec(pte_t pte)       { pte_val(pte) |= _PAGE_USER; return pte; }
-extern inline pte_t pte_mkdirty(pte_t pte)      { pte_val(pte) |= _PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkyoung(pte_t pte)      { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
-
-/*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
- */
-extern inline pte_t mk_pte(unsigned long page, pgprot_t pgprot)
-{ pte_t pte; pte_val(pte) = virt_to_phys(page) | pgprot_val(pgprot); return pte; }
-
-extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
-{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
-
-extern inline unsigned long pte_page(pte_t pte)
-{ return phys_to_virt(pte_val(pte) & PAGE_MASK); }
-
-extern inline unsigned long pmd_page(pmd_t pmd)
-{ return phys_to_virt(pmd_val(pmd) & PAGE_MASK); }
-
-/* to find an entry in a page-table-directory */
-extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
-{
-        return mm->pgd + (address >> PGDIR_SHIFT);
-}
-
-/* Find an entry in the second-level page table.. */
-#define pmd_offset(dir, address) ((pmd_t *)(dir))
-
-/* Find an entry in the third-level page table.. */
-#define pte_offset(dir, address) ((pte_t *)(dir))
-
-/*
- * Allocate and free page tables. The xxx_kernel() versions are
- * used to allocate a kernel page table - this turns on ASN bits
- * if any.
- */
-extern inline void pte_free_kernel(pte_t * pte)
-{
-	pte_val(*pte) = 0;
-}
-
-extern inline pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
-{
-	return (pte_t *) pmd;
-}
-
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-#define pmd_free_kernel(pmdp)
-#define pmd_alloc_kernel(pgd,address) ((pmd_t *)(pgd))
-
-#define pte_free(ptep)
-#define pte_alloc(pmd,address) ((pte_t *)(pmd))
-
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-#define pmd_free(pmd)
-#define pmd_alloc(pgd,address) ((pmd_t *)(pgd))
-
-extern inline void pgd_free(pgd_t * pgd)
-{
-	extern void kfree(void *);
-	kfree((void *)pgd);
-}
-
-extern inline pgd_t * pgd_alloc(void)
-{
-	pgd_t *pgd;
-	extern void *kmalloc(unsigned int, int);
-	
-	pgd = (pgd_t *) kmalloc(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL);
-	if (pgd)
-		memset(pgd, 0, PTRS_PER_PGD * BYTES_PER_PTR);
-	return pgd;
-}
-
-extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
-
-#define update_mmu_cache(vma,address,pte) processor.u.armv2._update_mmu_cache(vma,address,pte)
-
-#define SWP_TYPE(entry) (((entry) >> 1) & 0x7f)
-#define SWP_OFFSET(entry) ((entry) >> 8)
-#define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) <<  8))
-
-#endif /* __ASM_PROC_PAGE_H */
-
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armo/pgtable.h linux/include/asm-arm/proc-armo/pgtable.h
--- v2.2.7/linux/include/asm-arm/proc-armo/pgtable.h	Fri Jan  8 22:36:22 1999
+++ linux/include/asm-arm/proc-armo/pgtable.h	Sat May  8 11:06:57 1999
@@ -7,9 +7,9 @@
 #ifndef __ASM_PROC_PGTABLE_H
 #define __ASM_PROC_PGTABLE_H
 
-#include <asm/arch/mmu.h>
+#include <linux/config.h>
 #include <linux/slab.h>
-#include <asm/arch/processor.h>		/* For TASK_SIZE */
+#include <asm/arch/memory.h>		/* For TASK_SIZE */
 
 #define LIBRARY_TEXT_START 0x0c000000
 
@@ -280,13 +280,17 @@
 	return __phys_to_virt(pte_val(pte) & PAGE_MASK);
 }
 
-extern __inline__ pmd_t mk_pmd (pte_t *ptep)
+extern __inline__ pmd_t mk_pmd(pte_t *ptep)
 {
 	pmd_t pmd;
 	pmd_val(pmd) = __virt_to_phys((unsigned long)ptep) | _PAGE_TABLE;
 	return pmd;
 }
 
+/* these are aliases for the above function */
+#define mk_user_pmd(ptep)   mk_pmd(ptep)
+#define mk_kernel_pmd(ptep) mk_pmd(ptep)
+
 #define set_pmd(pmdp,pmd) ((*(pmdp)) = (pmd))
 
 extern __inline__ unsigned long pmd_page(pmd_t pmd)
@@ -319,6 +323,7 @@
  */
 
 #ifndef __SMP__
+#ifndef CONFIG_NO_PGT_CACHE
 extern struct pgtable_cache_struct {
 	unsigned long *pgd_cache;
 	unsigned long *pte_cache;
@@ -329,13 +334,16 @@
 #define pte_quicklist (quicklists.pte_cache)
 #define pgd_quicklist (quicklists.pgd_cache)
 #define pgtable_cache_size (quicklists.pgtable_cache_sz)
+#endif
 
 #else
 #error Pgtable caches have to be per-CPU, so that no locking is needed.
 #endif
 
 extern pgd_t *get_pgd_slow(void);
+extern void free_table(void *table);
 
+#ifndef CONFIG_NO_PGT_CACHE
 extern __inline__ pgd_t *get_pgd_fast(void)
 {
 	unsigned long *ret;
@@ -355,14 +363,17 @@
 	pgd_quicklist = (unsigned long *) pgd;
 	pgtable_cache_size++;
 }
+#endif
 
+/* keep this as an inline so we get type checking */
 extern __inline__ void free_pgd_slow(pgd_t *pgd)
 {
-	kfree(pgd);
+	free_table((void *)pgd);
 }
 
 extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
 
+#ifndef CONFIG_NO_PGT_CACHE
 extern __inline__ pte_t *get_pte_fast(void)
 {
 	unsigned long *ret;
@@ -381,10 +392,12 @@
 	pte_quicklist = (unsigned long *) pte;
 	pgtable_cache_size++;
 }
+#endif
 
+/* keep this as an inline so we get type checking */
 extern __inline__ void free_pte_slow(pte_t *pte)
 {
-	kfree(pte);
+	free_table((void *)pte);
 }
 
 /* We don't use pmd cache, so this is a dummy routine */
@@ -404,6 +417,26 @@
 extern void __bad_pmd(pmd_t *pmd);
 extern void __bad_pmd_kernel(pmd_t *pmd);
 
+#ifdef CONFIG_NO_PGT_CACHE
+#define pte_free_kernel(pte)    free_pte_slow(pte)
+#define pte_free(pte)           free_pte_slow(pte)
+#define pgd_free(pgd)           free_pgd_slow(pgd)
+#define pgd_alloc()             get_pgd_slow()
+
+extern __inline__ pte_t *pte_alloc(pmd_t * pmd, unsigned long address)
+{
+	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+
+	if (pmd_none (*pmd)) {
+		return get_pte_slow(pmd, address);
+	}
+	if (pmd_bad (*pmd)) {
+		__bad_pmd(pmd);
+		return NULL;
+	}
+	return (pte_t *) pmd_page(*pmd) + address;
+}
+#else
 #define pte_free_kernel(pte)    free_pte_fast(pte)
 #define pte_free(pte)           free_pte_fast(pte)
 #define pgd_free(pgd)           free_pgd_fast(pgd)
@@ -427,6 +460,7 @@
 	}
 	return (pte_t *) pmd_page(*pmd) + address;
 }
+#endif
 
 /*
  * allocating and freeing a pmd is trivial: the 1-entry pmd is
@@ -448,7 +482,6 @@
 extern __inline__ void set_pgdir(unsigned long address, pgd_t entry)
 {
 	struct task_struct * p;
-	pgd_t *pgd;
 
 	read_lock(&tasklist_lock);
 	for_each_task(p) {
@@ -457,8 +490,14 @@
 		*pgd_offset(p->mm,address) = entry;
 	}
 	read_unlock(&tasklist_lock);
-	for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
-		pgd[address >> PGDIR_SHIFT] = entry;
+#ifndef CONFIG_NO_PGT_CACHE
+	{
+		pgd_t *pgd;
+		for (pgd = (pgd_t *)pgd_quicklist; pgd;
+		     pgd = (pgd_t *)*(unsigned long *)pgd)
+			pgd[address >> PGDIR_SHIFT] = entry;
+	}
+#endif
 }
 
 extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armo/processor.h linux/include/asm-arm/proc-armo/processor.h
--- v2.2.7/linux/include/asm-arm/proc-armo/processor.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/proc-armo/processor.h	Sat May  8 11:06:57 1999
@@ -14,8 +14,6 @@
 #ifndef __ASM_PROC_PROCESSOR_H
 #define __ASM_PROC_PROCESSOR_H
 
-#ifdef __KERNEL__
-
 #include <asm/assembler.h>
 #include <linux/string.h>
 
@@ -32,6 +30,8 @@
 	unsigned long pc;
 };
 
+#define INIT_CSS (struct context_save_struct){ 0, 0, 0, 0, 0, 0, 0, SVC26_MODE }
+
 typedef struct {
 	void (*put_byte)(void);			/* Special calling convention */
 	void (*get_byte)(void);			/* Special calling convention */
@@ -50,50 +50,13 @@
 
 #define EXTRA_THREAD_STRUCT							\
 	uaccess_t	*uaccess;		/* User access functions*/	\
-	struct context_save_struct *save;					\
-	unsigned long	memmap;							\
 	unsigned long	memcmap[256];
 
 #define EXTRA_THREAD_STRUCT_INIT		\
-	&uaccess_kernel,			\
-	0,					\
-	(unsigned long) swapper_pg_dir,		\
+	,&uaccess_kernel,			\
 	{ 0, }
 
-DECLARE_THREAD_STRUCT;
-
-/*
- * Return saved PC of a blocked thread.
- */
-extern __inline__ unsigned long thread_saved_pc (struct thread_struct *t)
-{
-	if (t->save)
-		return t->save->pc & ~PCMASK;
-	else
-		return 0;
-}
-
-extern __inline__ unsigned long get_css_fp (struct thread_struct *t)
-{
-	if (t->save)
-		return t->save->fp;
-	else
-		return 0;
-}
-
-asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call");
-
-extern __inline__ void copy_thread_css (struct context_save_struct *save)
-{
-	save->r4 =
-	save->r5 =
-	save->r6 =
-	save->r7 =
-	save->r8 =
-	save->r9 =
-	save->fp = 0;
-	save->pc = ((unsigned long)ret_from_sys_call) | SVC26_MODE;
-}
+#define SWAPPER_PG_DIR ((unsigned long)swapper_pg_dir)
 
 #define start_thread(regs,pc,sp)					\
 ({									\
@@ -105,18 +68,16 @@
 	regs->ARM_r2 = stack[2];	/* r2 (envp) */			\
 	regs->ARM_r1 = stack[1];	/* r1 (argv) */			\
 	regs->ARM_r0 = stack[0];	/* r0 (argc) */			\
-	flush_tlb_mm(current->mm);					\
 })
 
 /* Allocation and freeing of basic task resources. */
 /*
  * NOTE! The task struct and the stack go together
  */
-#define alloc_task_struct() \
-	((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
-#define free_task_struct(p)    free_pages((unsigned long)(p),1)
-
+extern unsigned long get_page_8k(int priority);
+extern void free_page_8k(unsigned long page);
 
-#endif
+#define ll_alloc_task_struct()	((struct task_struct *)get_page_8k(GFP_KERNEL))
+#define ll_free_task_struct(p)  free_page_8k((unsigned long)(p))
 
 #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armo/ptrace.h linux/include/asm-arm/proc-armo/ptrace.h
--- v2.2.7/linux/include/asm-arm/proc-armo/ptrace.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/proc-armo/ptrace.h	Sat May  8 11:06:57 1999
@@ -68,8 +68,13 @@
 /* Are the current registers suitable for user mode?
  * (used to maintain security in signal handlers)
  */
-#define valid_user_regs(regs) \
-	(user_mode(regs) && ((regs)->ARM_sp & 3) == 0)
+static inline int valid_user_regs(struct pt_regs *regs)
+{
+	if (!user_mode(regs) || regs->ARM_pc & (F_BIT | I_BIT))
+		return 1;
+
+	return 0;
+}
 
 #endif
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armo/semaphore.h linux/include/asm-arm/proc-armo/semaphore.h
--- v2.2.7/linux/include/asm-arm/proc-armo/semaphore.h	Tue Jan 20 16:39:42 1998
+++ linux/include/asm-arm/proc-armo/semaphore.h	Sat May  8 11:06:57 1999
@@ -13,17 +13,19 @@
 	__asm__ __volatile__ ("
 	@ atomic down operation
 	mov	r0, pc
-	orr	r1, r0, #0x08000000
+	orr	lr, r0, #0x08000000
 	and	r0, r0, #0x0c000003
-	teqp	r1, #0
-	ldr	r1, [%0]
-	subs	r1, r1, #1
-	str	r1, [%0]
-	mov	r1, pc, lsr #28
-	teqp	r0, r1, lsl #28
+	teqp	lr, #0
+	ldr	lr, [%0]
+	subs	lr, lr, #1
+	str	lr, [%0]
+	mov	lr, pc, lsr #28
+	teqp	r0, lr, lsl #28
 	movmi	r0, %0
-	blmi	" SYMBOL_NAME_STR(__down)
-		: : "r" (sem) : "r0", "r1", "r2", "r3", "ip", "lr", "cc");
+	blmi	" SYMBOL_NAME_STR(__down_failed)
+		:
+		: "r" (sem)
+		: "r0", "lr", "cc");
 }
 
 /*
@@ -36,22 +38,47 @@
 	__asm__ __volatile__ ("
 	@ atomic down operation
 	mov	r0, pc
-	orr	r1, r0, #0x08000000
+	orr	lr, r0, #0x08000000
 	and	r0, r0, #0x0c000003
-	teqp	r1, #0
-	ldr	r1, [%1]
-	subs	r1, r1, #1
-	str	r1, [%1]
-	mov	r1, pc, lsr #28
+	teqp	lr, #0
+	ldr	lr, [%1]
+	subs	lr, lr, #1
+	str	lr, [%1]
+	mov	lr, pc, lsr #28
 	orrmi	r0, r0, #0x80000000	@ set N
-	teqp	r0, r1, lsl #28
+	teqp	r0, lr, lsl #28
 	movmi	r0, %1
 	movpl	r0, #0
-	blmi	" SYMBOL_NAME_STR(__down_interruptible) "
+	blmi	" SYMBOL_NAME_STR(__down_interruptible_failed) "
 	mov	%0, r0"
 		: "=r" (result)
 		: "r" (sem)
-		: "r0", "r1", "r2", "r3", "ip", "lr", "cc");
+		: "r0", "lr", "cc");
+	return result;
+}
+
+extern inline int down_trylock(struct semaphore * sem)
+{
+	int result;
+	__asm__ __volatile__ ("
+	@ atomic down operation
+	mov	r0, pc
+	orr	lr, r0, #0x08000000
+	and	r0, r0, #0x0c000003
+	teqp	lr, #0
+	ldr	lr, [%1]
+	subs	lr, lr, #1
+	str	lr, [%1]
+	mov	lr, pc, lsr #28
+	orrmi	r0, r0, #0x80000000	@ set N
+	teqp	r0, lr, lsl #28
+	movmi	r0, %1
+	movpl	r0, #0
+	blmi	" SYMBOL_NAME_STR(__down_trylock_failed) "
+	mov	%0, r0"
+		: "=r" (result)
+		: "r" (sem)
+		: "r0", "lr", "cc");
 	return result;
 }
 
@@ -66,18 +93,20 @@
 	__asm__ __volatile__ ("
 	@ atomic up operation
 	mov	r0, pc
-	orr	r1, r0, #0x08000000
+	orr	lr, r0, #0x08000000
 	and	r0, r0, #0x0c000003
-	teqp	r1, #0
-	ldr	r1, [%0]
-	adds	r1, r1, #1
-	str	r1, [%0]
-	mov	r1, pc, lsr #28
+	teqp	lr, #0
+	ldr	lr, [%0]
+	adds	lr, lr, #1
+	str	lr, [%0]
+	mov	lr, pc, lsr #28
 	orrls	r0, r0, #0x80000000	@ set N
-	teqp	r0, r1, lsl #28
+	teqp	r0, lr, lsl #28
 	movmi	r0, %0
-	blmi	" SYMBOL_NAME_STR(__up)
-		: : "r" (sem) : "r0", "r1", "r2", "r3", "ip", "lr", "cc");
+	blmi	" SYMBOL_NAME_STR(__up_wakeup)
+		:
+		: "r" (sem)
+		: "r0", "lr", "cc");
 }
 
 #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armv/io.h linux/include/asm-arm/proc-armv/io.h
--- v2.2.7/linux/include/asm-arm/proc-armv/io.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/proc-armv/io.h	Sat May  8 11:06:58 1999
@@ -22,17 +22,14 @@
 
 #include <asm/proc-fns.h>
 
-extern inline void dma_cache_inv(unsigned long start, unsigned long size)
-{
-	processor.u.armv3v4._cache_purge_area(start, start + size);
-}
+#define dma_cache_inv(start, size)					    \
+	do { processor.u.armv3v4._cache_purge_area((unsigned long)(start),  \
+		((unsigned long)(start)+(size))); } while (0)
 
-extern inline void dma_cache_wback(unsigned long start, unsigned long size)
-{
-	processor.u.armv3v4._cache_wback_area(start, start + size);
-}
+#define dma_cache_wback(start, size)					    \
+	do { processor.u.armv3v4._cache_wback_area((unsigned long)(start),  \
+		((unsigned long)(start)+(size))); } while (0)
 
-extern inline void dma_cache_wback_inv(unsigned long start, unsigned long size)
-{
-	processor.u.armv3v4._flush_cache_area(start, start + size, 0);
-}
+#define dma_cache_wback_inv(start, size)				    \
+	do { processor.u.armv3v4._flush_cache_area((unsigned long)(start),  \
+		((unsigned long)(start)+(size)), 0); } while (0)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armv/mm-init.h linux/include/asm-arm/proc-armv/mm-init.h
--- v2.2.7/linux/include/asm-arm/proc-armv/mm-init.h	Fri Jan  8 22:36:23 1999
+++ linux/include/asm-arm/proc-armv/mm-init.h	Sat May  8 11:06:58 1999
@@ -37,7 +37,7 @@
  */
 #include <asm/pgtable.h>
  
-#define PTE_SIZE (PTRS_PER_PTE * 4)
+#define PTE_SIZE (PTRS_PER_PTE * BYTES_PER_PTR)
 
 extern unsigned long setup_io_pagetables(unsigned long start_mem);
 
@@ -79,7 +79,7 @@
 alloc_init_page(unsigned long *mem, unsigned long virt, unsigned long phys, int domain, int prot)
 {
 	pgd_t *pgdp;
-	pmd_t *pmdp, pmd;
+	pmd_t *pmdp;
 	pte_t *ptep;
 
 	pgdp = pgd_offset_k(virt);
@@ -92,46 +92,41 @@
 
 		ptep = (pte_t *)memory;
 		memzero(ptep, PTE_SIZE);
+		memory += PTE_SIZE;
 
-		pmd_val(pmd) = __virt_to_phys(memory) | PMD_TYPE_TABLE | PMD_DOMAIN(domain);
-		set_pmd(pmdp, pmd);
+		ptep = (pte_t *)memory;
+		memzero(ptep, PTE_SIZE);
+
+		set_pmd(pmdp, __mk_pmd(ptep, PMD_TYPE_TABLE | PMD_DOMAIN(domain)));
 
 		*mem = memory + PTE_SIZE;
 	}
 
 	ptep = pte_offset(pmdp, virt);
 
-	pte_val(*ptep) = phys | prot | PTE_TYPE_SMALL;
+	set_pte(ptep, mk_pte_phys(phys, __pgprot(prot)));
 }
 
 static inline unsigned long
 setup_pagetables(unsigned long start_mem, unsigned long end_mem)
 {
-	unsigned long address;
+	unsigned long address = 0;
 
-	/*
-	 * map in zero page
-	 */
-	alloc_init_page(&start_mem, 0, __virt_to_phys(PAGE_OFFSET), DOMAIN_USER, PTE_CACHEABLE);
-
-	/*
-	 * ensure no mappings in user space
-	 */
-	for (address = PGDIR_SIZE; address < PAGE_OFFSET; address += PGDIR_SIZE)
-		free_init_section(address);
-
-	/*
-	 * map in physical ram & kernel
-	 */
-	for (address = PAGE_OFFSET; address < end_mem; address += PGDIR_SIZE)
-		alloc_init_section(&start_mem, address, __virt_to_phys(address), DOMAIN_KERNEL,
-				   PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE | PMD_SECT_AP_WRITE);
+	do {
+		if (address >= PAGE_OFFSET && address < end_mem)
+			/*
+			 * map in physical ram & kernel
+			 */
+			alloc_init_section(&start_mem, address, __virt_to_phys(address), DOMAIN_KERNEL,
+					   PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE | PMD_SECT_AP_WRITE);
+		else
+			/*
+			 * unmap everything else
+			 */
+			free_init_section(address);
 
-	/*
-	 * unmap everything else
-	 */
-	for (address = end_mem; address; address += PGDIR_SIZE)
-		free_init_section(address);
+		address += PGDIR_SIZE;
+	} while (address != 0);
 
 	/*
 	 * An area to invalidate the cache
@@ -144,6 +139,12 @@
 	 */
 	start_mem = setup_io_pagetables(start_mem);
 
+	/*
+	 * map in zero page
+	 */
+	alloc_init_page(&start_mem, 0, __virt_to_phys(PAGE_OFFSET),
+			DOMAIN_USER, L_PTE_CACHEABLE | L_PTE_YOUNG | L_PTE_PRESENT);
+
 	flush_cache_all();
 
 	return start_mem;
@@ -156,9 +157,21 @@
 
 	*start_mem = smem = PAGE_ALIGN(*start_mem);
 
+	/*
+	 * Mark all of memory from the end of kernel to end of memory
+	 */
 	while (smem < end_mem) {
-	    	clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags);
-    		smem += PAGE_SIZE;
+		clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags);
+		smem += PAGE_SIZE;
+	}
+
+	/*
+	 * Mark memory from page 1 to start of the swapper page directory
+	 */
+	smem = PAGE_OFFSET + PAGE_SIZE;
+	while (smem < (unsigned long)&swapper_pg_dir) {
+		clear_bit(PG_reserved, &mem_map[MAP_NR(smem)].flags);
+		smem += PAGE_SIZE;
 	}
 }	
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armv/pgtable.h linux/include/asm-arm/proc-armv/pgtable.h
--- v2.2.7/linux/include/asm-arm/proc-armv/pgtable.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/proc-armv/pgtable.h	Sat May  8 11:06:58 1999
@@ -3,14 +3,15 @@
  *
  * Copyright (C) 1995, 1996, 1997 Russell King
  *
- * 12-01-1997	RMK	Altered flushing routines to use function pointers
+ * 12-Jan-1997	RMK	Altered flushing routines to use function pointers
  *			now possible to combine ARM6, ARM7 and StrongARM versions.
+ * 17-Apr-1999	RMK	Now pass an area size to clean_cache_area and
+ *			flush_icache_area.
  */
 #ifndef __ASM_PROC_PGTABLE_H
 #define __ASM_PROC_PGTABLE_H
 
-#include <asm/arch/mmu.h>
-#include <asm/arch/processor.h>		/* For TASK_SIZE */
+#include <asm/arch/memory.h>		/* For TASK_SIZE */
 
 #define LIBRARY_TEXT_START 0x0c000000
 
@@ -41,8 +42,23 @@
 				 ((_vma)->vm_flags & VM_EXEC) ? 1 : 0);	\
 	} while (0)
 
+#define clean_cache_range(_start,_end)					\
+	do {								\
+		unsigned long _s, _sz;					\
+		_s = (unsigned long)_start;				\
+		_sz = (unsigned long)_end - _s;				\
+		processor.u.armv3v4._clean_cache_area(_s, _sz);		\
+	} while (0)
+
+#define clean_cache_area(_start,_size)					\
+	do {								\
+		unsigned long _s;					\
+		_s = (unsigned long)_start;				\
+		processor.u.armv3v4._clean_cache_area(_s, _size);	\
+	} while (0)
+
 #define flush_icache_range(_start,_end)					\
-	processor.u.armv3v4._flush_icache_area((_start), (_end))
+	processor.u.armv3v4._flush_icache_area((_start), (_end) - (_start))
 
 /*
  * We don't have a MEMC chip...
@@ -60,12 +76,6 @@
 	processor.u.armv3v4._flush_ram_page ((_page) & PAGE_MASK);
 
 /*
- * Make the page uncacheable (must flush page beforehand).
- */
-#define uncache_page(_page)						\
-	processor.u.armv3v4._flush_ram_page ((_page) & PAGE_MASK);
-
-/*
  * TLB flushing:
  *
  *  - flush_tlb() flushes the current mm struct TLBs
@@ -106,22 +116,15 @@
 	} while (0)
 
 /*
- * Since the page tables are in cached memory, we need to flush the dirty
- * data cached entries back before we flush the tlb...  This is also useful
- * to flush out the SWI instruction for signal handlers...
+ * PMD_SHIFT determines the size of the area a second-level page table can map
  */
-#define __flush_entry_to_ram(entry)						\
-	processor.u.armv3v4._flush_cache_entry((unsigned long)(entry))
-
-#define __flush_pte_to_ram(entry)						\
-	processor.u.armv3v4._flush_cache_pte((unsigned long)(entry))
-
-/* PMD_SHIFT determines the size of the area a second-level page table can map */
 #define PMD_SHIFT       20
 #define PMD_SIZE        (1UL << PMD_SHIFT)
 #define PMD_MASK        (~(PMD_SIZE-1))
 
-/* PGDIR_SHIFT determines what a third-level page table entry can map */
+/*
+ * PGDIR_SHIFT determines what a third-level page table entry can map
+ */
 #define PGDIR_SHIFT     20
 #define PGDIR_SIZE      (1UL << PGDIR_SHIFT)
 #define PGDIR_MASK      (~(PGDIR_SIZE-1))
@@ -135,6 +138,7 @@
 #define PTRS_PER_PGD    4096
 #define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE)
 
+
 /* Just any arbitrary offset to the start of the vmalloc VM area: the
  * current 8MB value just means that there will be a 8MB "hole" after the
  * physical memory until the kernel virtual memory starts.  That means that
@@ -147,87 +151,28 @@
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
 #define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
 
-/* PMD types (actually level 1 descriptor) */
-#define PMD_TYPE_MASK		0x0003
-#define PMD_TYPE_FAULT		0x0000
-#define PMD_TYPE_TABLE		0x0001
-#define PMD_TYPE_SECT		0x0002
-#define PMD_UPDATABLE		0x0010
-#define PMD_SECT_CACHEABLE	0x0008
-#define PMD_SECT_BUFFERABLE	0x0004
-#define PMD_SECT_AP_WRITE	0x0400
-#define PMD_SECT_AP_READ	0x0800
-#define PMD_DOMAIN(x)		((x) << 5)
-
-/* PTE types (actially level 2 descriptor) */
-#define PTE_TYPE_MASK	0x0003
-#define PTE_TYPE_FAULT	0x0000
-#define PTE_TYPE_LARGE	0x0001
-#define PTE_TYPE_SMALL	0x0002
-#define PTE_AP_READ	0x0aa0
-#define PTE_AP_WRITE	0x0550
-#define PTE_CACHEABLE	0x0008
-#define PTE_BUFFERABLE	0x0004
 
-/* Domains */
+/*
+ * Domains
+ */
 #define DOMAIN_USER	0
 #define DOMAIN_KERNEL	1
 #define DOMAIN_TABLE	1
 #define DOMAIN_IO	2
 
-#define _PAGE_CHG_MASK  (0xfffff00c | PTE_TYPE_MASK)
 
-/*
- * We define the bits in the page tables as follows:
- *  PTE_BUFFERABLE	page is dirty
- *  PTE_AP_WRITE	page is writable
- *  PTE_AP_READ		page is a young (unsetting this causes faults for any access)
- *  PTE_CACHEABLE       page is readable
- *
- * A page will not be made writable without the dirty bit set.
- * It is not legal to have a writable non-dirty page though (it breaks).
- *
- * A readable page is marked as being cacheable.
- * Youngness is indicated by hardware read.  If the page is old,
- * then we will fault and make the page young again.
- */
-#define _PTE_YOUNG	PTE_AP_READ
-#define _PTE_DIRTY	PTE_BUFFERABLE
-#define _PTE_READ	PTE_CACHEABLE
-#define _PTE_WRITE	PTE_AP_WRITE
-
-#define PAGE_NONE       __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG)
-#define PAGE_SHARED     __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG | _PTE_READ | _PTE_WRITE)
-#define PAGE_COPY       __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG | _PTE_READ)
-#define PAGE_READONLY   __pgprot(PTE_TYPE_SMALL | _PTE_YOUNG | _PTE_READ)
-#define PAGE_KERNEL     __pgprot(PTE_TYPE_SMALL | _PTE_READ  | _PTE_DIRTY | _PTE_WRITE)
 
-#define _PAGE_USER_TABLE	(PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_USER))
-#define _PAGE_KERNEL_TABLE	(PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL))
+#undef TEST_VERIFY_AREA
 
 /*
- * The arm can't do page protection for execute, and considers that the same are read.
- * Also, write permissions imply read permissions. This is the closest we can get..
+ * The sa110 doesn't have any external MMU info: the kernel page
+ * tables contain all the necessary information.
  */
-#define __P000  PAGE_NONE
-#define __P001  PAGE_READONLY
-#define __P010  PAGE_COPY
-#define __P011  PAGE_COPY
-#define __P100  PAGE_READONLY
-#define __P101  PAGE_READONLY
-#define __P110  PAGE_COPY
-#define __P111  PAGE_COPY
-
-#define __S000  PAGE_NONE
-#define __S001  PAGE_READONLY
-#define __S010  PAGE_SHARED
-#define __S011  PAGE_SHARED
-#define __S100  PAGE_READONLY
-#define __S101  PAGE_READONLY
-#define __S110  PAGE_SHARED
-#define __S111  PAGE_SHARED
+extern __inline__ void update_mmu_cache(struct vm_area_struct * vma,
+	unsigned long address, pte_t pte)
+{
+}
 
-#undef TEST_VERIFY_AREA
 
 /*
  * BAD_PAGETABLE is used when we need a bogus page-table, while
@@ -240,97 +185,40 @@
 extern pte_t * __bad_pagetable(void);
 extern unsigned long *empty_zero_page;
 
-#define BAD_PAGETABLE __bad_pagetable()
-#define BAD_PAGE __bad_page()
-#define ZERO_PAGE ((unsigned long) empty_zero_page)
+#define BAD_PAGETABLE	__bad_pagetable()
+#define BAD_PAGE	__bad_page()
+#define ZERO_PAGE	((unsigned long) empty_zero_page)
 
 /* number of bits that fit into a memory pointer */
-#define BYTES_PER_PTR			(sizeof(unsigned long))
-#define BITS_PER_PTR                    (8*BYTES_PER_PTR)
+#define BYTES_PER_PTR	(sizeof(unsigned long))
+#define BITS_PER_PTR	(8*BYTES_PER_PTR)
 
 /* to align the pointer to a pointer address */
-#define PTR_MASK                        (~(sizeof(void*)-1))
+#define PTR_MASK	(~(sizeof(void*)-1))
 
 /* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */
-#define SIZEOF_PTR_LOG2                 2
+#define SIZEOF_PTR_LOG2	2
 
 /* to find an entry in a page-table */
 #define PAGE_PTR(address) \
 ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK)
 
-/* to set the page-dir */
+/* to set the page-dir
+ * Note that we need to flush the cache and TLBs
+ * if we are affecting the current task.
+ */
 #define SET_PAGE_DIR(tsk,pgdir)					\
 do {								\
 	tsk->tss.memmap = __virt_to_phys((unsigned long)pgdir);	\
-	if ((tsk) == current)					\
+	if ((tsk) == current) {					\
+		flush_cache_all();				\
 		__asm__ __volatile__(				\
 		"mcr%?	p15, 0, %0, c2, c0, 0\n"		\
 		: : "r" (tsk->tss.memmap));			\
+		flush_tlb_all();				\
+	}							\
 } while (0)
 
-extern __inline__ int pte_none(pte_t pte)
-{
-	return !pte_val(pte);
-}
-
-#define pte_clear(ptep)	set_pte(ptep, __pte(0))
-
-extern __inline__ int pte_present(pte_t pte)
-{
-#if 0
-	/* This is what it really does, the else
-	   part is just to make it easier for the compiler */
-	switch (pte_val(pte) & PTE_TYPE_MASK) {
-	case PTE_TYPE_LARGE:
-	case PTE_TYPE_SMALL:
-		return 1;
-	default:
-		return 0;
-	}
-#else
-	return ((pte_val(pte) + 1) & 2);
-#endif
-}
-
-extern __inline__ int pmd_none(pmd_t pmd)
-{
-	return !pmd_val(pmd);
-}
-
-#define pmd_clear(pmdp) set_pmd(pmdp, __pmd(0))
-
-extern __inline__ int pmd_bad(pmd_t pmd)
-{
-#if 0
-	/* This is what it really does, the else
-	   part is just to make it easier for the compiler */
-	switch (pmd_val(pmd) & PMD_TYPE_MASK) {
-	case PMD_TYPE_FAULT:
-	case PMD_TYPE_TABLE:
-		return 0;
-	default:
-		return 1;
-	}
-#else
-	return pmd_val(pmd) & 2;
-#endif
-}
-
-extern __inline__ int pmd_present(pmd_t pmd)
-{
-#if 0
-	/* This is what it really does, the else
-	   part is just to make it easier for the compiler */
-	switch (pmd_val(pmd) & PMD_TYPE_MASK) {
-	case PMD_TYPE_TABLE:
-		return 1;
-	default:
-		return 0;
-	}
-#else
-	return ((pmd_val(pmd) + 1) & 2);
-#endif
-}
 
 /*
  * The "pgd_xxx()" functions here are trivial for a folded two-level
@@ -342,231 +230,224 @@
 #define pgd_present(pgd)	(1)
 #define pgd_clear(pgdp)
 
-/*
- * The following only work if pte_present() is true.
- * Undefined behaviour if not..
- */
-#define pte_read(pte)		(1)
-#define pte_exec(pte)		(1)
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
-extern __inline__ int pte_write(pte_t pte)
+/* to find an entry in a page-table-directory */
+extern __inline__ pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
 {
-	return pte_val(pte) & _PTE_WRITE;
+	return mm->pgd + (address >> PGDIR_SHIFT);
 }
 
-extern __inline__ int pte_dirty(pte_t pte)
-{
-	return pte_val(pte) & _PTE_DIRTY;
-}
+extern unsigned long get_page_2k(int priority);
+extern void free_page_2k(unsigned long page);
 
-extern __inline__ int pte_young(pte_t pte)
-{
-	return pte_val(pte) & _PTE_YOUNG;
-}
+/*
+ * Allocate and free page tables. The xxx_kernel() versions are
+ * used to allocate a kernel page table - this turns on ASN bits
+ * if any.
+ */
 
-extern __inline__ pte_t pte_wrprotect(pte_t pte)
-{
-	pte_val(pte) &= ~_PTE_WRITE;
-	return pte;
-}
+#ifndef __SMP__
+extern struct pgtable_cache_struct {
+	unsigned long *pgd_cache;
+	unsigned long *pte_cache;
+	unsigned long pgtable_cache_sz;
+} quicklists;
 
-extern __inline__ pte_t pte_nocache(pte_t pte)
-{
-	pte_val(pte) &= ~PTE_CACHEABLE;
-	return pte;
-}
+#define pgd_quicklist (quicklists.pgd_cache)
+#define pmd_quicklist ((unsigned long *)0)
+#define pte_quicklist (quicklists.pte_cache)
+#define pgtable_cache_size (quicklists.pgtable_cache_sz)
+#else
+#error Pgtable caches have to be per-CPU, so that no locking is needed.
+#endif
 
-extern __inline__ pte_t pte_mkclean(pte_t pte)
-{
-	pte_val(pte) &= ~_PTE_DIRTY;
-	return pte;
-}
+extern pgd_t *get_pgd_slow(void);
 
-extern __inline__ pte_t pte_mkold(pte_t pte)
+extern __inline__ pgd_t *get_pgd_fast(void)
 {
-	pte_val(pte) &= ~_PTE_YOUNG;
-	return pte;
+	unsigned long *ret;
+
+	if((ret = pgd_quicklist) != NULL) {
+		pgd_quicklist = (unsigned long *)(*ret);
+		ret[0] = ret[1];
+		clean_cache_area(ret, 4);
+		pgtable_cache_size--;
+	} else
+		ret = (unsigned long *)get_pgd_slow();
+	return (pgd_t *)ret;
 }
 
-extern __inline__ pte_t pte_mkwrite(pte_t pte)
+extern __inline__ void free_pgd_fast(pgd_t *pgd)
 {
-	pte_val(pte) |= _PTE_WRITE;
-	return pte;
+	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
+	pgd_quicklist = (unsigned long *) pgd;
+	pgtable_cache_size++;
 }
 
-extern __inline__ pte_t pte_mkdirty(pte_t pte)
+extern __inline__ void free_pgd_slow(pgd_t *pgd)
 {
-	pte_val(pte) |= _PTE_DIRTY;
-	return pte;
+	free_pages((unsigned long) pgd, 2);
 }
 
-extern __inline__ pte_t pte_mkyoung(pte_t pte)
+#define pgd_free(pgd)		free_pgd_fast(pgd)
+#define pgd_alloc()		get_pgd_fast()
+
+extern __inline__ void set_pgdir(unsigned long address, pgd_t entry)
 {
-	pte_val(pte) |= _PTE_YOUNG;
-	return pte;
+	struct task_struct * p;
+	pgd_t *pgd;
+
+	read_lock(&tasklist_lock);
+	for_each_task(p) {
+		if (!p->mm)
+			continue;
+		*pgd_offset(p->mm,address) = entry;
+	}
+	read_unlock(&tasklist_lock);
+	for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
+		pgd[address >> PGDIR_SHIFT] = entry;
 }
 
-/*
- * The following are unable to be implemented on this MMU
- */
-#if 0
-extern __inline__ pte_t pte_rdprotect(pte_t pte)
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+
+/****************
+* PMD functions *
+****************/
+
+/* PMD types (actually level 1 descriptor) */
+#define PMD_TYPE_MASK		0x0003
+#define PMD_TYPE_FAULT		0x0000
+#define PMD_TYPE_TABLE		0x0001
+#define PMD_TYPE_SECT		0x0002
+#define PMD_UPDATABLE		0x0010
+#define PMD_SECT_CACHEABLE	0x0008
+#define PMD_SECT_BUFFERABLE	0x0004
+#define PMD_SECT_AP_WRITE	0x0400
+#define PMD_SECT_AP_READ	0x0800
+#define PMD_DOMAIN(x)		((x) << 5)
+
+#define _PAGE_USER_TABLE	(PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_USER))
+#define _PAGE_KERNEL_TABLE	(PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL))
+
+#define pmd_none(pmd)		(!pmd_val(pmd))
+#define pmd_clear(pmdp)		set_pmd(pmdp, __pmd(0))
+#define pmd_bad(pmd)		(pmd_val(pmd) & 2)
+#define mk_user_pmd(ptep)	__mk_pmd(ptep, _PAGE_USER_TABLE)
+#define mk_kernel_pmd(ptep)	__mk_pmd(ptep, _PAGE_KERNEL_TABLE)
+#define set_pmd(pmdp,pmd)	processor.u.armv3v4._set_pmd(pmdp,pmd)
+
+/* Find an entry in the second-level page table.. */
+#define pmd_offset(dir, address) ((pmd_t *)(dir))
+
+extern __inline__ int pmd_present(pmd_t pmd)
 {
-	pte_val(pte) &= ~(PTE_CACHEABLE|PTE_AP_READ);
-	return pte;
+	return ((pmd_val(pmd) + 1) & 2);
 }
 
-extern __inline__ pte_t pte_exprotect(pte_t pte)
+/* We don't use pmd cache, so this is a dummy routine */
+extern __inline__ pmd_t *get_pmd_fast(void)
 {
-	pte_val(pte) &= ~(PTE_CACHEABLE|PTE_AP_READ);
-	return pte;
+	return (pmd_t *)0;
 }
 
-extern __inline__ pte_t pte_mkread(pte_t pte)
+extern __inline__ void free_pmd_fast(pmd_t *pmd)
 {
-	pte_val(pte) |= PTE_CACHEABLE;
-	return pte;
 }
 
-extern __inline__ pte_t pte_mkexec(pte_t pte)
+extern __inline__ void free_pmd_slow(pmd_t *pmd)
 {
-	pte_val(pte) |= PTE_CACHEABLE;
-	return pte;
 }
-#endif
+
+extern void __bad_pmd(pmd_t *pmd);
+extern void __bad_pmd_kernel(pmd_t *pmd);
 
 /*
- * Conversion functions: convert a page and protection to a page entry,
- * and a page entry and page directory to the page they refer to.
+ * allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
  */
-extern __inline__ pte_t mk_pte(unsigned long page, pgprot_t pgprot)
+extern __inline__ void pmd_free(pmd_t *pmd)
 {
-	pte_t pte;
-	pte_val(pte) = __virt_to_phys(page) | pgprot_val(pgprot);
-	return pte;
 }
 
-/* This takes a physical page address that is used by the remapping functions */
-extern __inline__ pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
+extern __inline__ pmd_t *pmd_alloc(pgd_t *pgd, unsigned long address)
 {
-	pte_t pte;
-	pte_val(pte) = physpage + pgprot_val(pgprot);
-	return pte;
+	return (pmd_t *) pgd;
 }
 
-extern __inline__ pte_t pte_modify(pte_t pte, pgprot_t newprot)
-{
-	pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
-	return pte;
-}
+#define pmd_free_kernel		pmd_free
+#define pmd_alloc_kernel	pmd_alloc
 
-extern __inline__ void set_pte(pte_t *pteptr, pte_t pteval)
+extern __inline__ pmd_t __mk_pmd(pte_t *ptep, unsigned long prot)
 {
-	*pteptr = pteval;
-	__flush_pte_to_ram(pteptr);
-}
+	unsigned long pte_ptr = (unsigned long)ptep;
+	pmd_t pmd;
 
-extern __inline__ unsigned long pte_page(pte_t pte)
-{
-	return __phys_to_virt(pte_val(pte) & PAGE_MASK);
-}
+	pte_ptr -= PTRS_PER_PTE * BYTES_PER_PTR;
 
-extern __inline__ pmd_t mk_user_pmd(pte_t *ptep)
-{
-	pmd_t pmd;
-	pmd_val(pmd) = __virt_to_phys((unsigned long)ptep) | _PAGE_USER_TABLE;
-	return pmd;
-}
+	/*
+	 * The pmd must be loaded with the physical
+	 * address of the PTE table
+	 */
+	pmd_val(pmd) = __virt_to_phys(pte_ptr) | prot;
 
-extern __inline__ pmd_t mk_kernel_pmd(pte_t *ptep)
-{
-	pmd_t pmd;
-	pmd_val(pmd) = __virt_to_phys((unsigned long)ptep) | _PAGE_KERNEL_TABLE;
 	return pmd;
 }
 
-#if 1
-#define set_pmd(pmdp,pmd) processor.u.armv3v4._set_pmd(pmdp,pmd)
-#else
-extern __inline__ void set_pmd(pmd_t *pmdp, pmd_t pmd)
-{
-	*pmdp = pmd;
-	__flush_pte_to_ram(pmdp);
-}
-#endif
-
 extern __inline__ unsigned long pmd_page(pmd_t pmd)
 {
-	return __phys_to_virt(pmd_val(pmd) & 0xfffffc00);
-}
-
-/* to find an entry in a kernel page-table-directory */
-#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+	unsigned long ptr;
 
-/* to find an entry in a page-table-directory */
-extern __inline__ pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address)
-{
-	return mm->pgd + (address >> PGDIR_SHIFT);
-}
+	ptr = pmd_val(pmd) & ~(PTRS_PER_PTE * BYTES_PER_PTR - 1);
 
-/* Find an entry in the second-level page table.. */
-#define pmd_offset(dir, address) ((pmd_t *)(dir))
+	ptr += PTRS_PER_PTE * BYTES_PER_PTR;
 
-/* Find an entry in the third-level page table.. */
-extern __inline__ pte_t * pte_offset(pmd_t * dir, unsigned long address)
-{
-	return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
+	return __phys_to_virt(ptr);
 }
 
-extern unsigned long get_small_page(int priority);
-extern void free_small_page(unsigned long page);
 
-/*
- * Allocate and free page tables. The xxx_kernel() versions are
- * used to allocate a kernel page table - this turns on ASN bits
- * if any.
- */
-
-#ifndef __SMP__
-extern struct pgtable_cache_struct {
-	unsigned long *pgd_cache;
-	unsigned long *pte_cache;
-	unsigned long pgtable_cache_sz;
-} quicklists;
+/****************
+* PTE functions *
+****************/
 
-#define pgd_quicklist (quicklists.pgd_cache)
-#define pmd_quicklist ((unsigned long *)0)
-#define pte_quicklist (quicklists.pte_cache)
-#define pgtable_cache_size (quicklists.pgtable_cache_sz)
-#else
-#error Pgtable caches have to be per-CPU, so that no locking is needed.
-#endif
+/* PTE types (actially level 2 descriptor) */
+#define PTE_TYPE_MASK		0x0003
+#define PTE_TYPE_FAULT		0x0000
+#define PTE_TYPE_LARGE		0x0001
+#define PTE_TYPE_SMALL		0x0002
+#define PTE_AP_READ		0x0aa0
+#define PTE_AP_WRITE		0x0550
+#define PTE_CACHEABLE		0x0008
+#define PTE_BUFFERABLE		0x0004
 
-extern pgd_t *get_pgd_slow(void);
+#define pte_none(pte)		(!pte_val(pte))
+#define pte_clear(ptep)		set_pte(ptep, __pte(0))
 
-extern __inline__ pgd_t *get_pgd_fast(void)
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+extern __inline__ pte_t mk_pte(unsigned long page, pgprot_t pgprot)
 {
-	unsigned long *ret;
-
-	if((ret = pgd_quicklist) != NULL) {
-		pgd_quicklist = (unsigned long *)(*ret);
-		ret[0] = ret[1];
-		pgtable_cache_size--;
-	} else
-		ret = (unsigned long *)get_pgd_slow();
-	return (pgd_t *)ret;
+	pte_t pte;
+	pte_val(pte) = __virt_to_phys(page) | pgprot_val(pgprot);
+	return pte;
 }
 
-extern __inline__ void free_pgd_fast(pgd_t *pgd)
+/* This takes a physical page address that is used by the remapping functions */
+extern __inline__ pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
 {
-	*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
-	pgd_quicklist = (unsigned long *) pgd;
-	pgtable_cache_size++;
+	pte_t pte;
+	pte_val(pte) = physpage + pgprot_val(pgprot);
+	return pte;
 }
 
-extern __inline__ void free_pgd_slow(pgd_t *pgd)
+#define set_pte(ptep, pte)	processor.u.armv3v4._set_pte(ptep,pte)
+
+extern __inline__ unsigned long pte_page(pte_t pte)
 {
-	free_pages((unsigned long) pgd, 2);
+	return __phys_to_virt(pte_val(pte) & PAGE_MASK);
 }
 
 extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
@@ -579,6 +460,7 @@
 	if((ret = (unsigned long *)pte_quicklist) != NULL) {
 		pte_quicklist = (unsigned long *)(*ret);
 		ret[0] = ret[1];
+		clean_cache_area(ret, 4);
 		pgtable_cache_size--;
 	}
 	return (pte_t *)ret;
@@ -593,31 +475,124 @@
 
 extern __inline__ void free_pte_slow(pte_t *pte)
 {
-	free_small_page((unsigned long)pte);
+	free_page_2k((unsigned long)(pte - PTRS_PER_PTE));
 }
 
-/* We don't use pmd cache, so this is a dummy routine */
-extern __inline__ pmd_t *get_pmd_fast(void)
-{
-	return (pmd_t *)0;
-}
+#define pte_free_kernel(pte)	free_pte_fast(pte)
+#define pte_free(pte)		free_pte_fast(pte)
 
-extern __inline__ void free_pmd_fast(pmd_t *pmd)
+/*###############################################################################
+ * New PageTableEntry stuff...
+ */
+/* We now keep two sets of ptes - the physical and the linux version.
+ * This gives us many advantages, and allows us greater flexibility.
+ *
+ * The Linux pte's contain:
+ *  bit   meaning
+ *   0    page present
+ *   1    young
+ *   2    bufferable	- matches physical pte
+ *   3    cacheable	- matches physical pte
+ *   4    user
+ *   5    write
+ *   6    execute
+ *   7    dirty
+ *  8-11  unused
+ *  12-31 virtual page address
+ *
+ * These are stored at the pte pointer; the physical PTE is at -1024bytes
+ */
+#define L_PTE_PRESENT		(1 << 0)
+#define L_PTE_YOUNG		(1 << 1)
+#define L_PTE_BUFFERABLE	(1 << 2)
+#define L_PTE_CACHEABLE		(1 << 3)
+#define L_PTE_USER		(1 << 4)
+#define L_PTE_WRITE		(1 << 5)
+#define L_PTE_EXEC		(1 << 6)
+#define L_PTE_DIRTY		(1 << 7)
+
+/*
+ * The following macros handle the cache and bufferable bits...
+ */
+#define _L_PTE_DEFAULT	L_PTE_PRESENT | L_PTE_YOUNG
+#define _L_PTE_READ	L_PTE_USER | L_PTE_CACHEABLE
+#define _L_PTE_EXEC	_L_PTE_READ | L_PTE_EXEC
+
+#define PAGE_NONE       __pgprot(_L_PTE_DEFAULT)
+#define PAGE_COPY       __pgprot(_L_PTE_DEFAULT | _L_PTE_READ  | L_PTE_BUFFERABLE)
+#define PAGE_SHARED     __pgprot(_L_PTE_DEFAULT | _L_PTE_READ  | L_PTE_BUFFERABLE | L_PTE_WRITE)
+#define PAGE_READONLY   __pgprot(_L_PTE_DEFAULT | _L_PTE_READ)
+#define PAGE_KERNEL     __pgprot(_L_PTE_DEFAULT | L_PTE_CACHEABLE | L_PTE_BUFFERABLE | L_PTE_DIRTY | L_PTE_WRITE)
+
+#define _PAGE_CHG_MASK		(PAGE_MASK | L_PTE_DIRTY | L_PTE_YOUNG)
+
+/*
+ * The table below defines the page protection levels that we insert into our
+ * Linux page table version.  These get translated into the best that the
+ * architecture can perform.  Note that on most ARM hardware:
+ *  1) We cannot do execute protection
+ *  2) If we could do execute protection, then read is implied
+ *  3) write implies read permissions
+ */
+#define __P000  PAGE_NONE
+#define __P001  PAGE_READONLY
+#define __P010  PAGE_COPY
+#define __P011  PAGE_COPY
+#define __P100  PAGE_READONLY
+#define __P101  PAGE_READONLY
+#define __P110  PAGE_COPY
+#define __P111  PAGE_COPY
+
+#define __S000  PAGE_NONE
+#define __S001  PAGE_READONLY
+#define __S010  PAGE_SHARED
+#define __S011  PAGE_SHARED
+#define __S100  PAGE_READONLY
+#define __S101  PAGE_READONLY
+#define __S110  PAGE_SHARED
+#define __S111  PAGE_SHARED
+
+
+
+#define pte_present(pte)	(pte_val(pte) & L_PTE_PRESENT)
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+#define pte_read(pte)			(pte_val(pte) & L_PTE_USER)
+#define pte_write(pte)			(pte_val(pte) & L_PTE_WRITE)
+#define pte_exec(pte)			(pte_val(pte) & L_PTE_EXEC)
+#define pte_dirty(pte)			(pte_val(pte) & L_PTE_DIRTY)
+#define pte_young(pte)			(pte_val(pte) & L_PTE_YOUNG)
+
+#define PTE_BIT_FUNC(fn,op)			\
+extern inline pte_t fn##(pte_t pte) { pte_val(pte) op##; return pte; }
+
+//PTE_BIT_FUNC(pte_rdprotect, &= ~L_PTE_USER);
+PTE_BIT_FUNC(pte_wrprotect, &= ~L_PTE_WRITE);
+PTE_BIT_FUNC(pte_exprotect, &= ~L_PTE_EXEC);
+PTE_BIT_FUNC(pte_mkclean,   &= ~L_PTE_DIRTY);
+PTE_BIT_FUNC(pte_mkold,     &= ~L_PTE_YOUNG);
+//PTE_BIT_FUNC(pte_mkread,    |= L_PTE_USER);
+PTE_BIT_FUNC(pte_mkwrite,   |= L_PTE_WRITE);
+PTE_BIT_FUNC(pte_mkexec,    |= L_PTE_EXEC);
+PTE_BIT_FUNC(pte_mkdirty,   |= L_PTE_DIRTY);
+PTE_BIT_FUNC(pte_mkyoung,   |= L_PTE_YOUNG);
+PTE_BIT_FUNC(pte_nocache,   &= ~L_PTE_CACHEABLE);
+
+extern __inline__ pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
+	pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot);
+	return pte;
 }
 
-extern __inline__ void free_pmd_slow(pmd_t *pmd)
+/* Find an entry in the third-level page table.. */
+extern __inline__ pte_t * pte_offset(pmd_t * dir, unsigned long address)
 {
+	return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
 }
 
-extern void __bad_pmd(pmd_t *pmd);
-extern void __bad_pmd_kernel(pmd_t *pmd);
-
-#define pte_free_kernel(pte)	free_pte_fast(pte)
-#define pte_free(pte)		free_pte_fast(pte)
-#define pgd_free(pgd)		free_pgd_fast(pgd)
-#define pgd_alloc()		get_pgd_fast()
-
 extern __inline__ pte_t * pte_alloc_kernel(pmd_t *pmd, unsigned long address)
 {
 	address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
@@ -653,49 +628,6 @@
 		return NULL;
 	}
 	return (pte_t *) pmd_page(*pmd) + address;
-}
-
-/*
- * allocating and freeing a pmd is trivial: the 1-entry pmd is
- * inside the pgd, so has no extra memory associated with it.
- */
-extern __inline__ void pmd_free(pmd_t *pmd)
-{
-}
-
-extern __inline__ pmd_t *pmd_alloc(pgd_t *pgd, unsigned long address)
-{
-	return (pmd_t *) pgd;
-}
-
-#define pmd_free_kernel		pmd_free
-#define pmd_alloc_kernel	pmd_alloc
-
-extern __inline__ void set_pgdir(unsigned long address, pgd_t entry)
-{
-	struct task_struct * p;
-	pgd_t *pgd;
-
-	read_lock(&tasklist_lock);
-	for_each_task(p) {
-		if (!p->mm)
-			continue;
-		*pgd_offset(p->mm,address) = entry;
-	}
-	read_unlock(&tasklist_lock);
-	for (pgd = (pgd_t *)pgd_quicklist; pgd; pgd = (pgd_t *)*(unsigned long *)pgd)
-		pgd[address >> PGDIR_SHIFT] = entry;
-}
-
-extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
-
-/*
- * The sa110 doesn't have any external MMU info: the kernel page
- * tables contain all the necessary information.
- */
-extern __inline__ void update_mmu_cache(struct vm_area_struct * vma,
-	unsigned long address, pte_t pte)
-{
 }
 
 #define SWP_TYPE(entry) (((entry) >> 2) & 0x7f)
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armv/processor.h linux/include/asm-arm/proc-armv/processor.h
--- v2.2.7/linux/include/asm-arm/proc-armv/processor.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/proc-armv/processor.h	Sat May  8 11:06:58 1999
@@ -12,8 +12,6 @@
 #ifndef __ASM_PROC_PROCESSOR_H
 #define __ASM_PROC_PROCESSOR_H
 
-#ifdef __KERNEL__
- 
 #define KERNEL_STACK_SIZE	PAGE_SIZE
 
 struct context_save_struct {
@@ -28,56 +26,18 @@
 	unsigned long pc;
 };
 
-#define EXTRA_THREAD_STRUCT				\
-	struct context_save_struct *save;		\
-	unsigned long memmap;
+#define INIT_CSS (struct context_save_struct){ SVC_MODE, 0, 0, 0, 0, 0, 0, 0, 0 }
 
-#define EXTRA_THREAD_STRUCT_INIT			\
-	0,						\
-	((unsigned long) swapper_pg_dir) - PAGE_OFFSET
-
-DECLARE_THREAD_STRUCT;
-
-/*
- * Return saved PC of a blocked thread.
- */
-extern __inline__ unsigned long thread_saved_pc (struct thread_struct *t)
-{
-	if (t->save)
-		return t->save->pc;
-	else
-		return 0;
-}
-
-extern __inline__ unsigned long get_css_fp (struct thread_struct *t)
-{
-	if (t->save)
-		return t->save->fp;
-	else
-		return 0;
-}
-
-asmlinkage void ret_from_sys_call(void) __asm__ ("ret_from_sys_call");
-
-extern __inline__ void copy_thread_css (struct context_save_struct *save)
-{
-	save->cpsr = SVC_MODE;
-	save->r4 =
-	save->r5 =
-	save->r6 =
-	save->r7 =
-	save->r8 =
-	save->r9 =
-	save->fp = 0;
-	save->pc = (unsigned long) ret_from_sys_call;
-}
+#define EXTRA_THREAD_STRUCT
+#define EXTRA_THREAD_STRUCT_INIT
+#define SWAPPER_PG_DIR	(((unsigned long)swapper_pg_dir) - PAGE_OFFSET)
 
 #define start_thread(regs,pc,sp)					\
 ({									\
 	unsigned long *stack = (unsigned long *)sp;			\
 	set_fs(USER_DS);						\
 	memzero(regs->uregs, sizeof(regs->uregs));			\
-	if (current->personality == PER_LINUX_32BIT)			\
+	if (current->personality & ADDR_LIMIT_32BIT)			\
 		regs->ARM_cpsr = USR_MODE;				\
 	else								\
 		regs->ARM_cpsr = USR26_MODE;				\
@@ -92,10 +52,7 @@
 /*
  * NOTE! The task struct and the stack go together
  */
-#define alloc_task_struct() \
-	((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
-#define free_task_struct(p)	free_pages((unsigned long)(p),1)
-
-#endif
+#define ll_alloc_task_struct() ((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
+#define ll_free_task_struct(p) free_pages((unsigned long)(p),1)
 
 #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armv/ptrace.h linux/include/asm-arm/proc-armv/ptrace.h
--- v2.2.7/linux/include/asm-arm/proc-armv/ptrace.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/proc-armv/ptrace.h	Sat May  8 11:06:58 1999
@@ -52,9 +52,14 @@
 #define CC_Z_BIT	(1 << 30)
 #define CC_N_BIT	(1 << 31)
 
+#if 0 /* GCC/egcs should be able to optimise this, IMHO */
 #define user_mode(regs)	\
 	((((regs)->ARM_cpsr & MODE_MASK) == USR_MODE) || \
 	 (((regs)->ARM_cpsr & MODE_MASK) == USR26_MODE))
+#else
+#define user_mode(regs)	\
+	(((regs)->ARM_cpsr & 0xf) == 0)
+#endif
 
 #define processor_mode(regs) \
 	((regs)->ARM_cpsr & MODE_MASK)
@@ -74,8 +79,19 @@
 /* Are the current registers suitable for user mode?
  * (used to maintain security in signal handlers)
  */
-#define valid_user_regs(regs) \
-	(user_mode(regs) && ((regs)->ARM_sp & 3) == 0)
+static inline int valid_user_regs(struct pt_regs *regs)
+{
+	if ((regs->ARM_cpsr & 0xf) == 0 ||
+	    (regs->ARM_cpsr & (F_BIT|I_BIT)))
+		return 1;
+
+	/*
+	 * Force CPSR to something logical...
+	 */
+	regs->ARM_cpsr &= (CC_V_BIT|CC_C_BIT|CC_Z_BIT|CC_N_BIT|0x10);
+
+	return 0;
+}
 
 #endif
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armv/semaphore.h linux/include/asm-arm/proc-armv/semaphore.h
--- v2.2.7/linux/include/asm-arm/proc-armv/semaphore.h	Fri Jan  8 22:36:23 1999
+++ linux/include/asm-arm/proc-armv/semaphore.h	Sat May  8 11:06:58 1999
@@ -60,6 +60,32 @@
 	return temp;
 }
 
+extern inline int down_trylock(struct semaphore *sem)
+{
+	unsigned int cpsr, temp;
+
+	__asm__ __volatile__ ("
+	@ atomic down try lock operation
+	mrs	%0, cpsr
+	orr	%1, %0, #128		@ disable IRQs
+	bic	%0, %0, #0x80000000	@ clear N
+	msr	cpsr, %1
+	ldr	%1, [%2]
+	subs	%1, %1, #1
+	orrmi	%0, %0, #0x80000000	@ set N
+	str	%1, [%2]
+	msr	cpsr, %0
+	movmi	r0, %2
+	movpl	r0, #0
+	blmi	" SYMBOL_NAME_STR(__down_trylock_failed) "
+	mov	%1, r0"
+		: "=&r" (cpsr), "=&r" (temp)
+		: "r" (sem)
+		: "r0", "lr", "cc");
+
+	return temp;
+}
+
 /*
  * Note! This is subtle. We jump to wake people up only if
  * the semaphore was negative (== somebody was waiting on it).
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-armv/uaccess.h linux/include/asm-arm/proc-armv/uaccess.h
--- v2.2.7/linux/include/asm-arm/proc-armv/uaccess.h	Fri Jan  8 22:36:23 1999
+++ linux/include/asm-arm/proc-armv/uaccess.h	Sat May  8 11:06:58 1999
@@ -133,6 +133,7 @@
 	"	.section .fixup,\"ax\"\n"			\
 	"	.align	2\n"					\
 	"3:	mvn	%0, %3\n"				\
+	"	mov	%1, #0\n"				\
 	"	b	2b\n"					\
 	"	.previous\n"					\
 	"	.section __ex_table,\"a\"\n"			\
@@ -153,6 +154,7 @@
 	"	.section .fixup,\"ax\"\n"			\
 	"	.align	2\n"					\
 	"4:	mvn	%0, %5\n"				\
+	"	mov	%1, #0\n"				\
 	"	b	3b\n"					\
 	"	.previous\n"					\
 	"	.section __ex_table,\"a\"\n"			\
@@ -173,6 +175,7 @@
 	"	.section .fixup,\"ax\"\n"			\
 	"	.align	2\n"					\
 	"3:	mvn	%0, %3\n"				\
+	"	mov	%1, #0\n"				\
 	"	b	2b\n"					\
 	"	.previous\n"					\
 	"	.section __ex_table,\"a\"\n"			\
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/proc-fns.h linux/include/asm-arm/proc-fns.h
--- v2.2.7/linux/include/asm-arm/proc-fns.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/proc-fns.h	Sat May  8 11:07:16 1999
@@ -9,6 +9,10 @@
 #include <asm/page.h>
 
 #ifdef __KERNEL__
+
+/* forward-decare task_struct */
+struct task_struct;
+
 /*
  * Don't change this structure
  */
@@ -18,7 +22,7 @@
 	 *
 	 * flush caches for task switch
 	 */
-	void (*_switch_to)(void *prev, void *next);
+	struct task_struct *(*_switch_to)(struct task_struct *prev, struct task_struct *next);
 	/*
 	 * get data abort address/flags
 	 */
@@ -54,10 +58,10 @@
 			 */
 			void (*_flush_cache_entry)(unsigned long address);
 			/*
-			 * flush a virtual address used for a page table
-			 * note D-cache only!
+			 * clean a virtual address range from the
+			 * D-cache without flushing the cache.
 			 */
-			void (*_flush_cache_pte)(unsigned long address);
+			void (*_clean_cache_area)(unsigned long start, unsigned long size);
 			/*
 			 * flush a page to RAM
 			 */
@@ -76,13 +80,17 @@
 			 */
 			void (*_set_pmd)(pmd_t *pmdp, pmd_t pmd);
 			/*
+			 * Set a PTE
+			 */
+			void (*_set_pte)(pte_t *ptep, pte_t pte);
+			/*
 			 * Special stuff for a reset
 			 */
 			unsigned long (*reset)(void);
 			/*
 			 * flush an icached page
 			 */
-			void (*_flush_icache_area)(unsigned long start, unsigned long end);
+			void (*_flush_icache_area)(unsigned long start, unsigned long size);
 			/*
 			 * write back dirty cached data
 			 */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/processor.h linux/include/asm-arm/processor.h
--- v2.2.7/linux/include/asm-arm/processor.h	Tue Jan 19 11:32:53 1999
+++ linux/include/asm-arm/processor.h	Sat May  8 11:06:58 1999
@@ -7,12 +7,14 @@
 #ifndef __ASM_ARM_PROCESSOR_H
 #define __ASM_ARM_PROCESSOR_H
 
+#define FP_SIZE 35
+
 struct fp_hard_struct {
-	unsigned int save[140/4];		/* as yet undefined */
+	unsigned int save[FP_SIZE];		/* as yet undefined */
 };
 
 struct fp_soft_struct {
-	unsigned int save[140/4];		/* undefined information */
+	unsigned int save[FP_SIZE];		/* undefined information */
 };
 
 union fp_state {
@@ -22,28 +24,59 @@
 
 typedef unsigned long mm_segment_t;		/* domain register	*/
 
-#define NR_DEBUGS	5
+#ifdef __KERNEL__
 
-#define DECLARE_THREAD_STRUCT							\
-struct thread_struct {								\
-	unsigned long	address;		/* Address of fault	*/	\
-	unsigned long	trap_no;		/* Trap number		*/	\
-	unsigned long	error_code;		/* Error code of trap	*/	\
-	union fp_state	fpstate;		/* FPE save state	*/	\
-	unsigned long	debug[NR_DEBUGS];	/* Debug/ptrace		*/	\
-	EXTRA_THREAD_STRUCT							\
-}
+#include <asm/assembler.h> 
+
+#define NR_DEBUGS	5
 
 #include <asm/arch/processor.h>
 #include <asm/proc/processor.h>
 
-#define INIT_TSS  {			\
-	0,				\
-	0,				\
-	0,				\
-	{ { { 0, }, }, },		\
-	{ 0, },				\
-	EXTRA_THREAD_STRUCT_INIT	\
+struct thread_struct {
+	unsigned long			address;	  /* Address of fault	*/
+	unsigned long			trap_no;	  /* Trap number	*/
+	unsigned long			error_code;	  /* Error code of trap	*/
+	union fp_state			fpstate;	  /* FPE save state	*/
+	unsigned long			debug[NR_DEBUGS]; /* Debug/ptrace	*/
+	struct context_save_struct	*save;		  /* context save	*/
+	unsigned long			memmap;		  /* page tables	*/
+	EXTRA_THREAD_STRUCT
+};
+
+#define INIT_MMAP \
+{ &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
+
+#define INIT_TSS  {				\
+	0,					\
+	0,					\
+	0,					\
+	{ { { 0, }, }, },			\
+	{ 0, },					\
+	(struct context_save_struct *)0,	\
+	SWAPPER_PG_DIR				\
+	EXTRA_THREAD_STRUCT_INIT		\
+}
+
+/*
+ * Return saved PC of a blocked thread.
+ */
+extern __inline__ unsigned long thread_saved_pc(struct thread_struct *t)
+{
+	return t->save ? t->save->pc & ~PCMASK : 0;
+}
+
+extern __inline__ unsigned long get_css_fp(struct thread_struct *t)
+{
+	return t->save ? t->save->fp : 0;
+}
+
+asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call");
+
+extern __inline__ void init_thread_css(struct context_save_struct *save)
+{
+	*save = INIT_CSS;
+	save->pc |= (unsigned long)ret_from_sys_call;
 }
 
 /* Forward declaration, a strange C thing */
@@ -57,7 +90,12 @@
 #define release_segments(mm)		do { } while (0)
 #define forget_segments()		do { } while (0)
 
+extern struct task_struct *alloc_task_struct(void);
+extern void free_task_struct(struct task_struct *);
+
 #define init_task	(init_task_union.task)
 #define init_stack	(init_task_union.stack)
+
+#endif
 
 #endif /* __ASM_ARM_PROCESSOR_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/semaphore-helper.h linux/include/asm-arm/semaphore-helper.h
--- v2.2.7/linux/include/asm-arm/semaphore-helper.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-arm/semaphore-helper.h	Sat May  8 11:06:58 1999
@@ -0,0 +1,84 @@
+#ifndef ASMARM_SEMAPHORE_HELPER_H
+#define ASMARM_SEMAPHORE_HELPER_H
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ */
+static inline void wake_one_more(struct semaphore * sem)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	if (atomic_read(&sem->count) <= 0)
+		sem->waking++;
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+}
+
+static inline int waking_non_zero(struct semaphore *sem)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	if (sem->waking > 0) {
+		sem->waking--;
+		ret = 1;
+	}
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+	return ret;
+}
+
+/*
+ * waking non zero interruptible
+ *	1	got the lock
+ *	0	go to sleep
+ *	-EINTR	interrupted
+ *
+ * We must undo the sem->count down_interruptible() increment while we are
+ * protected by the spinlock in order to make this atomic_inc() with the
+ * atomic_read() in wake_one_more(), otherwise we can race. -arca
+ */
+static inline int waking_non_zero_interruptible(struct semaphore *sem,
+						struct task_struct *tsk)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	if (sem->waking > 0) {
+		sem->waking--;
+		ret = 1;
+	} else if (signal_pending(tsk)) {
+		atomic_inc(&sem->count);
+		ret = -EINTR;
+	}
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+	return ret;	
+}
+
+/*
+ * waking_non_zero_try_lock:
+ *	1	failed to lock
+ *	0	got the lock
+ *
+ * We must undo the sem->count down_interruptible() increment while we are
+ * protected by the spinlock in order to make this atomic_inc() with the
+ * atomic_read() in wake_one_more(), otherwise we can race. -arca
+ */
+static inline int waking_non_zero_trylock(struct semaphore *sem)
+{
+	unsigned long flags;
+	int ret = 1;
+
+	spin_lock_irqsave(&semaphore_wake_lock, flags);
+	if (sem->waking <= 0)
+		atomic_inc(&sem->count);
+	else {
+		sem->waking--;
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+	return ret;
+}
+
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/semaphore.h linux/include/asm-arm/semaphore.h
--- v2.2.7/linux/include/asm-arm/semaphore.h	Tue Jan 19 11:32:53 1999
+++ linux/include/asm-arm/semaphore.h	Sat May  8 11:06:58 1999
@@ -19,49 +19,15 @@
 
 asmlinkage void __down_failed (void /* special register calling convention */);
 asmlinkage int  __down_interruptible_failed (void /* special register calling convention */);
+asmlinkage int  __down_failed_trylock(void  /* params in registers */);
 asmlinkage void __up_wakeup (void /* special register calling convention */);
 
 extern void __down(struct semaphore * sem);
 extern int  __down_interruptible(struct semaphore * sem);
+extern int  __down_trylock(struct semaphore * sem);
 extern void __up(struct semaphore * sem);
 
 #define sema_init(sem, val)	atomic_set(&((sem)->count), (val))
-
-/*
- * These two _must_ execute atomically wrt each other.
- *
- * This is trivially done with load_locked/store_cond,
- * but on the x86 we need an external synchronizer.
- * Currently this is just the global interrupt lock,
- * bah. Go for a smaller spinlock some day.
- *
- * (On the other hand this shouldn't be in any critical
- * path, so..)
- */
-static inline void wake_one_more(struct semaphore * sem)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	sem->waking++;
-	restore_flags(flags);
-}
-
-static inline int waking_non_zero(struct semaphore *sem, struct task_struct *tsk)
-{
-	unsigned long flags;
-	int ret = 0;
-
-	save_flags(flags);
-	cli();
-	if (sem->waking > 0) {
-		sem->waking--;
-		ret = 1;
-	}
-	restore_flags(flags);
-	return ret;
-}
 
 #include <asm/proc/semaphore.h>
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/system.h linux/include/asm-arm/system.h
--- v2.2.7/linux/include/asm-arm/system.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-arm/system.h	Sat May  8 11:07:16 1999
@@ -1,10 +1,26 @@
 #ifndef __ASM_ARM_SYSTEM_H
 #define __ASM_ARM_SYSTEM_H
 
+#include <linux/kernel.h>
+
+#ifdef __KERNEL__
+
 #include <linux/config.h>
 
+#define __ebsa285_data		__attribute__((__section__(".data.ebsa285")))
+#define __netwinder_data	__attribute__((__section__(".data.netwinder")))
+
+#ifdef CONFIG_TEXT_SECTIONS
+#define __ebsa285_text		__attribute__((__section__(".text.ebsa285")))
+#define __netwinder_text	__attribute__((__section__(".text.netwinder")))
+#else
+#define __ebsa285_text
+#define __netwinder_text
+#endif
+
 /* The type of machine we're running on */
-extern unsigned int machine_type;
+extern unsigned int __machine_arch_type;
+
 #define MACH_TYPE_EBSA110	0
 #define MACH_TYPE_RISCPC	1
 #define MACH_TYPE_NEXUSPCI	3
@@ -12,31 +28,101 @@
 #define MACH_TYPE_NETWINDER	5
 #define MACH_TYPE_CATS		6
 #define MACH_TYPE_TBOX		7
+#define MACH_TYPE_CO285		8
+#define MACH_TYPE_CLPS7110	9
+#define MACH_TYPE_ARCHIMEDES	10
+#define MACH_TYPE_A5K		11
+
+/*
+ * Sort out a definition for machine_arch_type
+ * The rules basically are:
+ * 1. If one architecture is selected, then all machine_is_xxx()
+ *    are constant.
+ * 2. If two or more architectures are selected, then the selected
+ *    machine_is_xxx() are variable, and the unselected machine_is_xxx()
+ *    are constant zero.
+ */
+#ifdef CONFIG_ARCH_EBSA110
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_EBSA110
+# endif
+# define machine_is_ebsa110()	(machine_arch_type == MACH_TYPE_EBSA110)
+#else
+# define machine_is_ebsa110()	(0)
+#endif
+
+#ifdef CONFIG_ARCH_RPC
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_RISCPC
+# endif
+# define machine_is_riscpc()	(machine_arch_type == MACH_TYPE_RISCPC)
+#else
+# define machine_is_riscpc()	(0)
+#endif
 
 #ifdef CONFIG_ARCH_EBSA285
-#define machine_is_ebsa285()	(1)
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_EBSA285
+# endif
+# define machine_is_ebsa285()	(machine_arch_type == MACH_TYPE_EBSA285)
 #else
-#define machine_is_ebsa285()	(0)
+# define machine_is_ebsa285()	(0)
 #endif
 
-#ifdef CONFIG_ARCH_VNC
-#define machine_is_netwinder()	(1)
+#ifdef CONFIG_ARCH_NETWINDER
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_NETWINDER
+# endif
+# define machine_is_netwinder()	(machine_arch_type == MACH_TYPE_NETWINDER)
 #else
-#define machine_is_netwinder()	(0)
+# define machine_is_netwinder()	(0)
 #endif
 
-#if defined(CONFIG_CATS)
-#define machine_is_cats()	(machine_type == MACH_TYPE_CATS)
+#ifdef CONFIG_CATS
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_CATS
+# endif
+# define machine_is_cats()	(machine_arch_type == MACH_TYPE_CATS)
 #else
-#define machine_is_cats()	(0)
+# define machine_is_cats()	(0)
 #endif
 
-#if 0
-#define machine_is_ebsa285()	(machine_type == MACH_TYPE_EBSA285)
-#define machine_is_netwinder()	(machine_type == MACH_TYPE_NETWINDER)
+#ifdef CONFIG_ARCH_CO285
+# ifdef machine_arch_type
+#  undef machine_arch_type
+#  define machine_arch_type	__machine_arch_type
+# else
+#  define machine_arch_type	MACH_TYPE_CO285
+# endif
+# define machine_is_co285()	(machine_arch_type == MACH_TYPE_CO285)
+#else
+# define machine_is_co285()	(0)
 #endif
 
-#include <linux/kernel.h>
+#ifndef machine_arch_type
+#define machine_arch_type	__machine_arch_type
+#endif
+
+/*
+ * task_struct isn't always declared - forward-declare it here.
+ */
+struct task_struct;
+
 #include <asm/proc-fns.h>
 
 extern void arm_malalignedptr(const char *, void *, volatile void *);
@@ -53,7 +139,7 @@
  *
  * `next' and `prev' should be struct task_struct, but it isn't always defined
  */
-#define switch_to(prev,next) processor._switch_to(prev,next)
+#define switch_to(prev,next,last) do { last = processor._switch_to(prev,next); } while (0)
 
 /*
  * Include processor dependent parts
@@ -62,9 +148,12 @@
 #include <asm/arch/system.h>
 
 #define mb() __asm__ __volatile__ ("" : : : "memory")
-#define nop() __asm__ __volatile__("mov r0,r0\n\t");
+#define rmb() mb()
+#define wmb() mb()
+#define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t");
 
 extern asmlinkage void __backtrace(void);
 
 #endif
 
+#endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/unistd.h linux/include/asm-arm/unistd.h
--- v2.2.7/linux/include/asm-arm/unistd.h	Fri Jan  8 22:36:23 1999
+++ linux/include/asm-arm/unistd.h	Sat May  8 11:06:58 1999
@@ -195,6 +195,9 @@
 #define __NR_capset			(__NR_SYSCALL_BASE+185)
 #define __NR_sigaltstack		(__NR_SYSCALL_BASE+186)
 #define __NR_sendfile			(__NR_SYSCALL_BASE+187)
+					/* 188 reserved */
+					/* 189 reserved */
+#define __NR_vfork			(__NR_SYSCALL_BASE+190)
 
 #define __sys2(x) #x
 #define __sys1(x) __sys2(x)
@@ -364,7 +367,7 @@
 
 static inline int _exit(int exitcode)
 {
-	extern int sys_exit(int);
+	extern int sys_exit(int) __attribute__((noreturn));
 	return sys_exit(exitcode);
 }
 
@@ -393,37 +396,11 @@
 static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp);
 
 /*
- * This is the mechanism for creating a new kernel thread.
- *
- * NOTE! Only a kernel-only process(ie the swapper or direct descendants
- * who haven't done an "execve()") should use this: it will work within
- * a system call from a "real" process, but the process memory space will
- * not be free'd until both the parent and the child have exited.
+ * Create a new kernel thread
  */
-static inline pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-	long retval;
-
-	__asm__ __volatile__("
-	mov	r0,%1
-	mov	r1,%2
-	"__syscall(clone)"
-	teq	r0, #0
-	bne	1f
-	mov	r0,%4
-	mov	lr, pc
-	mov	pc, %3
-	"__syscall(exit)"
-1:	mov %0,r0"
-        : "=r" (retval)
-        : "Ir" (flags | CLONE_VM), "Ir" (NULL), "r" (fn), "Ir" (arg)
-	: "r0","r1","r2","r3","lr");
-	
-	return retval;
-}
+extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 
 #endif
-
 #endif /* __ASM_ARM_UNISTD_H */
 
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/vga.h linux/include/asm-arm/vga.h
--- v2.2.7/linux/include/asm-arm/vga.h	Wed Sep  9 14:51:12 1998
+++ linux/include/asm-arm/vga.h	Sat May  8 11:06:58 1999
@@ -1,9 +1,10 @@
 #ifndef ASMARM_VGA_H
 #define ASMARM_VGA_H
 
+#include <asm/hardware.h>
 #include <asm/io.h>
 
-#define VGA_MAP_MEM(x)	(0xe0000000 + (x))
+#define VGA_MAP_MEM(x)	(PCIMEM_BASE + (x))
 
 #define vga_readb(x)	(*(x))
 #define vga_writeb(x,y)	(*(y) = (x))
diff -u --recursive --new-file v2.2.7/linux/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h
--- v2.2.7/linux/include/asm-i386/bugs.h	Fri Jan  1 12:58:21 1999
+++ linux/include/asm-i386/bugs.h	Mon May 10 10:32:45 1999
@@ -19,6 +19,7 @@
 
 #include <linux/config.h>
 #include <asm/processor.h>
+#include <asm/msr.h>
 
 #define CONFIG_BUGi386
 
@@ -27,6 +28,11 @@
 	boot_cpu_data.hlt_works_ok = 0;
 }
 
+__initfunc(static void mca_pentium(char *s, int *ints))
+{
+	mca_pentium_flag = 1;
+}
+
 __initfunc(static void no_387(char *s, int *ints))
 {
 	boot_cpu_data.hard_math = 0;
@@ -61,6 +67,31 @@
 #endif
 		return;
 	}
+	if (mca_pentium_flag) {
+		/* The IBM Model 95 machines with pentiums lock up on
+		 * fpu test, so we avoid it. All pentiums have inbuilt
+		 * FPU and thus should use exception 16. We still do
+		 * the FDIV test, although I doubt there where ever any
+		 * MCA boxes built with non-FDIV-bug cpus.
+		 */
+		__asm__("fninit\n\t"
+			"fldl %1\n\t"
+			"fdivl %2\n\t"
+			"fmull %2\n\t"
+			"fldl %1\n\t"
+			"fsubp %%st,%%st(1)\n\t"
+			"fistpl %0\n\t"
+			"fwait\n\t"
+			"fninit"
+			: "=m" (*&boot_cpu_data.fdiv_bug)
+			: "m" (*&x), "m" (*&y));
+		printk("mca-pentium specified, avoiding FPU coupling test... ");
+		if (!boot_cpu_data.fdiv_bug)
+			printk("??? No FDIV bug? Lucky you...\n");
+		else
+			printk("detected FDIV bug though.\n");
+		return;
+	}
 	/*
 	 * check if exception 16 works correctly.. This is truly evil
 	 * code: it disables the high 8 interrupts to make sure that
@@ -173,10 +204,10 @@
 
 		n = K6_BUG_LOOP;
 		f_vide = vide;
-		__asm__ ("rdtsc" : "=a" (d));
+		rdtscl(d);
 		while (n--) 
 			f_vide();
-		__asm__ ("rdtsc" : "=a" (d2));
+		rdtscl(d2);
 		d = d2-d;
 
 		/* Knock these two lines out if it debugs out ok */
@@ -246,6 +277,7 @@
 	    ((Cx86_dir0_msb == 5) || (Cx86_dir0_msb == 3))) {
 		int eax, dummy;
 		unsigned char ccr3, ccr4;
+		__u32 old_cap;
 
 		cli();
 		ccr3 = getCx86(CX86_CCR3);
@@ -257,8 +289,11 @@
 
 		/* we have up to level 1 available on the Cx6x86(L|MX) */
 		boot_cpu_data.cpuid_level = 1;
+		/*  Need to preserve some externally computed capabilities  */
+		old_cap = boot_cpu_data.x86_capability & X86_FEATURE_MTRR;
 		cpuid(1, &eax, &dummy, &dummy,
 		      &boot_cpu_data.x86_capability);
+		boot_cpu_data.x86_capability |= old_cap;
 
 		boot_cpu_data.x86 = (eax >> 8) & 15;
 		/*
@@ -314,6 +349,24 @@
 }
  
 /*
+ * In setup.c's cyrix_model() we have set the boot_cpu_data.coma_bug
+ * on certain processors that we know contain this bug and now we
+ * enable the workaround for it.
+ */
+
+__initfunc(static void check_cyrix_coma(void))
+{
+	if (boot_cpu_data.coma_bug) {
+		unsigned char ccr1;
+		cli();
+		ccr1 = getCx86 (CX86_CCR1);
+		setCx86 (CX86_CCR1, ccr1 | 0x10);
+		sti();
+		printk("Cyrix processor with \"coma bug\" found, workaround enabled\n");
+	}
+}
+ 
+/*
  * Check wether we are able to run this kernel safely on SMP.
  *
  * - In order to run on a i386, we need to be compiled for i386
@@ -371,5 +424,6 @@
 	check_popad();
 	check_amd_k6();
 	check_pentium_f00f();
+	check_cyrix_coma();
 	system_utsname.machine[1] = '0' + boot_cpu_data.x86;
 }
diff -u --recursive --new-file v2.2.7/linux/include/asm-i386/irq.h linux/include/asm-i386/irq.h
--- v2.2.7/linux/include/asm-i386/irq.h	Tue Feb 23 15:21:34 1999
+++ linux/include/asm-i386/irq.h	Thu May  6 14:02:34 1999
@@ -29,6 +29,7 @@
 }
 
 extern void disable_irq(unsigned int);
+extern void disable_irq_nosync(unsigned int);
 extern void enable_irq(unsigned int);
 
 #endif /* _ASM_IRQ_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-i386/msr.h linux/include/asm-i386/msr.h
--- v2.2.7/linux/include/asm-i386/msr.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-i386/msr.h	Thu Apr 29 11:53:41 1999
@@ -0,0 +1,30 @@
+/*
+ * Access to machine-specific registers (available on 586 and better only)
+ * Note: the rd* operations modify the parameters directly (without using
+ * pointer indirection), this allows gcc to optimize better
+ */
+
+#define rdmsr(msr,val1,val2) \
+       __asm__ __volatile__("rdmsr" \
+			    : "=a" (val1), "=d" (val2) \
+			    : "c" (msr))
+
+#define wrmsr(msr,val1,val2) \
+     __asm__ __volatile__("wrmsr" \
+			  : /* no outputs */ \
+			  : "c" (msr), "a" (val1), "d" (val2))
+
+#define rdtsc(low,high) \
+     __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
+
+#define rdtscl(low) \
+     __asm__ __volatile__ ("rdtsc" : "=a" (low) : : "edx")
+
+#define rdtscll(val) \
+     __asm__ __volatile__ ("rdtsc" : "=A" (val))
+
+#define rdpmc(counter,low,high) \
+     __asm__ __volatile__("rdpmc" \
+			  : "=a" (low), "=d" (high) \
+			  : "c" (counter))
+
diff -u --recursive --new-file v2.2.7/linux/include/asm-i386/mtrr.h linux/include/asm-i386/mtrr.h
--- v2.2.7/linux/include/asm-i386/mtrr.h	Mon Oct  5 13:13:42 1998
+++ linux/include/asm-i386/mtrr.h	Mon May 10 11:16:51 1999
@@ -1,6 +1,6 @@
 /*  Generic MTRR (Memory Type Range Register) ioctls.
 
-    Copyright (C) 1997-1998  Richard Gooch
+    Copyright (C) 1997-1999  Richard Gooch
 
     This library is free software; you can redistribute it and/or
     modify it under the terms of the GNU Library General Public
@@ -44,10 +44,11 @@
 };
 
 /*  These are the various ioctls  */
-#define MTRRIOC_ADD_ENTRY        _IOW(MTRR_IOCTL_BASE, 0, struct mtrr_sentry)
-#define MTRRIOC_SET_ENTRY        _IOW(MTRR_IOCTL_BASE, 1, struct mtrr_sentry)
-#define MTRRIOC_DEL_ENTRY        _IOW(MTRR_IOCTL_BASE, 2, struct mtrr_sentry)
+#define MTRRIOC_ADD_ENTRY        _IOW(MTRR_IOCTL_BASE,  0, struct mtrr_sentry)
+#define MTRRIOC_SET_ENTRY        _IOW(MTRR_IOCTL_BASE,  1, struct mtrr_sentry)
+#define MTRRIOC_DEL_ENTRY        _IOW(MTRR_IOCTL_BASE,  2, struct mtrr_sentry)
 #define MTRRIOC_GET_ENTRY        _IOWR(MTRR_IOCTL_BASE, 3, struct mtrr_gentry)
+#define MTRRIOC_KILL_ENTRY       _IOW(MTRR_IOCTL_BASE,  4, struct mtrr_sentry)
 
 /*  These are the region types  */
 #define MTRR_TYPE_UNCACHABLE 0
@@ -75,7 +76,7 @@
 #ifdef __KERNEL__
 
 /*  The following functions are for use by other drivers  */
-# if defined(CONFIG_MTRR) || defined(CONFIG_MTRR_MODULE)
+# ifdef CONFIG_MTRR
 extern int mtrr_add (unsigned long base, unsigned long size,
 		     unsigned int type, char increment);
 extern int mtrr_del (int reg, unsigned long base, unsigned long size);
diff -u --recursive --new-file v2.2.7/linux/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- v2.2.7/linux/include/asm-i386/processor.h	Tue Jan 19 11:32:53 1999
+++ linux/include/asm-i386/processor.h	Mon May 10 11:15:22 1999
@@ -35,6 +35,7 @@
 				    call  */
 	int	fdiv_bug;
 	int	f00f_bug;
+	int	coma_bug;
 	unsigned long loops_per_sec;
 	unsigned long *pgd_quick;
 	unsigned long *pte_quick;
@@ -119,12 +120,17 @@
 /*
  *      Cyrix CPU configuration register indexes
  */
+#define CX86_CCR0 0xc0
+#define CX86_CCR1 0xc1
 #define CX86_CCR2 0xc2
 #define CX86_CCR3 0xc3
 #define CX86_CCR4 0xe8
 #define CX86_CCR5 0xe9
+#define CX86_CCR6 0xea
 #define CX86_DIR0 0xfe
 #define CX86_DIR1 0xff
+#define CX86_ARR_BASE 0xc4
+#define CX86_RCR_BASE 0xdc
 
 /*
  *      Cyrix CPU indexed register access macros
@@ -148,6 +154,7 @@
 extern unsigned int machine_id;
 extern unsigned int machine_submodel_id;
 extern unsigned int BIOS_revision;
+extern unsigned int mca_pentium_flag;
 
 /*
  * User space process size: 3GB (default).
diff -u --recursive --new-file v2.2.7/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- v2.2.7/linux/include/asm-i386/system.h	Mon Dec 28 15:00:53 1998
+++ linux/include/asm-i386/system.h	Mon May 10 11:15:22 1999
@@ -9,30 +9,24 @@
 struct task_struct;	/* one of the stranger aspects of C forward declarations.. */
 extern void FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next));
 
-/*
- * We do most of the task switching in C, but we need
- * to do the EIP/ESP switch in assembly..
- */
-#define switch_to(prev,next) do {					\
-	unsigned long eax, edx, ecx;					\
-	asm volatile("pushl %%ebx\n\t"					\
-		     "pushl %%esi\n\t"					\
+#define switch_to(prev,next,last) do {					\
+	asm volatile("pushl %%esi\n\t"					\
 		     "pushl %%edi\n\t"					\
 		     "pushl %%ebp\n\t"					\
 		     "movl %%esp,%0\n\t"	/* save ESP */		\
-		     "movl %5,%%esp\n\t"	/* restore ESP */	\
+		     "movl %3,%%esp\n\t"	/* restore ESP */	\
 		     "movl $1f,%1\n\t"		/* save EIP */		\
-		     "pushl %6\n\t"		/* restore EIP */	\
+		     "pushl %4\n\t"		/* restore EIP */	\
 		     "jmp __switch_to\n"				\
 		     "1:\t"						\
 		     "popl %%ebp\n\t"					\
 		     "popl %%edi\n\t"					\
 		     "popl %%esi\n\t"					\
-		     "popl %%ebx"					\
 		     :"=m" (prev->tss.esp),"=m" (prev->tss.eip),	\
-		      "=a" (eax), "=d" (edx), "=c" (ecx)		\
+		      "=b" (last)					\
 		     :"m" (next->tss.esp),"m" (next->tss.eip),		\
-		      "a" (prev), "d" (next)); 				\
+		      "a" (prev), "d" (next),				\
+		      "b" (prev));					\
 } while (0)
 
 #define _set_base(addr,base) do { unsigned long __pr; \
diff -u --recursive --new-file v2.2.7/linux/include/asm-i386/timex.h linux/include/asm-i386/timex.h
--- v2.2.7/linux/include/asm-i386/timex.h	Mon Mar 29 11:09:12 1999
+++ linux/include/asm-i386/timex.h	Mon May 10 11:15:22 1999
@@ -7,6 +7,7 @@
 #define _ASMi386_TIMEX_H
 
 #include <linux/config.h>
+#include <asm/msr.h>
 
 #define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
 #define CLOCK_TICK_FACTOR	20	/* Factor of both 1000000 and CLOCK_TICK_RATE */
@@ -39,7 +40,7 @@
 #else
 	unsigned long eax, edx;
 
-	__asm__ __volatile__("rdtsc":"=a" (eax), "=d" (edx));
+	rdtsc(eax,edx);
 	return eax;
 #endif
 }
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/adb.h linux/include/asm-ppc/adb.h
--- v2.2.7/linux/include/asm-ppc/adb.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/adb.h	Thu Apr 29 12:39:01 1999
@@ -21,6 +21,16 @@
 #define ADB_RET_OK	0
 #define ADB_RET_TIMEOUT	3
 
+/* The kind of ADB request. The controller may emulate some
+   of all of those CUDA/PMU packet kinds */
+#define ADB_PACKET	0
+#define CUDA_PACKET	1
+#define ERROR_PACKET	2
+#define TIMER_PACKET	3
+#define POWER_PACKET	4
+#define MACIIC_PACKET	5
+#define PMU_PACKET	6
+
 #ifdef __KERNEL__
 
 struct adb_request {
@@ -41,19 +51,37 @@
     unsigned char id[16];
 };
 
-extern enum adb_hw {
-	ADB_NONE, ADB_VIACUDA, ADB_VIAPMU, ADB_MACIO
-} adb_hardware;
-
-extern int (*adb_send_request)(struct adb_request *req, int sync);
-extern int (*adb_autopoll)(int devs);
-extern int (*adb_reset_bus)(void);
+/* Messages sent thru the client_list notifier. You should NOT stop
+   the operation, at least not with this version */
+enum adb_message {
+    ADB_MSG_POWERDOWN,	/* Currently called before sleep only */
+    ADB_MSG_PRE_RESET,	/* Called before resetting the bus */
+    ADB_MSG_POST_RESET	/* Called after resetting the bus (re-do init & register) */
+};
+extern struct notifier_block *adb_client_list;
+
+/* Kind of ADB controller */
+enum adb_hw {
+    ADB_NONE, ADB_VIACUDA, ADB_VIAPMU, ADB_MACIO, ADB_UNKNOWN
+};
+
+/* Definition of a controller */
+extern struct adb_controller {
+    enum adb_hw		kind;
+	
+    int		(*send_request)(struct adb_request *req, int sync);
+    int		(*autopoll)(int devs);
+    int		(*reset_bus)(void);
+    void	(*poll)(void);
+} *adb_controller;
+extern enum adb_hw adb_hardware;
 
 /* Values for adb_request flags */
 #define ADBREQ_REPLY	1	/* expect reply */
 #define ADBREQ_SYNC	2	/* poll until done */
 
 void adb_init(void);
+
 int adb_request(struct adb_request *req, void (*done)(struct adb_request *),
 		int flags, int nbytes, ...);
 int adb_register(int default_id,int handler_id,struct adb_ids *ids,
@@ -62,6 +90,10 @@
 
 int adb_try_handler_change(int address, int new_id);
 int adb_get_infos(int address, int *original_address, int *handler_id);
+
+int adb_reset_bus(void);
+
+void adb_poll(void);
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/cuda.h linux/include/asm-ppc/cuda.h
--- v2.2.7/linux/include/asm-ppc/cuda.h	Fri May  8 23:14:56 1998
+++ linux/include/asm-ppc/cuda.h	Thu Apr 29 12:39:01 1999
@@ -5,15 +5,6 @@
  * 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
-#define PMU_PACKET	6
-
 /* CUDA commands (2nd byte) */
 #define CUDA_WARM_START		0
 #define CUDA_AUTOPOLL		1
@@ -41,7 +32,7 @@
 void via_cuda_init(void);
 int cuda_request(struct adb_request *req,
 		 void (*done)(struct adb_request *), int nbytes, ...);
-int cuda_send_request(struct adb_request *req);
 void cuda_poll(void);
+int cuda_present(void);
 
 #endif	/* __KERNEL */
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/dma.h linux/include/asm-ppc/dma.h
--- v2.2.7/linux/include/asm-ppc/dma.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/dma.h	Thu Apr 29 12:39:01 1999
@@ -35,36 +35,9 @@
 /* Doesn't really apply... */
 #define MAX_DMA_ADDRESS      0xFFFFFFFF
 
-#if defined(CONFIG_MACH_SPECIFIC)
-
-#if defined(CONFIG_PREP)
-#define DMA_MODE_READ 0x44
-#define DMA_MODE_WRITE 0x48
-#define ISA_DMA_THRESHOLD 0x00ffffff
-#endif /* CONFIG_PREP */
-
-#if defined(CONFIG_CHRP)
-#define DMA_MODE_READ 0x44
-#define DMA_MODE_WRITE 0x48
-#define ISA_DMA_THRESHOLD ~0L
-#endif /* CONFIG_CHRP */
-
-#ifdef CONFIG_PMAC
-#define DMA_MODE_READ 1
-#define DMA_MODE_WRITE 2
-#define ISA_DMA_THRESHOLD ~0L
-#endif /* CONFIG_PMAC */
-
-#ifdef CONFIG_APUS
-/* This is bogus and should go away. */
-#define ISA_DMA_THRESHOLD (0x00ffffff)
-#endif
-
-#else
 /* in arch/ppc/kernel/setup.c -- Cort */
 extern unsigned long DMA_MODE_WRITE, DMA_MODE_READ;
 extern unsigned long ISA_DMA_THRESHOLD;
-#endif
 
 
 #ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
@@ -204,7 +177,7 @@
 #define DMA2_EXT_REG               0x4D6
 
 #define DMA_MODE_CASCADE 0xC0   /* pass thru DREQ->HRQ, DACK<-HLDA only */
-#define DMA_AUTOINIT	0x10
+#define DMA_AUTOINIT   	 0x10
 
 extern spinlock_t  dma_spin_lock;
 
@@ -427,9 +400,8 @@
 extern void free_dma(unsigned int dmanr);	/* release it again */
 
 #ifdef CONFIG_PCI_QUIRKS
-extern int isa_dma_bridge_buggy;
-#else
-#define isa_dma_bridge_buggy    (0)
+extern int isa_dma_bridge_buggy;                                        
+#else                                                         
+#define isa_dma_bridge_buggy   (0)
 #endif
-
 #endif /* _ASM_DMA_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/hardirq.h linux/include/asm-ppc/hardirq.h
--- v2.2.7/linux/include/asm-ppc/hardirq.h	Mon Oct  5 13:13:43 1998
+++ linux/include/asm-ppc/hardirq.h	Thu Apr 29 12:39:01 1999
@@ -1,22 +1,22 @@
 #ifndef __ASM_HARDIRQ_H
 #define __ASM_HARDIRQ_H
 
-extern unsigned int local_irq_count[NR_CPUS];
+extern unsigned int ppc_local_irq_count[NR_CPUS];
 
 /*
  * Are we in an interrupt context? Either doing bottom half
  * or hardware interrupt processing?
  */
 #define in_interrupt() ({ int __cpu = smp_processor_id(); \
-	(local_irq_count[__cpu] + local_bh_count[__cpu] != 0); })
+	(ppc_local_irq_count[__cpu] + ppc_local_bh_count[__cpu] != 0); })
 
 #ifndef __SMP__
 
-#define hardirq_trylock(cpu)	(local_irq_count[cpu] == 0)
+#define hardirq_trylock(cpu)	(ppc_local_irq_count[cpu] == 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)	(ppc_local_irq_count[cpu]++)
+#define hardirq_exit(cpu)	(ppc_local_irq_count[cpu]--)
 
 #define synchronize_irq()	do { } while (0)
 
@@ -39,14 +39,14 @@
 
 static inline void hardirq_enter(int cpu)
 {
-	++local_irq_count[cpu];
+	++ppc_local_irq_count[cpu];
 	atomic_inc(&global_irq_count);
 }
 
 static inline void hardirq_exit(int cpu)
 {
 	atomic_dec(&global_irq_count);
-	--local_irq_count[cpu];
+	--ppc_local_irq_count[cpu];
 }
 
 static inline int hardirq_trylock(int cpu)
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/ide.h linux/include/asm-ppc/ide.h
--- v2.2.7/linux/include/asm-ppc/ide.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/ide.h	Thu May  6 23:14:37 1999
@@ -11,17 +11,8 @@
 #ifndef __ASMPPC_IDE_H
 #define __ASMPPC_IDE_H
 
-#include <linux/config.h>
-/*
- * On APUS, nearly everything comes from the m68k file
- * -- Cort
- */
-#ifdef CONFIG_APUS
-#include <linux/hdreg.h>
-#define ide_init_hwif_ports m68k_ide_init_hwif_ports 
-#include <asm-m68k/ide.h>
-#undef ide_init_hwif_ports
-#endif /* CONFIG_APUS */
+#include <linux/sched.h>
+#include <asm/processor.h>
 
 #ifndef MAX_HWIFS
 #define MAX_HWIFS	4
@@ -29,6 +20,12 @@
 
 typedef unsigned int ide_ioreg_t;
 
+#ifdef __KERNEL__
+
+#include <linux/hdreg.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+
 extern int pmac_ide_ports_known;
 extern ide_ioreg_t pmac_ide_regbase[MAX_HWIFS];
 extern int pmac_ide_irq[MAX_HWIFS];
@@ -40,43 +37,42 @@
 extern unsigned int chrp_ide_irq;
 extern void chrp_ide_probe(void);
 
+struct ide_machdep_calls {
+        void        (*insw)(ide_ioreg_t port, void *buf, int ns);
+        void        (*outsw)(ide_ioreg_t port, void *buf, int ns);
+        int         (*default_irq)(ide_ioreg_t base);
+        ide_ioreg_t (*default_io_base)(int index);
+        int         (*check_region)(ide_ioreg_t from, unsigned int extent);
+        void        (*request_region)(ide_ioreg_t from,
+                                      unsigned int extent,
+                                      const char *name);
+        void        (*release_region)(ide_ioreg_t from,
+                                      unsigned int extent);
+        void        (*fix_driveid)(struct hd_driveid *id);
+        void        (*ide_init_hwif)(ide_ioreg_t *p,
+                                     ide_ioreg_t base,
+                                     int *irq); 
+
+        int io_base;
+};
+
+extern struct ide_machdep_calls ppc_ide_md;
+
 void ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
-void prep_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
-void mbx_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
-void pmac_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
-void chrp_ide_init_hwif_ports(ide_ioreg_t *p, ide_ioreg_t base, int *irq);
 void ide_insw(ide_ioreg_t port, void *buf, int ns);
 void ide_outsw(ide_ioreg_t port, void *buf, int ns);
+void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
 
 #undef insw
 #define insw(port, buf, ns) 	do {				\
-	if ( _machine & (_MACH_chrp|_MACH_mbx) )		\
-		 ide_insw((port)+_IO_BASE, (buf), (ns));  	\
-	else if ( _machine & (_MACH_Pmac|_MACH_apus) )		\
-		 ide_insw((port), (buf), (ns));  		\
-	else							\
-		/* this must be the same as insw in io.h!! */	\
-		_insw((unsigned short *)((port)+_IO_BASE), (buf), (ns)); \
+	ppc_ide_md.insw((port), (buf), (ns));			\
 } while (0)
      
 #undef outsw
 #define outsw(port, buf, ns) 	do {				\
-	if ( _machine & (_MACH_chrp|_MACH_mbx) ) 		\
-		ide_outsw((port)+_IO_BASE, (buf), (ns)); 	\
-	else if ( _machine & (_MACH_Pmac|_MACH_apus) )		\
-		ide_outsw((port), (buf), (ns)); 		\
-	else							\
-		/* this must be the same as outsw in io.h!! */	\
-		_outsw((unsigned short *)((port)+_IO_BASE), (buf), (ns)); \
+	ppc_ide_md.outsw((port), (buf), (ns));			\
 } while (0)
 
-#ifndef CONFIG_APUS
-#ifdef __KERNEL__
-
-#include <linux/hdreg.h>
-#include <linux/ioport.h>
-#include <asm/io.h>
-
 #undef	SUPPORT_SLOW_DATA_PORTS
 #define	SUPPORT_SLOW_DATA_PORTS	0
 #undef	SUPPORT_VLB_SYNC
@@ -86,192 +82,41 @@
 
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
-	if ( _machine == _MACH_Pmac )
-		return 0;
-	else if ( _machine == _MACH_mbx )
-		/* IRQ 14 when in legacy mode on MBX */
-		return 14;
-        else if ( _machine == _MACH_chrp) {
-                if (chrp_ide_ports_known == 0) 
-			chrp_ide_probe();
-                return chrp_ide_irq;
-        }
-	switch (base) {
-		case 0x1f0: return 13;
-		case 0x170: return 13;
-		case 0x1e8: return 11;
-		case 0x168: return 10;
-		default:
-			return 0;
-	}
+	return ppc_ide_md.default_irq(base);
 }
 
 static __inline__ ide_ioreg_t ide_default_io_base(int index)
 {
-#if defined(CONFIG_BLK_DEV_IDE_PMAC)
-        if (_machine == _MACH_Pmac) {
-		return pmac_ide_regbase[index];
-	}
-#endif	
-	if (_machine == _MACH_mbx) return index;
-        if ( _machine == _MACH_chrp ) {
-                if (chrp_ide_ports_known == 0)
-                        chrp_ide_probe();
-                return chrp_ide_regbase[index];
-        }
-	switch (index) {
-		case 0:	return 0x1f0;
-		case 1:	return 0x170;
-		case 2: return 0x1e8;
-		case 3: return 0x168;
-		default:
-			return 0;
-	}
+	return ppc_ide_md.default_io_base(index);
 }
 
 static __inline__ int ide_check_region (ide_ioreg_t from, unsigned int extent)
 {
-	if ( (_machine == _MACH_Pmac) || (_machine == _MACH_mbx))
-		return 0;
-	return check_region(from, extent);
+	return ppc_ide_md.check_region(from, extent);
 }
 
 static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
 {
-	if ( (_machine == _MACH_Pmac) || (_machine == _MACH_mbx) )
-		return;
-	request_region(from, extent, name);
+	ppc_ide_md.request_region(from, extent, name);
 }
 
 static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
 {
-	if ( (_machine == _MACH_Pmac) || (_machine == _MACH_mbx) )
-		return;
-	release_region(from, extent);
+	ppc_ide_md.release_region(from, extent);
 }
 
-/* Convert the shorts/longs in hd_driveid from little to big endian;
-   chars are endian independent, of course, but strings need to be flipped.
-   (Despite what it says in drivers/block/ide.h, they come up as little endian...)
-   Changes to linux/hdreg.h may require changes here. */
 static __inline__ void ide_fix_driveid (struct hd_driveid *id) {
-  if ( _machine & (_MACH_chrp|_MACH_mbx|_MACH_Pmac) ) { 	\
-		int i;
-		unsigned short *stringcast;
-		id->config         = __le16_to_cpu(id->config);
-		id->cyls           = __le16_to_cpu(id->cyls);
-		id->reserved2      = __le16_to_cpu(id->reserved2);
-		id->heads          = __le16_to_cpu(id->heads);
-		id->track_bytes    = __le16_to_cpu(id->track_bytes);
-		id->sector_bytes   = __le16_to_cpu(id->sector_bytes);
-		id->sectors        = __le16_to_cpu(id->sectors);
-		id->vendor0        = __le16_to_cpu(id->vendor0);
-		id->vendor1        = __le16_to_cpu(id->vendor1);
-		id->vendor2        = __le16_to_cpu(id->vendor2);
-		stringcast = (unsigned short *)&id->serial_no[0];
-		for (i=0; i<(20/2); i++)
-			stringcast[i] = __le16_to_cpu(stringcast[i]);
-		id->buf_type       = __le16_to_cpu(id->buf_type);
-		id->buf_size       = __le16_to_cpu(id->buf_size);
-		id->ecc_bytes      = __le16_to_cpu(id->ecc_bytes);
-		stringcast = (unsigned short *)&id->fw_rev[0];
-		for (i=0; i<(8/2); i++)
-			stringcast[i] = __le16_to_cpu(stringcast[i]);
-		stringcast = (unsigned short *)&id->model[0];
-		for (i=0; i<(40/2); i++)
-			stringcast[i] = __le16_to_cpu(stringcast[i]);
-		id->dword_io       = __le16_to_cpu(id->dword_io);
-		id->reserved50     = __le16_to_cpu(id->reserved50);
-		id->field_valid    = __le16_to_cpu(id->field_valid);
-		id->cur_cyls       = __le16_to_cpu(id->cur_cyls);
-		id->cur_heads      = __le16_to_cpu(id->cur_heads);
-		id->cur_sectors    = __le16_to_cpu(id->cur_sectors);
-		id->cur_capacity0  = __le16_to_cpu(id->cur_capacity0);
-		id->cur_capacity1  = __le16_to_cpu(id->cur_capacity1);
-		id->lba_capacity   = __le32_to_cpu(id->lba_capacity);
-		id->dma_1word      = __le16_to_cpu(id->dma_1word);
-		id->dma_mword      = __le16_to_cpu(id->dma_mword);
-		id->eide_pio_modes = __le16_to_cpu(id->eide_pio_modes);
-		id->eide_dma_min   = __le16_to_cpu(id->eide_dma_min);
-		id->eide_dma_time  = __le16_to_cpu(id->eide_dma_time);
-		id->eide_pio       = __le16_to_cpu(id->eide_pio);
-		id->eide_pio_iordy = __le16_to_cpu(id->eide_pio_iordy);
-		id->word69         = __le16_to_cpu(id->word69);
-		id->word70         = __le16_to_cpu(id->word70);
-		id->word71         = __le16_to_cpu(id->word71);
-		id->word72         = __le16_to_cpu(id->word72);
-		id->word73         = __le16_to_cpu(id->word73);
-		id->word74         = __le16_to_cpu(id->word74);
-		id->word75         = __le16_to_cpu(id->word75);
-		id->word76         = __le16_to_cpu(id->word76);
-		id->word77         = __le16_to_cpu(id->word77);
-		id->word78         = __le16_to_cpu(id->word78);
-		id->word79         = __le16_to_cpu(id->word79);
-		id->word80         = __le16_to_cpu(id->word80);
-		id->word81         = __le16_to_cpu(id->word81);
-		id->command_sets   = __le16_to_cpu(id->command_sets);
-		id->word83         = __le16_to_cpu(id->word83);
-		id->word84         = __le16_to_cpu(id->word84);
-		id->word85         = __le16_to_cpu(id->word85);
-		id->word86         = __le16_to_cpu(id->word86);
-		id->word87         = __le16_to_cpu(id->word87);
-		id->dma_ultra      = __le16_to_cpu(id->dma_ultra);
-		id->word89         = __le16_to_cpu(id->word89);
-		id->word90         = __le16_to_cpu(id->word90);
-		id->word91         = __le16_to_cpu(id->word91);
-		id->word92         = __le16_to_cpu(id->word92);
-		id->word93         = __le16_to_cpu(id->word93);
-		id->word94         = __le16_to_cpu(id->word94);
-		id->word95         = __le16_to_cpu(id->word95);
-		id->word96         = __le16_to_cpu(id->word96);
-		id->word97         = __le16_to_cpu(id->word97);
-		id->word98         = __le16_to_cpu(id->word98);
-		id->word99         = __le16_to_cpu(id->word99);
-		id->word100        = __le16_to_cpu(id->word100);
-		id->word101        = __le16_to_cpu(id->word101);
-		id->word102        = __le16_to_cpu(id->word102);
-		id->word103        = __le16_to_cpu(id->word103);
-		id->word104        = __le16_to_cpu(id->word104);
-		id->word105        = __le16_to_cpu(id->word105);
-		id->word106        = __le16_to_cpu(id->word106);
-		id->word107        = __le16_to_cpu(id->word107);
-		id->word108        = __le16_to_cpu(id->word108);
-		id->word109        = __le16_to_cpu(id->word109);
-		id->word110        = __le16_to_cpu(id->word110);
-		id->word111        = __le16_to_cpu(id->word111);
-		id->word112        = __le16_to_cpu(id->word112);
-		id->word113        = __le16_to_cpu(id->word113);
-		id->word114        = __le16_to_cpu(id->word114);
-		id->word115        = __le16_to_cpu(id->word115);
-		id->word116        = __le16_to_cpu(id->word116);
-		id->word117        = __le16_to_cpu(id->word117);
-		id->word118        = __le16_to_cpu(id->word118);
-		id->word119        = __le16_to_cpu(id->word119);
-		id->word120        = __le16_to_cpu(id->word120);
-		id->word121        = __le16_to_cpu(id->word121);
-		id->word122        = __le16_to_cpu(id->word122);
-		id->word123        = __le16_to_cpu(id->word123);
-		id->word124        = __le16_to_cpu(id->word124);
-		id->word125        = __le16_to_cpu(id->word125);
-		id->word126        = __le16_to_cpu(id->word126);
-		id->word127        = __le16_to_cpu(id->word127);
-		id->security       = __le16_to_cpu(id->security);
-		for (i=0; i<127; i++)
-			id->reserved[i] = __le16_to_cpu(id->reserved[i]);
-	}
+        ppc_ide_md.fix_driveid(id);
 }
 
 #undef inb
-#define inb(port)	\
-	in_8((unsigned char *)((port) + \
-			       ((_machine==_MACH_Pmac)? 0: _IO_BASE) ) )
+#define inb(port)	in_8((unsigned char *)((port) + ppc_ide_md.io_base))
 #undef inb_p
 #define inb_p(port)	inb(port)
 
 #undef outb
 #define outb(val, port)	\
-	out_8((unsigned char *)((port) + \
-				((_machine==_MACH_Pmac)? 0: _IO_BASE) ), (val) )
+	out_8((unsigned char *)((port) + ppc_ide_md.io_base), (val) )
 #undef outb_p
 #define outb_p(val, port)	outb(val, port)
 
@@ -305,6 +150,5 @@
 #define ide_get_lock(lock, hdlr, data)	do {} while (0)
 
 #endif /* __KERNEL__ */
-#endif /* CONFIG_APUS */
 
 #endif /* __ASMPPC_IDE_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/io.h linux/include/asm-ppc/io.h
--- v2.2.7/linux/include/asm-ppc/io.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/io.h	Thu Apr 29 12:39:01 1999
@@ -5,8 +5,6 @@
 #include <asm/page.h>
 #include <asm/byteorder.h>
 
-#define KERNELBASE	0xc0000000
-
 #define SIO_CONFIG_RA	0x398
 #define SIO_CONFIG_RD	0x399
 
@@ -18,7 +16,7 @@
 #define CHRP_ISA_MEM_BASE 	0xf7000000
 #define CHRP_PCI_DRAM_OFFSET 	0
 #define PREP_ISA_IO_BASE 	0x80000000
-#define PREP_ISA_MEM_BASE 	0xd0000000
+#define PREP_ISA_MEM_BASE 	0xc0000000
 #define PREP_PCI_DRAM_OFFSET 	0x80000000
 
 #ifdef CONFIG_MBX
@@ -49,7 +47,7 @@
 #define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
 #else
 #define readw(addr) in_le16((volatile unsigned short *)(addr))
-#define readl(addr) in_le32((volatile unsigned *)addr)
+#define readl(addr) in_le32((volatile unsigned *)(addr))
 #define writew(b,addr) out_le16((volatile unsigned short *)(addr),(b))
 #define writel(b,addr) out_le32((volatile unsigned *)(addr),(b))
 #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/irq.h linux/include/asm-ppc/irq.h
--- v2.2.7/linux/include/asm-ppc/irq.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/irq.h	Thu Apr 29 12:39:01 1999
@@ -3,7 +3,7 @@
 #ifndef _ASM_IRQ_H
 #define _ASM_IRQ_H
 
-#include <asm/processor.h>		/* for is_prep() */
+#include <asm/machdep.h>		/* ppc_md */
 
 extern void disable_irq(unsigned int);
 extern void enable_irq(unsigned int);
@@ -42,7 +42,14 @@
  */
 static __inline__ int irq_cannonicalize(int irq)
 {
-	return (((is_prep || is_chrp) && irq == 2) ? 9 : irq);
+	if (ppc_md.irq_cannonicalize)
+	{
+		return ppc_md.irq_cannonicalize(irq);
+	}
+	else
+	{
+		return irq;
+	}
 }
 #endif
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/keyboard.h linux/include/asm-ppc/keyboard.h
--- v2.2.7/linux/include/asm-ppc/keyboard.h	Wed Apr 28 11:37:31 1999
+++ linux/include/asm-ppc/keyboard.h	Thu Apr 29 12:39:01 1999
@@ -17,7 +17,7 @@
 
 #include <linux/config.h>
 #include <asm/adb.h>
-
+#include <asm/machdep.h>
 #ifdef CONFIG_APUS
 #include <asm-m68k/keyboard.h>
 #else
@@ -26,132 +26,44 @@
 #define DISABLE_KBD_DURING_INTERRUPTS	0
 #define INIT_KBD
 
-extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int mackbd_getkeycode(unsigned int scancode);
-extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern int mackbd_unexpected_up(unsigned char keycode);
-extern void mackbd_leds(unsigned char leds);
-extern void mackbd_init_hw(void);
-
-extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char pckbd_unexpected_up(unsigned char keycode);
-extern void pckbd_leds(unsigned char leds);
-extern void pckbd_init_hw(void);
-
 static inline int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
 {
-	if ( is_prep || (_machine == _MACH_mbx) )
-		return pckbd_setkeycode(scancode,keycode);
-	else if ( is_chrp )
-#ifndef CONFIG_MAC_KEYBOARD
-		return pckbd_setkeycode(scancode,keycode);
-#else
-		/* I'm not actually sure if it's legal to have a CHRP machine
-		 * without an ADB controller. In any case, this should really
-		 * be changed to be a test to see if an ADB _keyboard_ exists
-		 * (not just a controller), but that's another story for
-		 * another night.
-		 */
-		if ( adb_hardware == ADB_NONE )
-			return pckbd_setkeycode(scancode,keycode);
-		else
-			return mackbd_setkeycode(scancode,keycode);
-#endif
-	else
-		return mackbd_setkeycode(scancode,keycode);
+	return ppc_md.kbd_setkeycode(scancode, keycode);
 }
-
-static inline int kbd_getkeycode(unsigned int x)
+  
+static inline int kbd_getkeycode(unsigned int scancode)
 {
-	if ( is_prep || (_machine == _MACH_mbx) )
-		return pckbd_getkeycode(x);
-	else if ( is_chrp )
-#ifndef CONFIG_MAC_KEYBOARD
-		return pckbd_getkeycode(x);
-#else
-		if ( adb_hardware == ADB_NONE )
-			return pckbd_getkeycode(x);
-		else
-			return mackbd_getkeycode(x);
-#endif
-	else
-		return mackbd_getkeycode(x);
+	return ppc_md.kbd_getkeycode(scancode);
 }
-
+  
 static inline int kbd_translate(unsigned char keycode, unsigned char *keycodep,
-		     char raw_mode)
+				char raw_mode)
 {
-	if ( is_prep || (_machine == _MACH_mbx) )
-		return pckbd_translate(keycode,keycodep,raw_mode);
-	else if ( is_chrp )
-#ifndef CONFIG_MAC_KEYBOARD
-		return pckbd_translate(keycode,keycodep,raw_mode);
-#else
-		if ( adb_hardware == ADB_NONE )
-			return pckbd_translate(keycode,keycodep,raw_mode);
-		else
-			return mackbd_translate(keycode,keycodep,raw_mode);
-#endif
-	else
-		return mackbd_translate(keycode,keycodep,raw_mode);
-	
+	return ppc_md.kbd_translate(keycode, keycodep, raw_mode);
 }
-
+  
 static inline int kbd_unexpected_up(unsigned char keycode)
 {
-	if ( is_prep || (_machine == _MACH_mbx) )
-		return pckbd_unexpected_up(keycode);
-	else if ( is_chrp )
-#ifndef CONFIG_MAC_KEYBOARD
-		return pckbd_unexpected_up(keycode);
-#else
-		if ( adb_hardware == ADB_NONE )
-			return pckbd_unexpected_up(keycode);
-		else
-			return mackbd_unexpected_up(keycode);
-#endif
-	else
-		return mackbd_unexpected_up(keycode);
-	
+	return ppc_md.kbd_unexpected_up(keycode);
 }
-
+  
 static inline void kbd_leds(unsigned char leds)
 {
-	if ( is_prep || (_machine == _MACH_mbx) )
-		pckbd_leds(leds);
-	else if ( is_chrp )
-#ifndef CONFIG_MAC_KEYBOARD
-		pckbd_leds(leds);
-#else
-		if ( adb_hardware == ADB_NONE )
-			pckbd_leds(leds);
-		else
-			mackbd_leds(leds);
-#endif
-	else
-		mackbd_leds(leds);
+	ppc_md.kbd_leds(leds);
 }
-
+  
 static inline void kbd_init_hw(void)
 {
-	if ( is_prep || (_machine == _MACH_mbx) )
-		pckbd_init_hw();
-	else if ( is_chrp )
-#ifndef CONFIG_MAC_KEYBOARD
-		pckbd_init_hw();
+	ppc_md.kbd_init_hw();
+}
+
+#define kbd_sysrq_xlate	(ppc_md.kbd_sysrq_xlate)
+
+#ifdef CONFIG_MAC_KEYBOARD
+# define SYSRQ_KEY 0x69
 #else
-		if ( adb_hardware == ADB_NONE )
-			pckbd_init_hw();
-		else
-			mackbd_init_hw();
+# define SYSRQ_KEY 0x54
 #endif
-	else
-		mackbd_init_hw();
-}
 
 #endif /* CONFIG_APUS */
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/machdep.h linux/include/asm-ppc/machdep.h
--- v2.2.7/linux/include/asm-ppc/machdep.h	Thu Aug  6 14:06:33 1998
+++ linux/include/asm-ppc/machdep.h	Thu Apr 29 12:39:01 1999
@@ -1,3 +1,4 @@
+
 #ifndef _PPC_MACHDEP_H
 #define _PPC_MACHDEP_H
 
@@ -7,6 +8,69 @@
 #include <asm-m68k/machdep.h>
 #endif
 
-#endif /* _PPC_MACHDEP_H */
+struct pt_regs;
+
+struct machdep_calls {
+	void		(*setup_arch)(unsigned long * memory_start_p,
+				unsigned long * memory_end_p);
+	/* Optional, may be NULL. */
+	int		(*setup_residual)(char *buffer);
+	/* Optional, may be NULL. */
+	int		(*get_cpuinfo)(char *buffer);
+	/* Optional, may be NULL. */
+	unsigned int	(*irq_cannonicalize)(unsigned int irq);
+	void		(*init_IRQ)(void);
+	void		(*do_IRQ)(struct pt_regs *regs, int cpu, int isfake);
+
+	/* A general init function, called by ppc_init in init/main.c.
+	   May be NULL. */
+	void		(*init)(void);
+
+	void		(*restart)(char *cmd);
+	void		(*power_off)(void);
+	void		(*halt)(void);
+
+	void		(*time_init)(void); /* Optional, may be NULL */
+	int		(*set_rtc_time)(unsigned long nowtime);
+	unsigned long	(*get_rtc_time)(void);
+	void		(*calibrate_decr)(void);
 
+	unsigned char 	(*nvram_read_val)(int addr);
+	void		(*nvram_write_val)(int addr, unsigned char val);
 
+/* Tons of keyboard stuff. */
+	int		(*kbd_setkeycode)(unsigned int scancode,
+				unsigned int keycode);
+	int		(*kbd_getkeycode)(unsigned int scancode);
+	int		(*kbd_translate)(unsigned char scancode,
+				unsigned char *keycode,
+				char raw_mode);
+	char		(*kbd_unexpected_up)(unsigned char keycode);
+	void		(*kbd_leds)(unsigned char leds);
+	void		(*kbd_init_hw)(void);
+#ifdef CONFIG_MAGIC_SYSRQ
+	unsigned char 	*kbd_sysrq_xlate;
+#endif
+
+	/* PCI interfaces */
+	int (*pcibios_read_config_byte)(unsigned char bus,
+		unsigned char dev_fn, unsigned char offset, unsigned char *val);
+	int (*pcibios_read_config_word)(unsigned char bus,
+		unsigned char dev_fn, unsigned char offset, unsigned short *val);
+	int (*pcibios_read_config_dword)(unsigned char bus,
+		unsigned char dev_fn, unsigned char offset, unsigned int *val);
+	int (*pcibios_write_config_byte)(unsigned char bus,
+		unsigned char dev_fn, unsigned char offset, unsigned char val);
+	int (*pcibios_write_config_word)(unsigned char bus, 
+		unsigned char dev_fn, unsigned char offset, unsigned short val);
+	int (*pcibios_write_config_dword)(unsigned char bus,
+		unsigned char dev_fn, unsigned char offset, unsigned int val);
+	void (*pcibios_fixup)(void);
+};
+
+extern struct machdep_calls ppc_md;
+extern char cmd_line[512];
+
+extern void setup_pci_ptrs(void);
+
+#endif /* _PPC_MACHDEP_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/mk48t59.h linux/include/asm-ppc/mk48t59.h
--- v2.2.7/linux/include/asm-ppc/mk48t59.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/mk48t59.h	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,35 @@
+/*
+ * Registers for the mk48t59 real-time-clock
+ */
+
+#ifndef _PPC_MK48T59_H
+#define _PPC_MK48T59_H
+
+/* RTC Offsets */
+
+#define MK48T59_RTC_SECONDS		0x1FF9
+#define MK48T59_RTC_MINUTES		0x1FFA
+#define MK48T59_RTC_HOURS		0x1FFB
+#define MK48T59_RTC_DAY_OF_WEEK		0x1FFC
+#define MK48T59_RTC_DAY_OF_MONTH	0x1FFD
+#define MK48T59_RTC_MONTH		0x1FFE
+#define MK48T59_RTC_YEAR		0x1FFF
+
+#define MK48T59_RTC_CONTROLA		0x1FF8
+#define MK48T59_RTC_CA_WRITE		0x80
+#define MK48T59_RTC_CA_READ		0x40
+#define MK48T59_RTC_CA_CALIB_SIGN	0x20
+#define MK48T59_RTC_CA_CALIB_MASK	0x1f
+
+#define MK48T59_RTC_CONTROLB		0x1FF9
+#define MK48T59_RTC_CB_STOP		0x80
+
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
+#endif
+
+#endif /* _PPC_MK48T59_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/page.h linux/include/asm-ppc/page.h
--- v2.2.7/linux/include/asm-ppc/page.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/page.h	Thu Apr 29 12:39:01 1999
@@ -9,7 +9,7 @@
 #define PAGE_MASK	(~(PAGE_SIZE-1))
 
 #define PAGE_OFFSET	0xc0000000
-
+#define KERNELBASE	PAGE_OFFSET
 
 #ifndef __ASSEMBLY__
 #ifdef __KERNEL__
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/pgtable.h linux/include/asm-ppc/pgtable.h
--- v2.2.7/linux/include/asm-ppc/pgtable.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/pgtable.h	Thu Apr 29 12:39:01 1999
@@ -37,6 +37,7 @@
 
 extern unsigned long va_to_phys(unsigned long address);
 extern pte_t *va_to_pte(struct task_struct *tsk, unsigned long address);
+extern unsigned long ioremap_bot, ioremap_base;
 #endif /* __ASSEMBLY__ */
 /*
  * The PowerPC MMU uses a hash table containing PTEs, together with
@@ -95,16 +96,19 @@
  * The vmalloc() routines leaves a hole of 4kB between each vmalloced
  * area for the same reason. ;)
  *
- * The vmalloc_offset MUST be larger than the gap between the bat2 mapping
- * and the size of physical ram.  Since the bat2 mapping can be larger than
- * the amount of ram we have vmalloc_offset must ensure that we don't try
- * to allocate areas that don't exist! This value of 64M will only cause
- * problems when we have >128M -- Cort
+ * We no longer map larger than phys RAM with the BATs so we don't have
+ * to worry about the VMALLOC_OFFSET causing problems.  We do have to worry
+ * about clashes between our early calls to ioremap() that start growing down
+ * from ioremap_base being run into the VM area allocations (growing upwards
+ * from VMALLOC_START).  For this reason we have ioremap_bot to check when
+ * we actually run into our mappings setup in the early boot with the VM
+ * system.  This really does become a problem for machines with good amounts
+ * of RAM.  -- Cort
  */
-#define VMALLOC_OFFSET	(0x4000000) /* 64M */
+#define VMALLOC_OFFSET (0x4000000) /* 64M */
 #define VMALLOC_START ((((long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)))
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
-#define VMALLOC_END	0xf0000000
+#define VMALLOC_END	ioremap_bot
 
 /*
  * Bits in a linux-style PTE.  These match the bits in the
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/pmu.h linux/include/asm-ppc/pmu.h
--- v2.2.7/linux/include/asm-ppc/pmu.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/pmu.h	Thu Apr 29 12:39:01 1999
@@ -64,11 +64,12 @@
 #define PMU_IOC_GET_MODEL	_IOR('B', 3, sizeof(__u32*))
 
 #ifdef __KERNEL__
+
 void find_via_pmu(void);
 void via_pmu_init(void);
+
 int pmu_request(struct adb_request *req,
 		void (*done)(struct adb_request *), int nbytes, ...);
-int pmu_send_request(struct adb_request *req);
 void pmu_poll(void);
 
 void pmu_enable_backlight(int on);
@@ -79,6 +80,7 @@
 void pmu_restart(void);
 void pmu_shutdown(void);
 
+int pmu_present(void);
 int pmu_get_model(void);
 
 /*
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/posix_types.h linux/include/asm-ppc/posix_types.h
--- v2.2.7/linux/include/asm-ppc/posix_types.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/posix_types.h	Thu Apr 29 12:39:01 1999
@@ -43,7 +43,8 @@
 
 #else /* __GNUC__ */
 
-#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ <= 2)
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) \
+    || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
 /* With GNU C, use inline functions instead so args are evaluated only once: */
 
 #undef __FD_SET
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/prep_nvram.h linux/include/asm-ppc/prep_nvram.h
--- v2.2.7/linux/include/asm-ppc/prep_nvram.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/prep_nvram.h	Thu Apr 29 12:39:01 1999
@@ -0,0 +1,146 @@
+/*
+ * PreP compliant NVRAM access
+ */
+
+/* Corey Minyard (minyard@acm.org) - Stolen from PReP book.   Per the
+   license I must say:
+     (C) Copyright (Corey Minyard), (1998).  All rights reserved
+ */
+
+/* Structure map for NVRAM on PowerPC Reference Platform */
+/* All fields are either character/byte strings which are valid either
+  endian or they are big-endian numbers.
+
+  There are a number of Date and Time fields which are in RTC format,
+  big-endian. These are stored in UT (GMT).
+
+  For enum's: if given in hex then they are bit significant, i.e. only
+  one bit is on for each enum.
+*/
+#ifndef _PPC_PREP_NVRAM_H
+#define _PPC_PREP_NVRAM_H
+
+#define NVSIZE 4096	/* size of NVRAM */
+#define OSAREASIZE 512	/* size of OSArea space */
+#define CONFSIZE 1024	/* guess at size of Configuration space */
+
+typedef struct _SECURITY {
+  unsigned long BootErrCnt;	    /* Count of boot password errors */
+  unsigned long ConfigErrCnt;	    /* Count of config password errors */
+  unsigned long BootErrorDT[2];	    /* Date&Time from RTC of last error in pw */
+  unsigned long ConfigErrorDT[2];   /* Date&Time from RTC of last error in pw */
+  unsigned long BootCorrectDT[2];   /* Date&Time from RTC of last correct pw */
+  unsigned long ConfigCorrectDT[2]; /* Date&Time from RTC of last correct pw */
+  unsigned long BootSetDT[2];	    /* Date&Time from RTC of last set of pw */
+  unsigned long ConfigSetDT[2];	    /* Date&Time from RTC of last set of pw */
+  unsigned char Serial[16];	    /* Box serial number */
+} SECURITY;
+
+typedef enum _OS_ID {
+  Unknown = 0,
+  Firmware = 1,
+  AIX = 2,
+  NT = 3,
+  MKOS2 = 4,
+  MKAIX = 5,
+  Taligent = 6,
+  Solaris = 7,
+  MK = 12
+} OS_ID;
+
+typedef struct _ERROR_LOG {
+  unsigned char ErrorLogEntry[40]; /* To be architected */
+} ERROR_LOG;
+
+typedef enum _BOOT_STATUS {
+  BootStarted = 0x01,
+  BootFinished = 0x02,
+  RestartStarted = 0x04,
+  RestartFinished = 0x08,
+  PowerFailStarted = 0x10,
+  PowerFailFinished = 0x20,
+  ProcessorReady = 0x40,
+  ProcessorRunning = 0x80,
+  ProcessorStart = 0x0100
+} BOOT_STATUS;
+
+typedef struct _RESTART_BLOCK {
+  unsigned short Version;
+  unsigned short Revision;
+  unsigned long ResumeReserve1[2];
+  volatile unsigned long BootStatus;
+  unsigned long CheckSum; /* Checksum of RESTART_BLOCK */
+  void * RestartAddress;
+  void * SaveAreaAddr;
+  unsigned long SaveAreaLength;
+} RESTART_BLOCK;
+
+typedef enum _OSAREA_USAGE {
+  Empty = 0,
+  Used = 1
+} OSAREA_USAGE;
+
+typedef enum _PM_MODE {
+  Suspend = 0x80, /* Part of state is in memory */
+  Normal = 0x00   /* No power management in effect */
+} PMMode;
+
+typedef struct _HEADER {
+  unsigned short Size;       /* NVRAM size in K(1024) */
+  unsigned char Version;     /* Structure map different */
+  unsigned char Revision;    /* Structure map the same -may
+                                be new values in old fields
+                                in other words old code still works */
+  unsigned short Crc1;       /* check sum from beginning of nvram to OSArea */
+  unsigned short Crc2;       /* check sum of config */
+  unsigned char LastOS;      /* OS_ID */
+  unsigned char Endian;      /* B if big endian, L if little endian */
+  unsigned char OSAreaUsage; /* OSAREA_USAGE */
+  unsigned char PMMode;      /* Shutdown mode */
+  RESTART_BLOCK RestartBlock;
+  SECURITY Security;
+  ERROR_LOG ErrorLog[2];
+
+  /* Global Environment information */
+  void * GEAddress;
+  unsigned long GELength;
+
+  /* Date&Time from RTC of last change to Global Environment */
+  unsigned long GELastWriteDT[2];
+
+  /* Configuration information */
+  void * ConfigAddress;
+  unsigned long ConfigLength;
+
+  /* Date&Time from RTC of last change to Configuration */
+  unsigned long ConfigLastWriteDT[2];
+  unsigned long ConfigCount; /* Count of entries in Configuration */
+
+  /* OS dependent temp area */
+  void * OSAreaAddress;
+  unsigned long OSAreaLength;
+
+  /* Date&Time from RTC of last change to OSAreaArea */
+  unsigned long OSAreaLastWriteDT[2];
+} HEADER;
+
+/* Here is the whole map of the NVRAM */
+typedef struct _NVRAM_MAP {
+  HEADER Header;
+  unsigned char GEArea[NVSIZE-CONFSIZE-OSAREASIZE-sizeof(HEADER)];
+  unsigned char OSArea[OSAREASIZE];
+  unsigned char ConfigArea[CONFSIZE];
+} NVRAM_MAP;
+
+/* Routines to manipulate the NVRAM */
+void init_prep_nvram(void);
+char *prep_nvram_get_var(const char *name);
+char *prep_nvram_first_var(void);
+char *prep_nvram_next_var(char *name);
+
+/* Routines to read and write directly to the NVRAM */
+unsigned char prep_nvram_read_val(int addr);
+void prep_nvram_write_val(int           addr,
+			  unsigned char val);
+
+#endif /* _PPC_PREP_NVRAM_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
--- v2.2.7/linux/include/asm-ppc/processor.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/processor.h	Thu Apr 29 12:39:01 1999
@@ -175,67 +175,13 @@
 #define SR15	15
 
 #ifndef __ASSEMBLY__
-/*
- * If we've configured for a specific machine set things
- * up so the compiler can optimize away the other parts.
- * -- Cort
- */
-#ifdef CONFIG_MACH_SPECIFIC
-#ifdef CONFIG_PREP
-#define _machine (_MACH_prep)
-#define is_prep (1)
-#define is_chrp (0)
-#define have_of (0)
-#endif /* CONFIG_PREP */
-
-#ifdef CONFIG_CHRP
-#define _machine (_MACH_chrp)
-#define is_prep (0)
-#define is_chrp (1)
-#define have_of (1)
-#endif /* CONFIG_CHRP */
-
-#ifdef CONFIG_PMAC
-#define _machine (_MACH_Pmac)
-#define is_prep (0)
-#define is_chrp (0)
-#define have_of (1)
-#endif /* CONFIG_PMAC */
-
-#ifdef CONFIG_MBX
-#define _machine (_MACH_mbx)
-#define is_prep (0)
-#define is_chrp (0)
-#define have_of (0)
-#endif /* CONFIG_MBX */
-
-#ifdef CONFIG_FADS
-#define _machine (_MACH_fads)
-#define is_prep (0)
-#define is_chrp (0)
-#define have_of (0)
-#endif /* CONFIG_FADS */
-
-#ifdef CONFIG_APUS
-#define _machine (_MACH_apus)
-#define is_prep (0)
-#define is_chrp (0)
-#define have_of (0)
-#endif /* CONFIG_APUS */
-
-#else /* CONFIG_MACH_SPECIFIC */
-
 extern int _machine;
 
-/* if we're a prep machine */
-#define is_prep (_machine == _MACH_prep)
-
-/* if we're a chrp machine */
-#define is_chrp (_machine == _MACH_chrp)
-
-/* if we have openfirmware */
-extern unsigned long have_of;
-#endif /* CONFIG_MACH_SPECIFIC */
+/* Temporary hacks until we can clean things up better - Corey */
+extern int have_of;
+extern int is_prep;
+extern int is_chrp;
+extern int is_powerplus;
 
 /* what kind of prep workstation we are */
 extern int _prep_type;
@@ -338,14 +284,10 @@
 #define init_task	(init_task_union.task)
 #define init_stack	(init_task_union.stack)
 
+/* In misc.c */
+void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
+
 #endif /* ndef ASSEMBLY*/
 
   
 #endif /* __ASM_PPC_PROCESSOR_H */
-
-
-
-
-
-
-
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/smp.h linux/include/asm-ppc/smp.h
--- v2.2.7/linux/include/asm-ppc/smp.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/smp.h	Thu Apr 29 12:39:07 1999
@@ -27,6 +27,7 @@
 
 extern void smp_message_pass(int target, int msg, unsigned long data, int wait);
 extern void smp_store_cpu_info(int id);
+extern void smp_message_recv(void);
 
 #define NO_PROC_ID		0xFF            /* No processor magic marker */
 #define PROC_CHANGE_PENALTY	20
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/softirq.h linux/include/asm-ppc/softirq.h
--- v2.2.7/linux/include/asm-ppc/softirq.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/softirq.h	Thu Apr 29 12:39:07 1999
@@ -4,7 +4,7 @@
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 
-extern unsigned int local_bh_count[NR_CPUS];
+extern unsigned int ppc_local_bh_count[NR_CPUS];
 
 #define get_active_bhs()	(bh_mask & bh_active)
 #define clear_active_bhs(x)	atomic_clear_mask((x),&bh_active)
@@ -29,6 +29,7 @@
 }
 
 #ifdef __SMP__
+
 /*
  * The locking mechanism for base handlers, to prevent re-entrancy,
  * is entirely private to an implementation, it should not be
@@ -55,7 +56,7 @@
 {
 	if (!test_and_set_bit(0,&global_bh_count)) {
 		if (atomic_read(&global_bh_lock) == 0) {
-			++local_bh_count[cpu];
+			++ppc_local_bh_count[cpu];
 			return 1;
 		}
 		clear_bit(0,&global_bh_count);
@@ -65,30 +66,30 @@
 
 static inline void softirq_endlock(int cpu)
 {
-	local_bh_count[cpu]--;
+	ppc_local_bh_count[cpu]--;
 	clear_bit(0,&global_bh_count);
 }
 
-#else /* __SMP__ */
+#else
 
 extern inline void start_bh_atomic(void)
 {
-	local_bh_count[smp_processor_id()]++;
+	ppc_local_bh_count[smp_processor_id()]++;
 	barrier();
 }
 
 extern inline void end_bh_atomic(void)
 {
 	barrier();
-	local_bh_count[smp_processor_id()]--;
+	ppc_local_bh_count[smp_processor_id()]--;
 }
 
 /* These are for the irq's testing the lock */
-#define softirq_trylock(cpu)	(local_bh_count[cpu] ? 0 : (local_bh_count[cpu]=1))
-#define softirq_endlock(cpu)	(local_bh_count[cpu] = 0)
-#define synchronize_bh()	do { } while (0)
+#define softirq_trylock(cpu)	(ppc_local_bh_count[cpu] ? 0 : (ppc_local_bh_count[cpu]=1))
+#define softirq_endlock(cpu)	(ppc_local_bh_count[cpu] = 0)
+#define synchronize_bh()	barrier()
 
-#endif /* __SMP__ */
+#endif	/* SMP */
 
 /*
  * These use a mask count to correctly handle
@@ -107,4 +108,4 @@
 		bh_mask |= 1 << nr;
 }
 
-#endif
+#endif	/* __ASM_SOFTIRQ_H */
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/string.h linux/include/asm-ppc/string.h
--- v2.2.7/linux/include/asm-ppc/string.h	Sat Aug 16 09:51:09 1997
+++ linux/include/asm-ppc/string.h	Thu Apr 29 12:39:07 1999
@@ -14,5 +14,6 @@
 #define __HAVE_ARCH_MEMCHR
 
 extern int strcasecmp(const char *, const char *);
+extern int strncasecmp(const char *, const char *, int);
 
 #endif
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/system.h linux/include/asm-ppc/system.h
--- v2.2.7/linux/include/asm-ppc/system.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/system.h	Thu Apr 29 12:39:07 1999
@@ -25,6 +25,9 @@
 #define rmb()  __asm__ __volatile__ ("sync" : : : "memory")
 #define wmb()  __asm__ __volatile__ ("eieio" : : : "memory")
 
+extern void xmon_irq(int, void *, struct pt_regs *);
+extern void xmon(struct pt_regs *excp);
+
 #define __save_flags(flags)	({\
 	__asm__ __volatile__ ("mfmsr %0" : "=r" ((flags)) : : "memory"); })
 #define __save_and_cli(flags)	({__save_flags(flags);__cli();})
@@ -38,10 +41,10 @@
 
 extern __inline__ void __restore_flags(unsigned long flags)
 {
-        extern atomic_t n_lost_interrupts;
+        extern atomic_t ppc_n_lost_interrupts;
 	extern void do_lost_interrupts(unsigned long);
 
-        if ((flags & MSR_EE) && atomic_read(&n_lost_interrupts) != 0) {
+        if ((flags & MSR_EE) && atomic_read(&ppc_n_lost_interrupts) != 0) {
                 do_lost_interrupts(flags);
         } else {
                 __asm__ __volatile__ ("sync; mtmsr %0; isync"
@@ -68,8 +71,8 @@
 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 smp_giveup_fpu(struct task_struct *);
+extern void giveup_fpu(struct task_struct *);
+extern void enable_kernel_fp(void);
 extern void cvt_fd(float *from, double *to, unsigned long *fpscr);
 extern void cvt_df(double *from, float *to, unsigned long *fpscr);
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-ppc/vga.h linux/include/asm-ppc/vga.h
--- v2.2.7/linux/include/asm-ppc/vga.h	Tue Mar 23 14:35:48 1999
+++ linux/include/asm-ppc/vga.h	Thu Apr 29 12:39:07 1999
@@ -46,7 +46,8 @@
 #define scr_memcpyw_from memcpy
 #define scr_memcpyw_to memcpy
 
-#define VGA_MAP_MEM(x) (x + _ISA_MEM_BASE)
+extern unsigned long vgacon_remap_base;
+#define VGA_MAP_MEM(x) (x + vgacon_remap_base)
 #define vga_readb(x) (*(x))
 #define vga_writeb(x,y) (*(y) = (x))
 
diff -u --recursive --new-file v2.2.7/linux/include/asm-sparc/siginfo.h linux/include/asm-sparc/siginfo.h
--- v2.2.7/linux/include/asm-sparc/siginfo.h	Wed Apr 28 11:37:31 1999
+++ linux/include/asm-sparc/siginfo.h	Wed Apr 28 14:40:07 1999
@@ -1,4 +1,4 @@
-/* $Id: siginfo.h,v 1.3 1998/08/26 10:33:29 davem Exp $
+/* $Id: siginfo.h,v 1.4 1999/04/28 19:45:20 davem Exp $
  * siginfo.c:
  */
 
diff -u --recursive --new-file v2.2.7/linux/include/linux/capability.h linux/include/linux/capability.h
--- v2.2.7/linux/include/linux/capability.h	Fri Oct 23 22:01:26 1998
+++ linux/include/linux/capability.h	Mon May 10 11:15:24 1999
@@ -193,7 +193,6 @@
 /* Allow device administration (mknod)*/
 /* Allow examination and configuration of disk quotas */
 /* Allow configuring the kernel's syslog (printk behaviour) */
-/* Allow sending a signal to any process */
 /* Allow setting the domainname */
 /* Allow setting the hostname */
 /* Allow calling bdflush() */
diff -u --recursive --new-file v2.2.7/linux/include/linux/dcache.h linux/include/linux/dcache.h
--- v2.2.7/linux/include/linux/dcache.h	Tue Mar 23 14:35:48 1999
+++ linux/include/linux/dcache.h	Sat May  8 17:56:37 1999
@@ -77,7 +77,7 @@
 };
 
 struct dentry_operations {
-	int (*d_revalidate)(struct dentry *);
+	int (*d_revalidate)(struct dentry *, int);
 	int (*d_hash) (struct dentry *, struct qstr *);
 	int (*d_compare) (struct dentry *, struct qstr *, struct qstr *);
 	void (*d_delete)(struct dentry *);
diff -u --recursive --new-file v2.2.7/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.2.7/linux/include/linux/fs.h	Wed Apr 28 11:37:31 1999
+++ linux/include/linux/fs.h	Mon May 10 11:15:24 1999
@@ -810,6 +810,18 @@
 #define PTR_ERR(ptr)	((long)(ptr))
 #define IS_ERR(ptr)	((unsigned long)(ptr) > (unsigned long)(-1000))
 
+/*
+ * The bitmask for a lookup event:
+ *  - follow links at the end
+ *  - require a directory
+ *  - ending slashes ok even for nonexistent files
+ *  - internal "there are more path compnents" flag
+ */
+#define LOOKUP_FOLLOW		(1)
+#define LOOKUP_DIRECTORY	(2)
+#define LOOKUP_SLASHOK		(4)
+#define LOOKUP_CONTINUE		(8)
+
 extern struct dentry * lookup_dentry(const char *, struct dentry *, unsigned int);
 extern struct dentry * __namei(const char *, unsigned int);
 
diff -u --recursive --new-file v2.2.7/linux/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h
--- v2.2.7/linux/include/linux/nfs_fs.h	Wed Mar 10 15:29:50 1999
+++ linux/include/linux/nfs_fs.h	Mon May 10 11:15:26 1999
@@ -181,6 +181,8 @@
 				struct nfs_fattr *);
 extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
 extern int nfs_revalidate(struct dentry *);
+extern int nfs_open(struct inode *, struct file *);
+extern int nfs_release(struct inode *, struct file *);
 extern int _nfs_revalidate_inode(struct nfs_server *, struct dentry *);
 
 /*
diff -u --recursive --new-file v2.2.7/linux/include/linux/pagemap.h linux/include/linux/pagemap.h
--- v2.2.7/linux/include/linux/pagemap.h	Wed Apr 28 11:37:31 1999
+++ linux/include/linux/pagemap.h	Mon May 10 11:15:32 1999
@@ -17,6 +17,27 @@
 	return PAGE_OFFSET + PAGE_SIZE * (page - mem_map);
 }
 
+/*
+ * The page cache can done in larger chunks than
+ * one page, because it allows for more efficient
+ * throughput (it can then be mapped into user
+ * space in smaller chunks for same flexibility).
+ *
+ * Or rather, it _will_ be done in larger chunks.
+ */
+#define PAGE_CACHE_SHIFT	PAGE_SHIFT
+#define PAGE_CACHE_SIZE		PAGE_SIZE
+#define PAGE_CACHE_MASK		PAGE_MASK
+
+#define page_cache_alloc()	__get_free_page(GFP_USER)
+#define page_cache_free(x)	free_page(x)
+#define page_cache_release(x)	__free_page(x)
+
+/*
+ * From a kernel address, get the "struct page *"
+ */
+#define page_cache_entry(x)	(mem_map + MAP_NR(x))
+
 #define PAGE_HASH_BITS 12
 #define PAGE_HASH_SIZE (1 << PAGE_HASH_BITS)
 
diff -u --recursive --new-file v2.2.7/linux/include/linux/parport_pc.h linux/include/linux/parport_pc.h
--- v2.2.7/linux/include/linux/parport_pc.h	Fri Oct 23 22:01:27 1998
+++ linux/include/linux/parport_pc.h	Mon May 10 11:16:13 1999
@@ -14,8 +14,15 @@
 #define STATUS   0x1
 #define DATA     0
 
+/* Private data for PC low-level driver. */
+struct parport_pc_private {
+	/* Contents of CTR. */
+	unsigned char ctr;
+};
+
 extern int parport_pc_epp_clear_timeout(struct parport *pb);
 
+extern volatile unsigned char parport_pc_ctr;
 
 extern __inline__ void parport_pc_write_epp(struct parport *p, unsigned char d)
 {
@@ -62,19 +69,24 @@
 
 extern __inline__ void parport_pc_write_control(struct parport *p, unsigned char d)
 {
+	struct parport_pc_private *priv = p->private_data;
+	priv->ctr = d;/* update soft copy */
 	outb(d, p->base+CONTROL);
 }
 
 extern __inline__ unsigned char parport_pc_read_control(struct parport *p)
 {
-	return inb(p->base+CONTROL);
+	struct parport_pc_private *priv = p->private_data;
+	return priv->ctr;
 }
 
 extern __inline__ unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask,  unsigned char val)
 {
-	unsigned char old = inb(p->base+CONTROL);
-	outb(((old & ~mask) ^ val), p->base+CONTROL);
-	return old;
+	struct parport_pc_private *priv = p->private_data;
+	unsigned char ctr = priv->ctr;
+	ctr = (ctr & ~mask) ^ val;
+	outb (ctr, p->base+CONTROL);
+	return priv->ctr = ctr; /* update soft copy */
 }
 
 extern __inline__ void parport_pc_write_status(struct parport *p, unsigned char d)
diff -u --recursive --new-file v2.2.7/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.2.7/linux/include/linux/sched.h	Mon Mar 29 11:09:12 1999
+++ linux/include/linux/sched.h	Mon May 10 11:15:26 1999
@@ -112,10 +112,10 @@
  * a separate lock).
  */
 extern rwlock_t tasklist_lock;
-extern spinlock_t scheduler_lock;
 extern spinlock_t runqueue_lock;
 
 extern void sched_init(void);
+extern void init_idle(void);
 extern void show_state(void);
 extern void trap_init(void);
 
diff -u --recursive --new-file v2.2.7/linux/include/linux/smp.h linux/include/linux/smp.h
--- v2.2.7/linux/include/linux/smp.h	Mon Dec 28 15:00:53 1998
+++ linux/include/linux/smp.h	Mon May 10 11:15:24 1999
@@ -42,6 +42,12 @@
 extern void smp_commence(void);
 
 /*
+ * Call a function on all other processors
+ */
+extern int smp_call_function (void (*func) (void *info), void *info,
+			      int retry, int wait);
+
+/*
  * True once the per process idle is forked
  */
 extern int smp_threads_ready;
@@ -60,7 +66,7 @@
 					 * when rebooting
 					 */
 #define MSG_RESCHEDULE		0x0003	/* Reschedule request from master CPU*/
-#define MSG_MTRR_CHANGE         0x0004  /* Change MTRR */
+#define MSG_CALL_FUNCTION       0x0004  /* Call function on all other CPUs */
 
 #else
 
@@ -68,12 +74,13 @@
  *	These macros fold the SMP functionality into a single CPU system
  */
  
-#define smp_num_cpus			1
-#define smp_processor_id()		0
-#define hard_smp_processor_id()		0
-#define smp_threads_ready		1
+#define smp_num_cpus				1
+#define smp_processor_id()			0
+#define hard_smp_processor_id()			0
+#define smp_threads_ready			1
 #define kernel_lock()
-#define cpu_logical_map(cpu)		0
+#define cpu_logical_map(cpu)			0
+#define smp_call_function(func,info,retry,wait)
 
 #endif
 #endif
diff -u --recursive --new-file v2.2.7/linux/include/linux/videodev.h linux/include/linux/videodev.h
--- v2.2.7/linux/include/linux/videodev.h	Tue Feb 23 15:21:35 1999
+++ linux/include/linux/videodev.h	Fri May  7 11:05:30 1999
@@ -95,6 +95,8 @@
 #define VIDEO_TUNER_LOW		8	/* Uses KHz not MHz */
 #define VIDEO_TUNER_NORM	16	/* Tuner can set norm */
 #define VIDEO_TUNER_STEREO_ON	128	/* Tuner is seeing stereo */
+#define VIDEO_TUNER_RDS_ON      256     /* Tuner is seeing an RDS datastream */
+#define VIDEO_TUNER_MBS_ON      512     /* Tuner is seeing an MBS datastream */
 	__u16 mode;			/* PAL/NTSC/SECAM/OTHER */
 #define VIDEO_MODE_PAL		0
 #define VIDEO_MODE_NTSC		1
@@ -275,6 +277,7 @@
 #define VID_HARDWARE_GEMTEK	18
 #define VID_HARDWARE_TYPHOON	19
 #define VID_HARDWARE_VINO	20	/* Reserved for SGI Indy Vino */
+#define VID_HARDWARE_CADET	21	/* Cadet radio */
 
 /*
  *	Initialiser list
diff -u --recursive --new-file v2.2.7/linux/include/net/tcp.h linux/include/net/tcp.h
--- v2.2.7/linux/include/net/tcp.h	Wed Apr 28 11:37:32 1999
+++ linux/include/net/tcp.h	Mon May 10 11:16:25 1999
@@ -174,6 +174,7 @@
 	struct tcp_func		*af_specific;
 	struct tcp_bind_bucket	*tb;
 	struct tcp_tw_bucket	*next_death;
+	struct tcp_tw_bucket	**pprev_death;
 	int			death_slot;
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 	struct in6_addr		v6_daddr;
@@ -714,6 +715,22 @@
 	u32 new_win = __tcp_select_window(sk);
 
 	return (new_win && (new_win > (cur_win << 1)));
+}
+
+/* Recalculate snd_ssthresh, we want to set it to:
+ *
+ * 	one half the current congestion window, but no
+ *	less than two segments
+ *
+ * We must take into account the current send window
+ * as well, however we keep track of that using different
+ * units so a conversion is necessary.  -DaveM
+ */
+extern __inline__ __u32 tcp_recalc_ssthresh(struct tcp_opt *tp)
+{
+	__u32 snd_wnd_packets = tp->snd_wnd / tp->mss_cache;
+
+	return max(min(snd_wnd_packets, tp->snd_cwnd) >> 1, 2);
 }
 
 /* TCP timestamps are only 32-bits, this causes a slight
diff -u --recursive --new-file v2.2.7/linux/include/scsi/sg.h linux/include/scsi/sg.h
--- v2.2.7/linux/include/scsi/sg.h	Fri Apr 16 14:47:31 1999
+++ linux/include/scsi/sg.h	Fri May  7 11:05:30 1999
@@ -12,10 +12,16 @@
 *       Copyright (C) 1998, 1999 Douglas Gilbert
 
 
-    Version: 2.1.31 (990327)
+    Version: 2.1.32 (990501)
     This version for later 2.1.x series and 2.2.x kernels
     D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au)
 
+    Changes since 2.1.31 (990327)
+        - add ioctls SG_GET_UNDERRUN_FLAG and _SET_. Change the default
+          to _not_ flag underruns (affects aic7xxx driver)
+        - clean up logging of pointers to use %p (for 64 bit architectures)
+        - rework usage of get_user/copy_to_user family of kernel calls
+        - "disown" scsi_command blocks before releasing them
     Changes since 2.1.30 (990320)
         - memory tweaks: change flags on kmalloc (GFP_KERNEL to GFP_ATOMIC)
         -                increase max allowable mid-level pool usage
@@ -113,7 +119,7 @@
  requesting 512KB) and scale them back in the face of ENOMEM errors.
  N.B. Queuing up commands also ties up kernel memory.
 
- More documentation can be found at www.netwinder.org/~dougg
+ More documentation can be found at www.torque.net/sg
 */
 
 #define SG_MAX_SENSE 16   /* too little, unlikely to change in 2.2.x */
@@ -197,6 +203,11 @@
 #define SG_GET_COMMAND_Q 0x2270   /* Yields 0 (queuing off) or 1 (on) */
 #define SG_SET_COMMAND_Q 0x2271   /* Change queuing state with 0 or 1 */
 
+/* Get/set whether DMA underrun will cause an error (DID_ERROR) [this only
+   currently applies to the [much-used] aic7xxx driver) */
+#define SG_GET_UNDERRUN_FLAG 0x2280 /* Yields 0 (don't flag) or 1 (flag) */
+#define SG_SET_UNDERRUN_FLAG 0x2281 /* Change flag underrun state */
+
 
 #define SG_DEFAULT_TIMEOUT (60*HZ) /* HZ == 'jiffies in 1 second' */
 #define SG_DEFAULT_RETRIES 1
@@ -206,6 +217,7 @@
 #define SG_DEF_MERGE_FD 0       /* was 1 -> per device sequencing */
 #define SG_DEF_FORCE_LOW_DMA 0  /* was 1 -> memory below 16MB on i386 */
 #define SG_DEF_FORCE_PACK_ID 0
+#define SG_DEF_UNDERRUN_FLAG 0
 
 /* maximum outstanding requests, write() yields EDOM if exceeded */
 #define SG_MAX_QUEUE 16
diff -u --recursive --new-file v2.2.7/linux/init/main.c linux/init/main.c
--- v2.2.7/linux/init/main.c	Wed Apr 28 11:37:32 1999
+++ linux/init/main.c	Fri May  7 11:05:30 1999
@@ -74,7 +74,7 @@
 extern void uidcache_init(void);
 extern void mca_init(void);
 extern void sbus_init(void);
-extern void powermac_init(void);
+extern void ppc_init(void);
 extern void sysctl_init(void);
 extern void filescache_init(void);
 extern void signals_init(void);
@@ -354,7 +354,7 @@
 int rows, cols;
 
 #ifdef CONFIG_BLK_DEV_RAM
-extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load */
+extern int rd_doload;		/* 1 = load ramdisk, 0 = don't load 2 = dual disk */
 extern int rd_prompt;		/* 1 = prompt for ramdisk, 0 = don't prompt */
 extern int rd_size;		/* Size of the ramdisk(s) */
 extern int rd_image_start;	/* starting block # of image */
@@ -578,6 +578,7 @@
 	{ "no-hlt", no_halt },
 	{ "no387", no_387 },
 	{ "reboot=", reboot_setup },
+	{ "mca-pentium", mca_pentium },
 #endif
 #ifdef CONFIG_INET
 	{ "ether=", eth_setup },
@@ -901,7 +902,7 @@
 static void __init load_ramdisk(char *str, int *ints)
 {
    if (ints[0] > 0 && ints[1] >= 0)
-      rd_doload = ints[1] & 1;
+      rd_doload = ints[1] & 3;
 }
 
 static void __init prompt_ramdisk(char *str, int *ints)
@@ -1262,7 +1263,7 @@
 	sbus_init();
 #endif
 #if defined(CONFIG_PPC)
-	powermac_init();
+	ppc_init();
 #endif
 #ifdef CONFIG_MCA
 	mca_init();
diff -u --recursive --new-file v2.2.7/linux/ipc/shm.c linux/ipc/shm.c
--- v2.2.7/linux/ipc/shm.c	Wed Apr 28 11:37:32 1999
+++ linux/ipc/shm.c	Tue May  4 16:58:15 1999
@@ -634,7 +634,7 @@
 
 	pte = __pte(shp->shm_pages[idx]);
 	if (!pte_present(pte)) {
-		unsigned long page = get_free_page(GFP_KERNEL);
+		unsigned long page = get_free_page(GFP_USER);
 		if (!page) {
 			oom(current);
 			return 0;
diff -u --recursive --new-file v2.2.7/linux/kernel/exit.c linux/kernel/exit.c
--- v2.2.7/linux/kernel/exit.c	Tue Mar 23 14:35:48 1999
+++ linux/kernel/exit.c	Fri Apr 30 08:13:37 1999
@@ -32,9 +32,9 @@
 		 */
 		for (;;)  {
 			int has_cpu;
-			spin_lock(&scheduler_lock);
+			spin_lock_irq(&runqueue_lock);
 			has_cpu = p->has_cpu;
-			spin_unlock(&scheduler_lock);
+			spin_unlock_irq(&runqueue_lock);
 			if (!has_cpu)
 				break;
 			do {
diff -u --recursive --new-file v2.2.7/linux/kernel/sched.c linux/kernel/sched.c
--- v2.2.7/linux/kernel/sched.c	Tue Mar 23 14:35:48 1999
+++ linux/kernel/sched.c	Mon May 10 09:55:21 1999
@@ -96,13 +96,156 @@
  
 struct task_struct * task[NR_TASKS] = {&init_task, };
 
+/*
+ * We align per-CPU scheduling data on cacheline boundaries,
+ * to prevent cacheline ping-pong.
+ */
+static union {
+	struct schedule_data {
+		struct task_struct * curr;
+		cycles_t last_schedule;
+	} schedule_data;
+	char __pad [SMP_CACHE_BYTES];
+} aligned_data [NR_CPUS] __cacheline_aligned = { {{&init_task,0}}};
+
+#define cpu_curr(cpu) aligned_data[(cpu)].schedule_data.curr
+
 struct kernel_stat kstat = { 0 };
 
+#ifdef __SMP__
+
+#define idle_task(cpu) (task[cpu_number_map[(cpu)]])
+#define can_schedule(p)	(!(p)->has_cpu)
+
+#else
+
+#define idle_task(cpu) (&init_task)
+#define can_schedule(p) (1)
+
+#endif
+
 void scheduling_functions_start_here(void) { }
 
+/*
+ * This is the function that decides how desirable a process is..
+ * You can weigh different processes against each other depending
+ * on what CPU they've run on lately etc to try to handle cache
+ * and TLB miss penalties.
+ *
+ * Return values:
+ *	 -1000: never select this
+ *	     0: out of time, recalculate counters (but it might still be
+ *		selected)
+ *	   +ve: "goodness" value (the larger, the better)
+ *	 +1000: realtime process, select this.
+ */
+
+static inline int goodness (struct task_struct * prev,
+				 struct task_struct * p, int this_cpu)
+{
+	int weight;
+
+	/*
+	 * Realtime process, select the first one on the
+	 * runqueue (taking priorities within processes
+	 * into account).
+	 */
+	if (p->policy != SCHED_OTHER) {
+		weight = 1000 + p->rt_priority;
+		goto out;
+	}
+
+	/*
+	 * Give the process a first-approximation goodness value
+	 * according to the number of clock-ticks it has left.
+	 *
+	 * Don't do any other calculations if the time slice is
+	 * over..
+	 */
+	weight = p->counter;
+	if (!weight)
+		goto out;
+			
 #ifdef __SMP__
-static void reschedule_idle_slow(struct task_struct * p)
+	/* Give a largish advantage to the same processor...   */
+	/* (this is equivalent to penalizing other processors) */
+	if (p->processor == this_cpu)
+		weight += PROC_CHANGE_PENALTY;
+#endif
+
+	/* .. and a slight advantage to the current MM */
+	if (p->mm == prev->mm)
+		weight += 1;
+	weight += p->priority;
+
+out:
+	return weight;
+}
+
+/*
+ * subtle. We want to discard a yielded process only if it's being
+ * considered for a reschedule. Wakeup-time 'queries' of the scheduling
+ * state do not count. Another optimization we do: sched_yield()-ed
+ * processes are runnable (and thus will be considered for scheduling)
+ * right when they are calling schedule(). So the only place we need
+ * to care about SCHED_YIELD is when we calculate the previous process'
+ * goodness ...
+ */
+static inline int prev_goodness (struct task_struct * prev,
+					struct task_struct * p, int this_cpu)
+{
+	if (p->policy & SCHED_YIELD) {
+		p->policy &= ~SCHED_YIELD;
+		return 0;
+	}
+	return goodness(prev, p, this_cpu);
+}
+
+/*
+ * the 'goodness value' of replacing a process on a given CPU.
+ * positive value means 'replace', zero or negative means 'dont'.
+ */
+static inline int preemption_goodness (struct task_struct * prev,
+				struct task_struct * p, int cpu)
+{
+	return goodness(prev, p, cpu) - goodness(prev, prev, cpu);
+}
+
+/*
+ * If there is a dependency between p1 and p2,
+ * don't be too eager to go into the slow schedule.
+ * In particular, if p1 and p2 both want the kernel
+ * lock, there is no point in trying to make them
+ * extremely parallel..
+ *
+ * (No lock - lock_depth < 0)
+ *
+ * There are two additional metrics here:
+ *
+ * first, a 'cutoff' interval, currently 0-200 usecs on
+ * x86 CPUs, depending on the size of the 'SMP-local cache'.
+ * If the current process has longer average timeslices than
+ * this, then we utilize the idle CPU.
+ *
+ * second, if the wakeup comes from a process context,
+ * then the two processes are 'related'. (they form a
+ * 'gang')
+ *
+ * An idle CPU is almost always a bad thing, thus we skip
+ * the idle-CPU utilization only if both these conditions
+ * are true. (ie. a 'process-gang' rescheduling with rather
+ * high frequency should stay on the same CPU).
+ *
+ * [We can switch to something more finegrained in 2.3.]
+ *
+ * do not 'guess' if the to-be-scheduled task is RT.
+ */
+#define related(p1,p2) (((p1)->lock_depth >= 0) && (p2)->lock_depth >= 0) && \
+	(((p2)->policy == SCHED_OTHER) && ((p1)->avg_slice < cacheflush_time))
+
+static inline void reschedule_idle_slow(struct task_struct * p)
 {
+#ifdef __SMP__
 /*
  * (see reschedule_idle() for an explanation first ...)
  *
@@ -124,60 +267,71 @@
  * 2.3. Also we can try to use the avg_slice value to predict
  * 'likely reschedule' events even on other CPUs.]
  */
-	int best_cpu = p->processor, this_cpu = smp_processor_id();
-	struct task_struct **idle = task, *tsk, *target_tsk;
-	int i = smp_num_cpus;
+	int this_cpu = smp_processor_id(), target_cpu;
+	struct task_struct *tsk, *target_tsk;
+	int cpu, best_cpu, weight, best_weight, i;
+	unsigned long flags;
+
+	best_weight = 0; /* prevents negative weight */
+
+	spin_lock_irqsave(&runqueue_lock, flags);
+
+	/*
+	 * shortcut if the woken up task's last CPU is
+	 * idle now.
+	 */
+	best_cpu = p->processor;
+	target_tsk = idle_task(best_cpu);
+	if (cpu_curr(best_cpu) == target_tsk)
+		goto send_now;
 
 	target_tsk = NULL;
-	do {
-		tsk = *idle;
-		idle++;
-		if (tsk->has_cpu) {
-			if (tsk->processor == this_cpu)
-				continue;
+	for (i = 0; i < smp_num_cpus; i++) {
+		cpu = cpu_logical_map(i);
+		tsk = cpu_curr(cpu);
+		if (related(tsk, p))
+			goto out_no_target;
+		weight = preemption_goodness(tsk, p, cpu);
+		if (weight > best_weight) {
+			best_weight = weight;
 			target_tsk = tsk;
-			if (tsk->processor == best_cpu) {
-				/*
-				 * bingo, we couldnt get a better
-				 * CPU, activate it.
-				 */
-				goto send; /* this one helps GCC ... */
-			}
 		}
-	} while (--i > 0);
+	}
 
 	/*
-	 * found any idle CPU?
+	 * found any suitable CPU?
 	 */
-	if (target_tsk) {
-send:
-		target_tsk->need_resched = 1;
-		smp_send_reschedule(target_tsk->processor);
-		return;
-	}
+	if (!target_tsk)
+		goto out_no_target;
+		
+send_now:
+	target_cpu = target_tsk->processor;
+	target_tsk->need_resched = 1;
+	spin_unlock_irqrestore(&runqueue_lock, flags);
+	/*
+	 * the APIC stuff can go outside of the lock because
+	 * it uses no task information, only CPU#.
+	 */
+	if (target_cpu != this_cpu)
+		smp_send_reschedule(target_cpu);
+	return;
+out_no_target:
+	spin_unlock_irqrestore(&runqueue_lock, flags);
+	return;
+#else /* UP */
+	int this_cpu = smp_processor_id();
+	struct task_struct *tsk;
+
+	tsk = cpu_curr(this_cpu);
+	if (preemption_goodness(tsk, p, this_cpu) > 0)
+		tsk->need_resched = 1;
+#endif
 }
-#endif /* __SMP__ */
 
-/*
- * If there is a dependency between p1 and p2,
- * don't be too eager to go into the slow schedule.
- * In particular, if p1 and p2 both want the kernel
- * lock, there is no point in trying to make them
- * extremely parallel..
- *
- * (No lock - lock_depth < 0)
- */
-#define related(p1,p2) ((p1)->lock_depth >= 0 && (p2)->lock_depth >= 0)
-
-static inline void reschedule_idle(struct task_struct * p)
+static void reschedule_idle(struct task_struct * p)
 {
-
-	if (p->policy != SCHED_OTHER || p->counter > current->counter + 3) {
-		current->need_resched = 1;
-		return;
-	}
-
 #ifdef __SMP__
+	int cpu = smp_processor_id();
 	/*
 	 * ("wakeup()" should not be called before we've initialized
 	 * SMP completely.
@@ -187,35 +341,20 @@
 	 *
 	 * SMP rescheduling is done in 2 passes:
 	 *  - pass #1: faster: 'quick decisions'
-	 *  - pass #2: slower: 'lets try and find another CPU'
+	 *  - pass #2: slower: 'lets try and find a suitable CPU'
 	 */
 
 	/*
-	 * Pass #1
-	 *
-	 * There are two metrics here:
-	 *
-	 * first, a 'cutoff' interval, currently 0-200 usecs on
-	 * x86 CPUs, depending on the size of the 'SMP-local cache'.
-	 * If the current process has longer average timeslices than
-	 * this, then we utilize the idle CPU.
-	 *
-	 * second, if the wakeup comes from a process context,
-	 * then the two processes are 'related'. (they form a
-	 * 'gang')
-	 *
-	 * An idle CPU is almost always a bad thing, thus we skip
-	 * the idle-CPU utilization only if both these conditions
-	 * are true. (ie. a 'process-gang' rescheduling with rather
-	 * high frequency should stay on the same CPU).
-	 *
-	 * [We can switch to something more finegrained in 2.3.]
+	 * Pass #1. (subtle. We might be in the middle of __switch_to, so
+	 * to preserve scheduling atomicity we have to use cpu_curr)
 	 */
-	if ((current->avg_slice < cacheflush_time) && related(current, p))
+	if ((p->processor == cpu) && related(cpu_curr(cpu), p))
 		return;
-
-	reschedule_idle_slow(p);
 #endif /* __SMP__ */
+	/*
+	 * Pass #2
+	 */
+	reschedule_idle_slow(p);
 }
 
 /*
@@ -291,7 +430,6 @@
  * The run-queue lock locks the parts that actually access
  * and change the run-queues, and have to be interrupt-safe.
  */
-spinlock_t scheduler_lock = SPIN_LOCK_UNLOCKED;	/* should be acquired first */
 spinlock_t runqueue_lock = SPIN_LOCK_UNLOCKED;  /* second */
 rwlock_t tasklist_lock = RW_LOCK_UNLOCKED;	/* third */
 
@@ -307,12 +445,19 @@
 {
 	unsigned long flags;
 
+	/*
+	 * We want the common case fall through straight, thus the goto.
+	 */
 	spin_lock_irqsave(&runqueue_lock, flags);
 	p->state = TASK_RUNNING;
-	if (!p->next_run) {
-		add_to_runqueue(p);
-		reschedule_idle(p);
-	}
+	if (p->next_run)
+		goto out;
+	add_to_runqueue(p);
+	spin_unlock_irqrestore(&runqueue_lock, flags);
+
+	reschedule_idle(p);
+	return;
+out:
 	spin_unlock_irqrestore(&runqueue_lock, flags);
 }
 
@@ -324,63 +469,6 @@
 }
 
 /*
- * This is the function that decides how desirable a process is..
- * You can weigh different processes against each other depending
- * on what CPU they've run on lately etc to try to handle cache
- * and TLB miss penalties.
- *
- * Return values:
- *	 -1000: never select this
- *	     0: out of time, recalculate counters (but it might still be
- *		selected)
- *	   +ve: "goodness" value (the larger, the better)
- *	 +1000: realtime process, select this.
- */
-static inline int goodness(struct task_struct * p, struct task_struct * prev, int this_cpu)
-{
-	int policy = p->policy;
-	int weight;
-
-	if (policy & SCHED_YIELD) {
-		p->policy = policy & ~SCHED_YIELD;
-		return 0;
-	}
-
-	/*
-	 * Realtime process, select the first one on the
-	 * runqueue (taking priorities within processes
-	 * into account).
-	 */
-	if (policy != SCHED_OTHER)
-		return 1000 + p->rt_priority;
-
-	/*
-	 * Give the process a first-approximation goodness value
-	 * according to the number of clock-ticks it has left.
-	 *
-	 * Don't do any other calculations if the time slice is
-	 * over..
-	 */
-	weight = p->counter;
-	if (weight) {
-			
-#ifdef __SMP__
-		/* Give a largish advantage to the same processor...   */
-		/* (this is equivalent to penalizing other processors) */
-		if (p->processor == this_cpu)
-			weight += PROC_CHANGE_PENALTY;
-#endif
-
-		/* .. and a slight advantage to the current thread */
-		if (p->mm == prev->mm)
-			weight += 1;
-		weight += p->priority;
-	}
-
-	return weight;
-}
-
-/*
  * Event timer code
  */
 #define TVN_BITS 6
@@ -513,18 +601,6 @@
 	return ret;
 }
 
-#ifdef __SMP__
-
-#define idle_task (task[cpu_number_map[this_cpu]])
-#define can_schedule(p)	(!(p)->has_cpu)
-
-#else
-
-#define idle_task (&init_task)
-#define can_schedule(p) (1)
-
-#endif
-
 signed long schedule_timeout(signed long timeout)
 {
 	struct timer_list timer;
@@ -577,60 +653,24 @@
 }
 
 /*
- * This one aligns per-CPU data on cacheline boundaries.
+ * schedule_tail() is getting called from the fork return path. This
+ * cleans up all remaining scheduler things, without impacting the
+ * common case.
  */
-static union {
-	struct schedule_data {
-		struct task_struct * prev;
-		long prevstate;
-		cycles_t last_schedule;
-	} schedule_data;
-	char __pad [SMP_CACHE_BYTES];
-} aligned_data [NR_CPUS] __cacheline_aligned = { {{&init_task,0}}};
-
-
-static inline void __schedule_tail (void)
+static inline void __schedule_tail (struct task_struct *prev)
 {
 #ifdef __SMP__
-	struct schedule_data * sched_data;
-
-	/*
-	 * We might have switched CPUs:
-	 */
-	sched_data = & aligned_data[smp_processor_id()].schedule_data;
-
-	/*
-	 * Subtle. In the rare event that we got a wakeup to 'prev' just
-	 * during the reschedule (this is possible, the scheduler is pretty
-	 * parallel), we should do another reschedule in the next task's
-	 * context. schedule() will do the right thing next time around.
-	 * this is equivalent to 'delaying' the wakeup until the reschedule
-	 * has finished.
-	 */
-	if (sched_data->prev->state != sched_data->prevstate)
-		current->need_resched = 1;
-
-	/*
-	 * Release the previous process ...
-	 *
-	 * We have dropped all locks, and we must make sure that we
-	 * only mark the previous process as no longer having a CPU
-	 * after all other state has been seen by other CPU's. Thus
-	 * the write memory barrier!
-	 */
+	if ((prev->state == TASK_RUNNING) &&
+			(prev != idle_task(smp_processor_id())))
+		reschedule_idle(prev);
 	wmb();
-	sched_data->prev->has_cpu = 0;
+	prev->has_cpu = 0;
 #endif /* __SMP__ */
 }
 
-/*
- * schedule_tail() is getting called from the fork return path. This
- * cleans up all remaining scheduler things, without impacting the
- * common case.
- */
-void schedule_tail (void)
+void schedule_tail (struct task_struct *prev)
 {
-	__schedule_tail();
+	__schedule_tail(prev);
 }
 
 /*
@@ -646,37 +686,38 @@
 asmlinkage void schedule(void)
 {
 	struct schedule_data * sched_data;
-	struct task_struct * prev, * next;
-	int this_cpu;
+	struct task_struct *prev, *next, *p;
+	int this_cpu, c;
 
-	run_task_queue(&tq_scheduler);
+	if (tq_scheduler)
+		goto handle_tq_scheduler;
+tq_scheduler_back:
 
 	prev = current;
 	this_cpu = prev->processor;
-	/*
-	 * 'sched_data' is protected by the fact that we can run
-	 * only one process per CPU.
-	 */
-	sched_data = & aligned_data[this_cpu].schedule_data;
 
 	if (in_interrupt())
 		goto scheduling_in_interrupt;
+
 	release_kernel_lock(prev, this_cpu);
 
 	/* Do "administrative" work here while we don't hold any locks */
-	if (bh_active & bh_mask)
-		do_bottom_half();
+	if (bh_mask & bh_active)
+		goto handle_bh;
+handle_bh_back:
+
+	/*
+	 * 'sched_data' is protected by the fact that we can run
+	 * only one process per CPU.
+	 */
+	sched_data = & aligned_data[this_cpu].schedule_data;
 
-	spin_lock(&scheduler_lock);
 	spin_lock_irq(&runqueue_lock);
 
 	/* move an exhausted RR process to be last.. */
-	prev->need_resched = 0;
-
-	if (!prev->counter && prev->policy == SCHED_RR) {
-		prev->counter = prev->priority;
-		move_last_runqueue(prev);
-	}
+	if (prev->policy == SCHED_RR)
+		goto move_rr_last;
+move_rr_back:
 
 	switch (prev->state) {
 		case TASK_INTERRUPTIBLE:
@@ -688,62 +729,72 @@
 			del_from_runqueue(prev);
 		case TASK_RUNNING:
 	}
+	prev->need_resched = 0;
 
-	sched_data->prevstate = prev->state;
+repeat_schedule:
 
-/* this is the scheduler proper: */
-	{
-		struct task_struct * p = init_task.next_run;
-		int c = -1000;
+	/*
+	 * this is the scheduler proper:
+	 */
 
-		/* Default process to select.. */
-		next = idle_task;
-		if (prev->state == TASK_RUNNING) {
-			c = goodness(prev, prev, this_cpu);
-			next = prev;
-		}
+	p = init_task.next_run;
+	/* Default process to select.. */
+	next = idle_task(this_cpu);
+	c = -1000;
+	if (prev->state == TASK_RUNNING)
+		goto still_running;
+still_running_back:
 
-		/*
-		 * This is subtle.
-		 * Note how we can enable interrupts here, even
-		 * though interrupts can add processes to the run-
-		 * queue. This is because any new processes will
-		 * be added to the front of the queue, so "p" above
-		 * is a safe starting point.
-		 * run-queue deletion and re-ordering is protected by
-		 * the scheduler lock
-		 */
-		spin_unlock_irq(&runqueue_lock);
+	/*
+	 * This is subtle.
+	 * Note how we can enable interrupts here, even
+	 * though interrupts can add processes to the run-
+	 * queue. This is because any new processes will
+	 * be added to the front of the queue, so "p" above
+	 * is a safe starting point.
+	 * run-queue deletion and re-ordering is protected by
+	 * the scheduler lock
+	 */
 /*
  * Note! there may appear new tasks on the run-queue during this, as
  * interrupts are enabled. However, they will be put on front of the
  * list, so our list starting at "p" is essentially fixed.
  */
-		while (p != &init_task) {
-			if (can_schedule(p)) {
-				int weight = goodness(p, prev, this_cpu);
-				if (weight > c)
-					c = weight, next = p;
-			}
-			p = p->next_run;
-		}
-
-		/* Do we need to re-calculate counters? */
-		if (!c) {
-			struct task_struct *p;
-			read_lock(&tasklist_lock);
-			for_each_task(p)
-				p->counter = (p->counter >> 1) + p->priority;
-			read_unlock(&tasklist_lock);
+	while (p != &init_task) {
+		if (can_schedule(p)) {
+			int weight = goodness(prev, p, this_cpu);
+			if (weight > c)
+				c = weight, next = p;
 		}
+		p = p->next_run;
 	}
 
+	/* Do we need to re-calculate counters? */
+	if (!c)
+		goto recalculate;
+	/*
+	 * from this point on nothing can prevent us from
+	 * switching to the next task, save this fact in
+	 * sched_data.
+	 */
+	sched_data->curr = next;
+#ifdef __SMP__
+ 	next->has_cpu = 1;
+	next->processor = this_cpu;
+#endif
+	spin_unlock_irq(&runqueue_lock);
+
+	if (prev == next)
+		goto same_process;
+
+#ifdef __SMP__
  	/*
  	 * maintain the per-process 'average timeslice' value.
  	 * (this has to be recalculated even if we reschedule to
- 	 * the same process) Currently this is only used on SMP:
+ 	 * the same process) Currently this is only used on SMP,
+	 * and it's approximate, so we do not have to maintain
+	 * it while holding the runqueue spinlock.
  	 */
-#ifdef __SMP__
 	{
 		cycles_t t, this_slice;
 
@@ -752,10 +803,11 @@
 		sched_data->last_schedule = t;
 
 		/*
-		 * Simple, exponentially fading average calculation:
+		 * Exponentially fading average calculation, with
+		 * some weight so it doesnt get fooled easily by
+		 * smaller irregularities.
 		 */
-		prev->avg_slice = this_slice + prev->avg_slice;
-		prev->avg_slice >>= 1;
+		prev->avg_slice = (this_slice*1 + prev->avg_slice*1)/2;
 	}
 
 	/*
@@ -763,27 +815,55 @@
 	 * thus we have to lock the previous process from getting
 	 * rescheduled during switch_to().
 	 */
- 	next->processor = this_cpu;
- 	next->has_cpu = 1;
-	spin_unlock(&scheduler_lock);
+
 #endif /* __SMP__ */
- 	if (prev != next) {
-#ifdef __SMP__
-		sched_data->prev = prev;
-#endif
-	 	kstat.context_swtch++;
-		get_mmu_context(next);
-		switch_to(prev,next);
 
-		__schedule_tail();
-	}
+	kstat.context_swtch++;
+	get_mmu_context(next);
+	switch_to(prev, next, prev);
+	__schedule_tail(prev);
+
+same_process:
   
 	reacquire_kernel_lock(current);
 	return;
 
+recalculate:
+	{
+		struct task_struct *p;
+		spin_unlock_irq(&runqueue_lock);
+		read_lock(&tasklist_lock);
+		for_each_task(p)
+			p->counter = (p->counter >> 1) + p->priority;
+		read_unlock(&tasklist_lock);
+		spin_lock_irq(&runqueue_lock);
+		goto repeat_schedule;
+	}
+
+still_running:
+	c = prev_goodness(prev, prev, this_cpu);
+	next = prev;
+	goto still_running_back;
+
+handle_bh:
+	do_bottom_half();
+	goto handle_bh_back;
+
+handle_tq_scheduler:
+	run_task_queue(&tq_scheduler);
+	goto tq_scheduler_back;
+
+move_rr_last:
+	if (!prev->counter) {
+		prev->counter = prev->priority;
+		move_last_runqueue(prev);
+	}
+	goto move_rr_back;
+
 scheduling_in_interrupt:
 	printk("Scheduling in interrupt\n");
 	*(int *)0 = 0;
+	return;
 }
 
 rwlock_t waitqueue_lock = RW_LOCK_UNLOCKED;
@@ -798,21 +878,42 @@
  */
 void __wake_up(struct wait_queue **q, unsigned int mode)
 {
-	struct wait_queue *next;
+	struct task_struct *p;
+	struct wait_queue *head, *next;
+
+        if (!q)
+		goto out;
+	/*
+	 * this is safe to be done before the check because it
+	 * means no deference, just pointer operations.
+	 */
+	head = WAIT_QUEUE_HEAD(q);
 
 	read_lock(&waitqueue_lock);
-	if (q && (next = *q)) {
-		struct wait_queue *head;
+	next = *q;
+	if (!next)
+		goto out_unlock;
 
-		head = WAIT_QUEUE_HEAD(q);
-		while (next != head) {
-			struct task_struct *p = next->task;
-			next = next->next;
-			if (p->state & mode)
+	while (next != head) {
+		p = next->task;
+		next = next->next;
+		if (p->state & mode) {
+			/*
+			 * We can drop the read-lock early if this
+			 * is the only/last process.
+			 */
+			if (next == head) {
+				read_unlock(&waitqueue_lock);
 				wake_up_process(p);
+				goto out;
+			}
+			wake_up_process(p);
 		}
 	}
+out_unlock:
 	read_unlock(&waitqueue_lock);
+out:
+	return;
 }
 
 /*
@@ -942,14 +1043,14 @@
 
 #define	SLEEP_ON_HEAD					\
 	wait.task = current;				\
-	write_lock_irqsave(&waitqueue_lock, flags);	\
+	write_lock_irqsave(&waitqueue_lock,flags);	\
 	__add_wait_queue(p, &wait);			\
 	write_unlock(&waitqueue_lock);
 
 #define	SLEEP_ON_TAIL						\
 	write_lock_irq(&waitqueue_lock);			\
 	__remove_wait_queue(p, &wait);				\
-	write_unlock_irqrestore(&waitqueue_lock, flags);
+	write_unlock_irqrestore(&waitqueue_lock,flags);
 
 void interruptible_sleep_on(struct wait_queue **p)
 {
@@ -1623,7 +1724,6 @@
 	/*
 	 * We play safe to avoid deadlocks.
 	 */
-	spin_lock(&scheduler_lock);
 	spin_lock_irq(&runqueue_lock);
 	read_lock(&tasklist_lock);
 
@@ -1671,7 +1771,6 @@
 out_unlock:
 	read_unlock(&tasklist_lock);
 	spin_unlock_irq(&runqueue_lock);
-	spin_unlock(&scheduler_lock);
 
 out_nounlock:
 	return retval;
@@ -1746,14 +1845,12 @@
 
 asmlinkage int sys_sched_yield(void)
 {
-	spin_lock(&scheduler_lock);
 	spin_lock_irq(&runqueue_lock);
 	if (current->policy == SCHED_OTHER)
 		current->policy |= SCHED_YIELD;
 	current->need_resched = 1;
 	move_last_runqueue(current);
 	spin_unlock_irq(&runqueue_lock);
-	spin_unlock(&scheduler_lock);
 	return 0;
 }
 
@@ -1930,11 +2027,22 @@
 	read_unlock(&tasklist_lock);
 }
 
+void __init init_idle(void)
+{
+	cycles_t t;
+	struct schedule_data * sched_data;
+	sched_data = &aligned_data[smp_processor_id()].schedule_data;
+
+	t = get_cycles();
+	sched_data->curr = current;
+	sched_data->last_schedule = t;
+}
+
 void __init sched_init(void)
 {
 	/*
-	 *	We have to do a little magic to get the first
-	 *	process right in SMP mode.
+	 * We have to do a little magic to get the first
+	 * process right in SMP mode.
 	 */
 	int cpu=hard_smp_processor_id();
 	int nr = NR_TASKS;
diff -u --recursive --new-file v2.2.7/linux/kernel/signal.c linux/kernel/signal.c
--- v2.2.7/linux/kernel/signal.c	Mon Mar 29 11:09:12 1999
+++ linux/kernel/signal.c	Sun May  2 12:23:54 1999
@@ -265,7 +265,7 @@
 	    && ((sig != SIGCONT) || (current->session != t->session))
 	    && (current->euid ^ t->suid) && (current->euid ^ t->uid)
 	    && (current->uid ^ t->suid) && (current->uid ^ t->uid)
-	    && !capable(CAP_SYS_ADMIN))
+	    && !capable(CAP_KILL))
 		goto out_nolock;
 
 	/* The null signal is a permissions and process existance probe.
diff -u --recursive --new-file v2.2.7/linux/mm/filemap.c linux/mm/filemap.c
--- v2.2.7/linux/mm/filemap.c	Tue Mar 23 14:35:48 1999
+++ linux/mm/filemap.c	Thu Apr 29 15:07:58 1999
@@ -34,12 +34,6 @@
 unsigned long page_cache_size = 0;
 struct page * page_hash_table[PAGE_HASH_SIZE];
 
-/*
- * Simple routines for both non-shared and shared mappings.
- */
-
-#define release_page(page) __free_page((page))
-
 /* 
  * Define a request structure for outstanding page write requests
  * to the background page io daemon
@@ -83,7 +77,7 @@
 		page->prev = NULL;
 		remove_page_from_hash_queue(page);
 		page->inode = NULL;
-		__free_page(page);
+		page_cache_release(page);
 		continue;
 	}
 }
@@ -115,15 +109,15 @@
 			page->prev = NULL;
 			remove_page_from_hash_queue(page);
 			page->inode = NULL;
-			__free_page(page);
+			page_cache_release(page);
 			continue;
 		}
 		p = &page->next;
 		offset = start - offset;
 		/* partial truncate, clear end of page */
-		if (offset < PAGE_SIZE) {
+		if (offset < PAGE_CACHE_SIZE) {
 			unsigned long address = page_address(page);
-			memset((void *) (offset + address), 0, PAGE_SIZE - offset);
+			memset((void *) (offset + address), 0, PAGE_CACHE_SIZE - offset);
 			flush_page_to_ram(address);
 		}
 	}
@@ -136,7 +130,7 @@
 {
 	remove_page_from_hash_queue(page);
 	remove_page_from_inode_queue(page);
-	__free_page(page);
+	page_cache_release(page);
 }
 
 int shrink_mmap(int priority, int gfp_mask)
@@ -226,9 +220,9 @@
 {
 	unsigned long offset, len;
 
-	offset = (pos & ~PAGE_MASK);
-	pos = pos & PAGE_MASK;
-	len = PAGE_SIZE - offset;
+	offset = (pos & ~PAGE_CACHE_MASK);
+	pos = pos & PAGE_CACHE_MASK;
+	len = PAGE_CACHE_SIZE - offset;
 	do {
 		struct page * page;
 
@@ -238,13 +232,13 @@
 		if (page) {
 			wait_on_page(page);
 			memcpy((void *) (offset + page_address(page)), buf, len);
-			release_page(page);
+			page_cache_release(page);
 		}
 		count -= len;
 		buf += len;
-		len = PAGE_SIZE;
+		len = PAGE_CACHE_SIZE;
 		offset = 0;
-		pos += PAGE_SIZE;
+		pos += PAGE_CACHE_SIZE;
 	} while (count);
 }
 
@@ -271,10 +265,10 @@
 	struct page * page;
 	struct page ** hash;
 
-	offset &= PAGE_MASK;
+	offset &= PAGE_CACHE_MASK;
 	switch (page_cache) {
 	case 0:
-		page_cache = __get_free_page(GFP_USER);
+		page_cache = page_cache_alloc();
 		if (!page_cache)
 			break;
 	default:
@@ -286,12 +280,12 @@
 			/*
 			 * Ok, add the new page to the hash-queues...
 			 */
-			page = mem_map + MAP_NR(page_cache);
+			page = page_cache_entry(page_cache);
 			add_to_page_cache(page, inode, offset, hash);
 			inode->i_op->readpage(file, page);
 			page_cache = 0;
 		}
-		release_page(page);
+		page_cache_release(page);
 	}
 	return page_cache;
 }
@@ -413,7 +407,7 @@
  * performances.
  * Reasonable means, in this context, not too large but not too small.
  * The actual maximum value is:
- *	MAX_READAHEAD + PAGE_SIZE = 76k is CONFIG_READA_SMALL is undefined
+ *	MAX_READAHEAD + PAGE_CACHE_SIZE = 76k is CONFIG_READA_SMALL is undefined
  *      and 32K if defined (4K page size assumed).
  *
  * Asynchronous read-ahead benefits:
@@ -440,7 +434,7 @@
  *   ONE seems to be the only reasonable value.
  * - The total memory pool usage for the file access stream.
  *   This maximum memory usage is implicitly 2 IO read chunks:
- *   2*(MAX_READAHEAD + PAGE_SIZE) = 156K if CONFIG_READA_SMALL is undefined,
+ *   2*(MAX_READAHEAD + PAGE_CACHE_SIZE) = 156K if CONFIG_READA_SMALL is undefined,
  *   64k if defined (4K page size assumed).
  */
 
@@ -459,7 +453,7 @@
 	unsigned long raend;
 	int max_readahead = get_max_readahead(inode);
 
-	raend = filp->f_raend & PAGE_MASK;
+	raend = filp->f_raend & PAGE_CACHE_MASK;
 	max_ahead = 0;
 
 /*
@@ -476,7 +470,7 @@
 			if (raend < inode->i_size)
 				max_ahead = filp->f_ramax;
 			filp->f_rawin = 0;
-			filp->f_ralen = PAGE_SIZE;
+			filp->f_ralen = PAGE_CACHE_SIZE;
 			if (!max_ahead) {
 				filp->f_raend  = ppos + filp->f_ralen;
 				filp->f_rawin += filp->f_ralen;
@@ -491,17 +485,17 @@
  *   it is the moment to try to read ahead asynchronously.
  * We will later force unplug device in order to force asynchronous read IO.
  */
-	else if (reada_ok && filp->f_ramax && raend >= PAGE_SIZE &&
+	else if (reada_ok && filp->f_ramax && raend >= PAGE_CACHE_SIZE &&
 	         ppos <= raend && ppos + filp->f_ralen >= raend) {
 /*
  * Add ONE page to max_ahead in order to try to have about the same IO max size
- * as synchronous read-ahead (MAX_READAHEAD + 1)*PAGE_SIZE.
+ * as synchronous read-ahead (MAX_READAHEAD + 1)*PAGE_CACHE_SIZE.
  * Compute the position of the last page we have tried to read in order to 
  * begin to read ahead just at the next page.
  */
-		raend -= PAGE_SIZE;
+		raend -= PAGE_CACHE_SIZE;
 		if (raend < inode->i_size)
-			max_ahead = filp->f_ramax + PAGE_SIZE;
+			max_ahead = filp->f_ramax + PAGE_CACHE_SIZE;
 
 		if (max_ahead) {
 			filp->f_rawin = filp->f_ralen;
@@ -516,7 +510,7 @@
  */
 	ahead = 0;
 	while (ahead < max_ahead) {
-		ahead += PAGE_SIZE;
+		ahead += PAGE_CACHE_SIZE;
 		page_cache = try_to_read_ahead(filp, raend + ahead,
 						page_cache);
 	}
@@ -538,7 +532,7 @@
 
 		filp->f_ralen += ahead;
 		filp->f_rawin += filp->f_ralen;
-		filp->f_raend = raend + ahead + PAGE_SIZE;
+		filp->f_raend = raend + ahead + PAGE_CACHE_SIZE;
 
 		filp->f_ramax += filp->f_ramax;
 
@@ -590,7 +584,7 @@
 	page_cache = 0;
 
 	pos = *ppos;
-	pgpos = pos & PAGE_MASK;
+	pgpos = pos & PAGE_CACHE_MASK;
 /*
  * If the current position is outside the previous read-ahead window, 
  * we reset the current read-ahead context and set read ahead max to zero
@@ -614,12 +608,12 @@
  * Then, at least MIN_READAHEAD if read ahead is ok,
  * and at most MAX_READAHEAD in all cases.
  */
-	if (pos + desc->count <= (PAGE_SIZE >> 1)) {
+	if (pos + desc->count <= (PAGE_CACHE_SIZE >> 1)) {
 		filp->f_ramax = 0;
 	} else {
 		unsigned long needed;
 
-		needed = ((pos + desc->count) & PAGE_MASK) - pgpos;
+		needed = ((pos + desc->count) & PAGE_CACHE_MASK) - pgpos;
 
 		if (filp->f_ramax < needed)
 			filp->f_ramax = needed;
@@ -639,8 +633,8 @@
 		/*
 		 * Try to find the data in the page cache..
 		 */
-		hash = page_hash(inode, pos & PAGE_MASK);
-		page = __find_page(inode, pos & PAGE_MASK, *hash);
+		hash = page_hash(inode, pos & PAGE_CACHE_MASK);
+		page = __find_page(inode, pos & PAGE_CACHE_MASK, *hash);
 		if (!page)
 			goto no_cached_page;
 
@@ -653,7 +647,7 @@
  * the page has been rewritten.
  */
 		if (PageUptodate(page) || PageLocked(page))
-			page_cache = generic_file_readahead(reada_ok, filp, inode, pos & PAGE_MASK, page, page_cache);
+			page_cache = generic_file_readahead(reada_ok, filp, inode, pos & PAGE_CACHE_MASK, page, page_cache);
 		else if (reada_ok && filp->f_ramax > MIN_READAHEAD)
 				filp->f_ramax = MIN_READAHEAD;
 
@@ -670,8 +664,8 @@
 	{
 		unsigned long offset, nr;
 
-		offset = pos & ~PAGE_MASK;
-		nr = PAGE_SIZE - offset;
+		offset = pos & ~PAGE_CACHE_MASK;
+		nr = PAGE_CACHE_SIZE - offset;
 		if (nr > inode->i_size - pos)
 			nr = inode->i_size - pos;
 
@@ -684,7 +678,7 @@
 		 */
 		nr = actor(desc, (const char *) (page_address(page) + offset), nr);
 		pos += nr;
-		release_page(page);
+		page_cache_release(page);
 		if (nr && desc->count)
 			continue;
 		break;
@@ -696,7 +690,7 @@
 		 * page..
 		 */
 		if (!page_cache) {
-			page_cache = __get_free_page(GFP_USER);
+			page_cache = page_cache_alloc();
 			/*
 			 * That could have slept, so go around to the
 			 * very beginning..
@@ -710,9 +704,9 @@
 		/*
 		 * Ok, add the new page to the hash-queues...
 		 */
-		page = mem_map + MAP_NR(page_cache);
+		page = page_cache_entry(page_cache);
 		page_cache = 0;
-		add_to_page_cache(page, inode, pos & PAGE_MASK, hash);
+		add_to_page_cache(page, inode, pos & PAGE_CACHE_MASK, hash);
 
 		/*
 		 * Error handling is tricky. If we get a read error,
@@ -737,7 +731,7 @@
 			if (!error)
 				goto found_page;
 			desc->error = error;
-			release_page(page);
+			page_cache_release(page);
 			break;
 		}
 
@@ -756,7 +750,7 @@
 				error = -EIO; /* Some unspecified error occurred.. */
 			}
 			desc->error = error;
-			release_page(page);
+			page_cache_release(page);
 			break;
 		}
 	}
@@ -764,7 +758,7 @@
 	*ppos = pos;
 	filp->f_reada = 1;
 	if (page_cache)
-		free_page(page_cache);
+		page_cache_free(page_cache);
 	UPDATE_ATIME(inode);
 }
 
@@ -943,7 +937,7 @@
 	unsigned long old_page, new_page;
 
 	new_page = 0;
-	offset = (address & PAGE_MASK) - area->vm_start + area->vm_offset;
+	offset = (address - area->vm_start + area->vm_offset) & PAGE_MASK;
 	if (offset >= inode->i_size && (area->vm_flags & VM_SHARED) && area->vm_mm == current->mm)
 		goto no_page;
 
@@ -962,7 +956,7 @@
 	 * extra page -- better to overlap the allocation with the I/O.
 	 */
 	if (no_share && !new_page) {
-		new_page = __get_free_page(GFP_USER);
+		new_page = page_cache_alloc();
 		if (!new_page)
 			goto failure;
 	}
@@ -984,7 +978,7 @@
 		 * of any potential extra pages.
 		 */
 		if (new_page)
-			free_page(new_page);
+			page_cache_free(new_page);
 
 		flush_page_to_ram(old_page);
 		return old_page;
@@ -995,7 +989,7 @@
 	 */
 	copy_page(new_page, old_page);
 	flush_page_to_ram(new_page);
-	release_page(page);
+	page_cache_release(page);
 	return new_page;
 
 no_cached_page:
@@ -1003,14 +997,14 @@
 	 * Try to read in an entire cluster at once.
 	 */
 	reada   = offset;
-	reada >>= PAGE_SHIFT + page_cluster;
-	reada <<= PAGE_SHIFT + page_cluster;
+	reada >>= PAGE_CACHE_SHIFT + page_cluster;
+	reada <<= PAGE_CACHE_SHIFT + page_cluster;
 
-	for (i = 1 << page_cluster; i > 0; --i, reada += PAGE_SIZE)
+	for (i = 1 << page_cluster; i > 0; --i, reada += PAGE_CACHE_SIZE)
 		new_page = try_to_read_ahead(file, reada, new_page);
 
 	if (!new_page)
-		new_page = __get_free_page(GFP_USER);
+		new_page = page_cache_alloc();
 	if (!new_page)
 		goto no_page;
 
@@ -1027,7 +1021,7 @@
 	/*
 	 * Now, create a new page-cache page from the page we got
 	 */
-	page = mem_map + MAP_NR(new_page);
+	page = page_cache_entry(new_page);
 	new_page = 0;
 	add_to_page_cache(page, inode, offset, hash);
 
@@ -1061,9 +1055,9 @@
 	 * mm layer so, possibly freeing the page cache page first.
 	 */
 failure:
-	release_page(page);
+	page_cache_release(page);
 	if (new_page)
-		free_page(new_page);
+		page_cache_free(new_page);
 no_page:
 	return 0;
 }
@@ -1166,7 +1160,7 @@
 		set_pte(ptep, pte_mkclean(pte));
 		flush_tlb_page(vma, address);
 		page = pte_page(pte);
-		atomic_inc(&mem_map[MAP_NR(page)].count);
+		atomic_inc(&page_cache_entry(page)->count);
 	} else {
 		if (pte_none(pte))
 			return 0;
@@ -1179,12 +1173,12 @@
 		}
 		page = pte_page(pte);
 		if (!pte_dirty(pte) || flags == MS_INVALIDATE) {
-			free_page(page);
+			page_cache_free(page);
 			return 0;
 		}
 	}
 	error = filemap_write_page(vma, address - vma->vm_start + vma->vm_offset, page, 1);
-	free_page(page);
+	page_cache_free(page);
 	return error;
 }
 
@@ -1492,9 +1486,9 @@
 		 * Try to find the page in the cache. If it isn't there,
 		 * allocate a free page.
 		 */
-		offset = (pos & ~PAGE_MASK);
-		pgpos = pos & PAGE_MASK;
-		bytes = PAGE_SIZE - offset;
+		offset = (pos & ~PAGE_CACHE_MASK);
+		pgpos = pos & PAGE_CACHE_MASK;
+		bytes = PAGE_CACHE_SIZE - offset;
 		if (bytes > count)
 			bytes = count;
 
@@ -1502,13 +1496,13 @@
 		page = __find_page(inode, pgpos, *hash);
 		if (!page) {
 			if (!page_cache) {
-				page_cache = __get_free_page(GFP_USER);
+				page_cache = page_cache_alloc();
 				if (page_cache)
 					continue;
 				status = -ENOMEM;
 				break;
 			}
-			page = mem_map + MAP_NR(page_cache);
+			page = page_cache_entry(page_cache);
 			add_to_page_cache(page, inode, pgpos, hash);
 			page_cache = 0;
 		}
@@ -1530,7 +1524,7 @@
 		/* Mark it unlocked again and drop the page.. */
 		clear_bit(PG_locked, &page->flags);
 		wake_up(&page->wait);
-		__free_page(page);
+		page_cache_release(page);
 
 		if (status < 0)
 			break;
@@ -1545,7 +1539,7 @@
 		inode->i_size = pos;
 
 	if (page_cache)
-		free_page(page_cache);
+		page_cache_free(page_cache);
 out:
 	return written ? written : status;
 }
@@ -1573,10 +1567,11 @@
 	if (!page) {
 		if (!new)
 			goto out;
-		page_cache = get_free_page(GFP_USER);
+		page_cache = page_cache_alloc();
 		if (!page_cache)
 			goto out;
-		page = mem_map + MAP_NR(page_cache);
+		clear_page(page_cache);
+		page = page_cache_entry(page_cache);
 		add_to_page_cache(page, inode, offset, hash);
 	}
 	if (atomic_read(&page->count) != 2)
@@ -1596,7 +1591,7 @@
  */
 void put_cached_page(unsigned long addr)
 {
-	struct page * page = mem_map + MAP_NR(addr);
+	struct page * page = page_cache_entry(addr);
 
 	if (!test_bit(PG_locked, &page->flags))
 		printk("put_cached_page: page not locked!\n");
@@ -1605,7 +1600,7 @@
 			atomic_read(&page->count));
 	clear_bit(PG_locked, &page->flags);
 	wake_up(&page->wait);
-	__free_page(page);
+	page_cache_release(page);
 }
 
 
@@ -1637,7 +1632,7 @@
 {
 	struct pio_request *p;
 
-	atomic_inc(&mem_map[MAP_NR(page)].count);
+	atomic_inc(&page_cache_entry(page)->count);
 
 	/* 
 	 * We need to allocate without causing any recursive IO in the
@@ -1726,7 +1721,7 @@
 				      (const char *) p->page, p->offset);
 			up(&inode->i_sem);
 			fput(p->file);
-			free_page(p->page);
+			page_cache_free(p->page);
 			kmem_cache_free(pio_request_cache, p);
 		}
 	}
diff -u --recursive --new-file v2.2.7/linux/mm/mmap.c linux/mm/mmap.c
--- v2.2.7/linux/mm/mmap.c	Fri Apr 16 14:47:31 1999
+++ linux/mm/mmap.c	Tue May  4 15:44:38 1999
@@ -176,6 +176,9 @@
 	struct vm_area_struct * vma;
 	int error;
 
+	if (file && (!file->f_op || !file->f_op->mmap))
+		return -ENODEV;
+
 	if ((len = PAGE_ALIGN(len)) == 0)
 		return addr;
 
@@ -244,9 +247,6 @@
 	 * specific mapper. the address has already been validated, but
 	 * not unmapped, but the maps are removed from the list.
 	 */
-	if (file && (!file->f_op || !file->f_op->mmap))
-		return -ENODEV;
-
 	vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
 	if (!vma)
 		return -ENOMEM;
diff -u --recursive --new-file v2.2.7/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.2.7/linux/mm/page_alloc.c	Wed Apr 28 11:37:32 1999
+++ linux/mm/page_alloc.c	Thu May  6 14:32:06 1999
@@ -419,12 +419,12 @@
 		return;
 	}
 
-	/* The page is unshared, and we want write access.  In this
-	   case, it is safe to tear down the swap cache and give the
-	   page over entirely to this process. */
-
-	if (PageSwapCache(page_map))
-		delete_from_swap_cache(page_map);
+	/*
+	 * The page is unshared and we're going to dirty it - so tear
+	 * down the swap cache and give exclusive access to the page to
+	 * this process.
+	 */
+	delete_from_swap_cache(page_map);
 	set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))));
   	return;
 }
diff -u --recursive --new-file v2.2.7/linux/net/core/iovec.c linux/net/core/iovec.c
--- v2.2.7/linux/net/core/iovec.c	Mon Sep 28 10:51:36 1998
+++ linux/net/core/iovec.c	Mon May 10 09:55:25 1999
@@ -59,8 +59,15 @@
 		goto out;
 	m->msg_iov=iov;
 
-	for (err = 0, ct = 0; ct < m->msg_iovlen; ct++)
+	for (err = 0, ct = 0; ct < m->msg_iovlen; ct++) {
 		err += iov[ct].iov_len;
+		/* Goal is not to verify user data, but to prevent returning
+		   negative value, which is interpreted as errno.
+		   Overflow is still possible, but it is harmless.
+		 */
+		if (err < 0)
+			return -EMSGSIZE;
+	}
 out:
 	return err;
 }
diff -u --recursive --new-file v2.2.7/linux/net/core/sock.c linux/net/core/sock.c
--- v2.2.7/linux/net/core/sock.c	Mon Mar 29 11:09:12 1999
+++ linux/net/core/sock.c	Mon May 10 09:55:25 1999
@@ -7,7 +7,7 @@
  *		handler for protocols to use and generic option handler.
  *
  *
- * Version:	$Id: sock.c,v 1.79 1999/03/28 10:18:25 davem Exp $
+ * Version:	$Id: sock.c,v 1.80 1999/05/08 03:04:34 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -944,7 +944,7 @@
 			 */
 			if (current->pgrp != -arg &&
 				current->pid != arg &&
-				!capable(CAP_NET_ADMIN)) return(-EPERM);
+				!capable(CAP_KILL)) return(-EPERM);
 			sk->proc = arg;
 			return(0);
 		case F_GETOWN:
diff -u --recursive --new-file v2.2.7/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.2.7/linux/net/ipv4/devinet.c	Mon Mar 29 11:09:12 1999
+++ linux/net/ipv4/devinet.c	Mon May 10 09:55:25 1999
@@ -1,7 +1,7 @@
 /*
  *	NET3	IP device support routines.
  *
- *	Version: $Id: devinet.c,v 1.27 1999/03/25 10:04:06 davem Exp $
+ *	Version: $Id: devinet.c,v 1.28 1999/05/08 20:00:16 davem Exp $
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -712,6 +712,7 @@
 				ifa->ifa_mask = inet_make_mask(8);
 				ifa->ifa_dev = in_dev;
 				ifa->ifa_scope = RT_SCOPE_HOST;
+				memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
 				inet_insert_ifa(in_dev, ifa);
 			}
 		}
diff -u --recursive --new-file v2.2.7/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.2.7/linux/net/ipv4/route.c	Wed Apr 28 11:37:32 1999
+++ linux/net/ipv4/route.c	Mon May 10 09:55:25 1999
@@ -5,7 +5,7 @@
  *
  *		ROUTE - implementation of the IP router.
  *
- * Version:	$Id: route.c,v 1.66 1999/04/22 10:07:35 davem Exp $
+ * Version:	$Id: route.c,v 1.67 1999/05/08 20:00:20 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1492,13 +1492,16 @@
 			return -ENODEV;	/* Wrong error code */
 
 		if (LOCAL_MCAST(daddr) || daddr == 0xFFFFFFFF) {
-			key.src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK);
+			if (!key.src)
+				key.src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK);
 			goto make_route;
 		}
-		if (MULTICAST(daddr))
-			key.src = inet_select_addr(dev_out, 0, key.scope);
-		else if (!daddr)
-			key.src = inet_select_addr(dev_out, 0, RT_SCOPE_HOST);
+		if (!key.src) {
+			if (MULTICAST(daddr))
+				key.src = inet_select_addr(dev_out, 0, key.scope);
+			else if (!daddr)
+				key.src = inet_select_addr(dev_out, 0, RT_SCOPE_HOST);
+		}
 	}
 
 	if (!key.dst) {
diff -u --recursive --new-file v2.2.7/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.2.7/linux/net/ipv4/tcp_input.c	Wed Apr 28 11:37:32 1999
+++ linux/net/ipv4/tcp_input.c	Mon May 10 09:55:25 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.163 1999/04/28 16:08:05 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.164 1999/05/08 21:09:52 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -497,8 +497,7 @@
 		if (tp->high_seq == 0 || after(ack, tp->high_seq)) {
 			tp->dup_acks++;
 			if ((tp->fackets_out > 3) || (tp->dup_acks == 3)) {
-                                tp->snd_ssthresh =
-					max(min(tp->snd_wnd, tp->snd_cwnd) >> 1, 2);
+                                tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
                                 tp->snd_cwnd = (tp->snd_ssthresh + 3);
 				tp->high_seq = tp->snd_nxt;
 				if(!tp->fackets_out)
diff -u --recursive --new-file v2.2.7/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.2.7/linux/net/ipv4/tcp_ipv4.c	Wed Apr 28 11:37:32 1999
+++ linux/net/ipv4/tcp_ipv4.c	Mon May 10 09:55:25 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.174 1999/04/28 16:08:19 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.175 1999/05/08 21:09:54 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -819,7 +819,7 @@
 	switch (type) {
 	case ICMP_SOURCE_QUENCH:
 #ifndef OLD_SOURCE_QUENCH /* This is deprecated */
-		tp->snd_ssthresh = max(tp->snd_cwnd >> 1, 2);
+		tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
 		tp->snd_cwnd = tp->snd_ssthresh;
 		tp->snd_cwnd_cnt = 0;
 		tp->high_seq = tp->snd_nxt;
diff -u --recursive --new-file v2.2.7/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- v2.2.7/linux/net/ipv4/tcp_output.c	Wed Apr 28 11:37:32 1999
+++ linux/net/ipv4/tcp_output.c	Mon May 10 09:55:25 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.107 1999/04/28 16:08:12 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.108 1999/05/08 21:48:59 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -521,24 +521,39 @@
 void tcp_simple_retransmit(struct sock *sk)
 {
 	struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
-	struct sk_buff *skb; 
-	unsigned int mss = tcp_current_mss(sk); 
+	struct sk_buff *skb, *old_next_skb;
+	unsigned int mss = tcp_current_mss(sk);
 
  	/* Don't muck with the congestion window here. */
  	tp->dup_acks = 0;
  	tp->high_seq = tp->snd_nxt;
- 	tp->retrans_head = NULL; 
+ 	tp->retrans_head = NULL;
 
  	/* Input control flow will see that this was retransmitted
 	 * and not use it for RTT calculation in the absence of
 	 * the timestamp option.
 	 */
-	for (skb = skb_peek(&sk->write_queue);
+	for (old_next_skb = skb = skb_peek(&sk->write_queue);
 	     ((skb != tp->send_head) &&
 	      (skb != (struct sk_buff *)&sk->write_queue));
-	     skb = skb->next) 
-		if (skb->len > mss)
-			tcp_retransmit_skb(sk, skb); 
+	     skb = skb->next) {
+		int resend_skb = 0;
+
+		/* Our goal is to push out the packets which we
+		 * sent already, but are being chopped up now to
+		 * account for the PMTU information we have.
+		 *
+		 * As we resend the queue, packets are fragmented
+		 * into two pieces, and when we try to send the
+		 * second piece it may be collapsed together with
+		 * a subsequent packet, and so on.  -DaveM
+		 */
+		if (old_next_skb != skb || skb->len > mss)
+			resend_skb = 1;
+		old_next_skb = skb->next;
+		if (resend_skb != 0)
+			tcp_retransmit_skb(sk, skb);
+	}
 }
 
 static __inline__ void update_retrans_head(struct sock *sk)
diff -u --recursive --new-file v2.2.7/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c
--- v2.2.7/linux/net/ipv4/tcp_timer.c	Wed Apr 28 11:37:32 1999
+++ linux/net/ipv4/tcp_timer.c	Mon May 10 09:55:25 1999
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_timer.c,v 1.60 1999/04/28 16:08:21 davem Exp $
+ * Version:	$Id: tcp_timer.c,v 1.62 1999/05/08 21:09:55 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -317,48 +317,47 @@
 void tcp_tw_schedule(struct tcp_tw_bucket *tw)
 {
 	int slot = (tcp_tw_death_row_slot - 1) & (TCP_TWKILL_SLOTS - 1);
+	struct tcp_tw_bucket **tpp = &tcp_tw_death_row[slot];
+
+	if((tw->next_death = *tpp) != NULL)
+		(*tpp)->pprev_death = &tw->next_death;
+	*tpp = tw;
+	tw->pprev_death = tpp;
 
 	tw->death_slot = slot;
-	tw->next_death = tcp_tw_death_row[slot];
-	tcp_tw_death_row[slot] = tw;
+
 	tcp_inc_slow_timer(TCP_SLT_TWKILL);
 }
 
 /* Happens rarely if at all, no care about scalability here. */
 void tcp_tw_reschedule(struct tcp_tw_bucket *tw)
 {
-	struct tcp_tw_bucket *walk;
-	int slot = tw->death_slot;
+	struct tcp_tw_bucket **tpp;
+	int slot;
+
+	if(tw->next_death)
+		tw->next_death->pprev_death = tw->pprev_death;
+	*tw->pprev_death = tw->next_death;
+	tw->pprev_death = NULL;
 
-	walk = tcp_tw_death_row[slot];
-	if(walk == tw) {
-		tcp_tw_death_row[slot] = tw->next_death;
-	} else {
-		while(walk->next_death != tw)
-			walk = walk->next_death;
-		walk->next_death = tw->next_death;
-	}
 	slot = (tcp_tw_death_row_slot - 1) & (TCP_TWKILL_SLOTS - 1);
+	tpp = &tcp_tw_death_row[slot];
+	if((tw->next_death = *tpp) != NULL)
+		(*tpp)->pprev_death = &tw->next_death;
+	*tpp = tw;
+	tw->pprev_death = tpp;
+
 	tw->death_slot = slot;
-	tw->next_death = tcp_tw_death_row[slot];
-	tcp_tw_death_row[slot] = tw;
 	/* Timer was incremented when we first entered the table. */
 }
 
 /* This is for handling early-kills of TIME_WAIT sockets. */
 void tcp_tw_deschedule(struct tcp_tw_bucket *tw)
 {
-	struct tcp_tw_bucket *walk;
-	int slot = tw->death_slot;
-
-	walk = tcp_tw_death_row[slot];
-	if(walk == tw) {
-		tcp_tw_death_row[slot] = tw->next_death;
-	} else {
-		while(walk->next_death != tw)
-			walk = walk->next_death;
-		walk->next_death = tw->next_death;
-	}
+	if(tw->next_death)
+		tw->next_death->pprev_death = tw->pprev_death;
+	*tw->pprev_death = tw->next_death;
+	tw->pprev_death = NULL;
 	tcp_dec_slow_timer(TCP_SLT_TWKILL);
 }
 
@@ -478,7 +477,7 @@
 		 * means it must be an accurate representation of our current
 		 * sending rate _and_ the snd_wnd.
 		 */
-		tp->snd_ssthresh = max(min(tp->snd_wnd, tp->snd_cwnd) >> 1, 2);
+		tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
 		tp->snd_cwnd_cnt = 0;
 		tp->snd_cwnd = 1;
 	}
diff -u --recursive --new-file v2.2.7/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
--- v2.2.7/linux/net/ipv4/udp.c	Tue Mar 23 14:35:48 1999
+++ linux/net/ipv4/udp.c	Mon May 10 09:55:25 1999
@@ -5,7 +5,7 @@
  *
  *		The User Datagram Protocol (UDP).
  *
- * Version:	$Id: udp.c,v 1.65 1999/03/21 05:22:49 davem Exp $
+ * Version:	$Id: udp.c,v 1.66 1999/05/08 20:00:25 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -955,7 +955,7 @@
 	 * Error for blocking case is chosen to masquerade
    	 * as some normal condition.
 	 */
-	return (msg->msg_flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;	
+	return (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;	
 #endif
 }
 
diff -u --recursive --new-file v2.2.7/linux/net/ipv6/udp.c linux/net/ipv6/udp.c
--- v2.2.7/linux/net/ipv6/udp.c	Wed Apr 28 11:37:32 1999
+++ linux/net/ipv6/udp.c	Mon May 10 09:55:25 1999
@@ -7,7 +7,7 @@
  *
  *	Based on linux/ipv4/udp.c
  *
- *	$Id: udp.c,v 1.39 1999/04/22 10:07:47 davem Exp $
+ *	$Id: udp.c,v 1.40 1999/05/08 20:00:32 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -381,7 +381,7 @@
 			/* Error for blocking case is chosen to masquerade
 			   as some normal condition.
 			 */
-			err = (msg->msg_flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
+			err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
 			udp_stats_in6.UdpInErrors++;
 			goto out_free;
 		}
@@ -398,7 +398,7 @@
 			/* Error for blocking case is chosen to masquerade
 			   as some normal condition.
 			 */
-			err = (msg->msg_flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
+			err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH;
 			udp_stats_in6.UdpInErrors++;
 			goto out_free;
 		}
diff -u --recursive --new-file v2.2.7/linux/net/irda/ircomm/ircomm_common.c linux/net/irda/ircomm/ircomm_common.c
--- v2.2.7/linux/net/irda/ircomm/ircomm_common.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/ircomm/ircomm_common.c	Thu May  6 16:40:53 1999
@@ -147,13 +147,7 @@
 };
 
 #ifdef CONFIG_PROC_FS
-extern struct proc_dir_entry proc_irda;
-struct proc_dir_entry proc_ircomm = {
-	0, 6, "ircomm",
-        S_IFREG | S_IRUGO, 1, 0, 0,
-        0, NULL,
-        &ircomm_proc_read,
-};
+extern struct proc_dir_entry *proc_irda;
 #endif
 
 static void (*state[])( struct ircomm_cb *self, IRCOMM_EVENT event,
@@ -229,7 +223,7 @@
 	 */
 
 #ifdef CONFIG_PROC_FS
-	proc_register( &proc_irda, &proc_ircomm);
+	create_proc_entry("ircomm", 0, proc_irda)->get_info = ircomm_proc_read;
 #endif /* CONFIG_PROC_FS */
 
 
@@ -267,7 +261,7 @@
 	}
 
 #ifdef CONFIG_PROC_FS
-	proc_unregister( &proc_irda, proc_ircomm.low_ino);
+	remove_proc_entry("ircomm", proc_irda);
 #endif /* CONFIG_PROC_FS */
 }
 #endif /* MODULE */
diff -u --recursive --new-file v2.2.7/linux/net/irda/irlan/irlan_common.c linux/net/irda/irlan/irlan_common.c
--- v2.2.7/linux/net/irda/irlan/irlan_common.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/irlan/irlan_common.c	Thu May  6 16:40:53 1999
@@ -99,15 +99,8 @@
 static int irlan_proc_read(char *buf, char **start, off_t offset, int len, 
 			   int unused);
 
-extern struct proc_dir_entry proc_irda;
-
-struct proc_dir_entry proc_irlan = {
-	0, 5, "irlan",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL,
-	&irlan_proc_read,
-};
-#endif /* CONFIG_PROC_FS */
+extern struct proc_dir_entry *proc_irda;
+#endif
 
 void irlan_watchdog_timer_expired(unsigned long data)
 {
@@ -188,7 +181,7 @@
 		return -ENOMEM;
 	}
 #ifdef CONFIG_PROC_FS
-	proc_register(&proc_irda, &proc_irlan);
+	create_proc_entry("irlan", 0, proc_irda)->get_info = irlan_proc_read;
 #endif /* CONFIG_PROC_FS */
 
 	DEBUG(4, __FUNCTION__ "()\n");
@@ -224,7 +217,7 @@
 	irlmp_unregister_service(skey);
 
 #ifdef CONFIG_PROC_FS
-	proc_unregister(&proc_irda, proc_irlan.low_ino);
+	remove_proc_entry("irlan", proc_irda);
 #endif /* CONFIG_PROC_FS */
 	/*
 	 *  Delete hashbin and close all irlan client instances in it
diff -u --recursive --new-file v2.2.7/linux/net/irda/irlpt/irlpt_cli.c linux/net/irda/irlpt/irlpt_cli.c
--- v2.2.7/linux/net/irda/irlpt/irlpt_cli.c	Wed Apr 28 11:37:32 1999
+++ linux/net/irda/irlpt/irlpt_cli.c	Thu May  6 16:40:53 1999
@@ -157,14 +157,7 @@
 	return len;
 }
 
-struct proc_dir_entry proc_irlpt_client = {
-	0, 12, "irlpt_client",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL /* ops -- default to array */,
-	&irlpt_client_proc_read /* get_info */,
-};
-
-extern struct proc_dir_entry proc_irda;
+extern struct proc_dir_entry *proc_irda;
 
 #endif /* CONFIG_PROC_FS */
 
@@ -193,7 +186,8 @@
 				     NULL);
 
 #ifdef CONFIG_PROC_FS
-	proc_register( &proc_irda, &proc_irlpt_client);
+	create_proc_entry("irlpt_client", 0, proc_irda)->get_info
+			= irlpt_client_proc_read;
 #endif /* CONFIG_PROC_FS */
 
 	DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
@@ -219,7 +213,7 @@
 	hashbin_delete( irlpt_clients, (FREE_FUNC) irlpt_client_close);
 
 #ifdef CONFIG_PROC_FS
-	proc_unregister( &proc_irda, proc_irlpt_client.low_ino);
+	remove_proc_entry("irlpt_client", proc_irda);
 #endif
 
 	DEBUG( irlpt_client_debug, __FUNCTION__ " -->\n");
diff -u --recursive --new-file v2.2.7/linux/net/irda/irlpt/irlpt_srvr.c linux/net/irda/irlpt/irlpt_srvr.c
--- v2.2.7/linux/net/irda/irlpt/irlpt_srvr.c	Fri Apr 16 14:47:31 1999
+++ linux/net/irda/irlpt/irlpt_srvr.c	Thu May  6 16:40:53 1999
@@ -160,14 +160,7 @@
 	return len;
 }
 
-extern struct proc_dir_entry proc_irda;
-
-struct proc_dir_entry proc_irlpt_server = {
-	0, 12, "irlpt_server",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL /* ops -- default to array */,
-	&irlpt_server_proc_read /* get_info */,
-};
+extern struct proc_dir_entry *proc_irda;
 
 #endif /* CONFIG_PROC_FS */
 
@@ -215,7 +208,8 @@
 	register_irlpt_server();
 
 #ifdef CONFIG_PROC_FS
-	proc_register( &proc_irda, &proc_irlpt_server);
+	create_proc_entry("irlpt_server", 0, proc_irda)->get_info
+		= irlpt_server_proc_read;
 #endif /* CONFIG_PROC_FS */
 
 	DEBUG( irlpt_server_debug, __FUNCTION__ " -->\n");
@@ -248,7 +242,7 @@
 	kfree(irlpt_server);
 
 #ifdef CONFIG_PROC_FS
-	proc_unregister( &proc_irda, proc_irlpt_server.low_ino);
+	remove_proc_entry("irlpt_server", proc_irda);
 #endif
 
 	DEBUG( irlpt_server_debug, __FUNCTION__ " -->\n");
diff -u --recursive --new-file v2.2.7/linux/net/irda/irproc.c linux/net/irda/irproc.c
--- v2.2.7/linux/net/irda/irproc.c	Fri Apr 16 14:47:31 1999
+++ linux/net/irda/irproc.c	Thu May  6 16:40:53 1999
@@ -32,11 +32,6 @@
 #include <net/irda/irlap.h>
 #include <net/irda/irlmp.h>
 
-static int proc_irda_lookup(struct inode * dir, struct dentry *dentry);
-
-static int proc_irda_readdir(struct file *filp, void *dirent, 
- 			     filldir_t filldir);
-
 extern int irda_device_proc_read(char *buf, char **start, off_t offset, 
 				 int len, int unused);
 extern int irlap_proc_read(char *buf, char **start, off_t offset, int len, 
@@ -50,9 +45,6 @@
 extern int discovery_proc_read(char *buf, char **start, off_t offset, int len, 
 			       int unused);
 
-static int proc_discovery_read(char *buf, char **start, off_t offset, int len,
-			       int unused);
-
 enum irda_directory_inos {
 	PROC_IRDA_LAP = 1,
 	PROC_IRDA_LMP,
@@ -63,121 +55,26 @@
 	PROC_IRDA_IRIAS
 };
 
-static struct file_operations proc_irda_dir_operations = {
-        NULL,                   /* lseek - default */
-        NULL,                   /* read - bad */
-        NULL,                   /* write - bad */
-        proc_irda_readdir,      /* readdir */
-        NULL,                   /* select - default */
-        NULL,                   /* ioctl - default */
-        NULL,                   /* mmap */
-        NULL,                   /* no special open code */
-        NULL,                   /* no special release code */
-        NULL                    /* can't fsync */
-};
-
-/*
- * proc directories can do almost nothing..
- */
-struct inode_operations proc_irda_dir_inode_operations = {
-        &proc_irda_dir_operations,   /* default net directory file-ops */
-        NULL,                   /* create */
-	proc_irda_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 */
+struct irda_entry {
+	char *name;
+	int (*fn)(char*,char**,off_t,int,int);
 };
 
-struct proc_dir_entry proc_irda = {
-	0, 4, "irda",
-        S_IFDIR | S_IRUGO | S_IXUGO, 2, 0, 0,
-        0, &proc_irda_dir_inode_operations,
-        NULL, NULL,
-        NULL,
-        NULL, NULL
-};
+struct proc_dir_entry *proc_irda;
 
+static irda_entry dir[] = {
 #if 0 
-struct proc_dir_entry proc_lpt = {
-	0, 3, "lpt",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL /* ops -- default to array */,
-	&irlpt_proc_read /* get_info */,
-};
+	{"lpt", irlpt_proc_read},
 #endif
-
-struct proc_dir_entry proc_discovery = {
-	0, 9, "discovery",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL /* ops -- default to array */,
-	&discovery_proc_read /* get_info */,
+	{"discovery",	discovery_proc_read},
+	{"irda_device",	irda_device_proc_read},
+	{"irttp",	irttp_proc_read},
+	{"irlmp",	irlmp_proc_read},
+	{"irlap",	irlap_proc_read},
+	{"irias",	irias_proc_read},
 };
 
-struct proc_dir_entry proc_irda_device = {
-	0, 11, "irda_device",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL,
-	&irda_device_proc_read,
-};
-
-struct proc_dir_entry proc_ttp = {
-	0, 5, "irttp",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL /* ops -- default to array */,
-	&irttp_proc_read /* get_info */,
-};
-
-struct proc_dir_entry proc_lmp = {
-	0, 5, "irlmp",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL /* ops -- default to array */,
-	&irlmp_proc_read /* get_info */,
-};
-
-struct proc_dir_entry proc_lap = {
-	0, 5, "irlap",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL /* ops -- default to array */,
-	&irlap_proc_read /* get_info */,
-};
-
-struct proc_dir_entry proc_ias = {
-	0, 5, "irias",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	0, NULL /* ops -- default to array */,
-	&irias_proc_read /* get_info */,
-};
-
-/*
- * Function proc_delete_dentry (dentry)
- *
- *    Copy of proc/root.c because this function is invisible to the irda
- *    module
- * 
- */
-static void proc_delete_dentry(struct dentry * dentry)
-{
-	d_drop(dentry);
-}
-
-static struct dentry_operations proc_dentry_operations =
-{
-	NULL,			/* revalidate */
-	NULL,			/* d_hash */
-	NULL,			/* d_compare */
-	proc_delete_dentry	/* d_delete(struct dentry *) */
-};
+#define IRDA_ENTRIES_NUM (sizeof(dir)/sizeof(dir[0]))
 
 /*
  * Function irda_proc_register (void)
@@ -186,16 +83,13 @@
  *
  */
 void irda_proc_register(void) {
-	proc_net_register(&proc_irda);
+	int i;
+	proc_irda = create_proc_entry("net/irda", S_IFDIR, NULL);
 #ifdef MODULE
-	proc_irda.fill_inode = &irda_proc_modcount;
+	proc_irda->fill_inode = &irda_proc_modcount;
 #endif /* MODULE */
-	proc_register(&proc_irda, &proc_lap);
-	proc_register(&proc_irda, &proc_lmp);
-	proc_register(&proc_irda, &proc_ttp);
-	proc_register(&proc_irda, &proc_ias);
- 	proc_register(&proc_irda, &proc_irda_device); 
-	proc_register(&proc_irda, &proc_discovery);
+	for (i=0;i<IRDA_ENTRIES_NUM;i++)
+		create_proc_entry(dir[i].name,0,proc_irda)->get_info=dir[i].fn;
 }
 
 /*
@@ -205,116 +99,8 @@
  *
  */
 void irda_proc_unregister(void) {
-	proc_unregister(&proc_irda, proc_discovery.low_ino);
- 	proc_unregister(&proc_irda, proc_irda_device.low_ino);
-	proc_unregister(&proc_irda, proc_ias.low_ino);
-	proc_unregister(&proc_irda, proc_ttp.low_ino);
-	proc_unregister(&proc_irda, proc_lmp.low_ino);
-	proc_unregister(&proc_irda, proc_lap.low_ino);
-	proc_unregister(proc_net, proc_irda.low_ino);
-}
-
-/*
- * Function proc_irda_lookup (dir, dentry)
- *
- *    This is a copy of proc_lookup from the linux-2.2.x kernel
- *
- */
-int proc_irda_lookup(struct inode * dir, struct dentry *dentry)
-{
-	struct inode *inode;
-	struct proc_dir_entry * de;
-	int error;
-
-	error = -ENOTDIR;
-	if (!dir || !S_ISDIR(dir->i_mode))
-		goto out;
-
-	error = -ENOENT;
-	inode = NULL;
-	de = (struct proc_dir_entry *) dir->u.generic_ip;
-	if (de) {
-		for (de = de->subdir; de ; de = de->next) {
-			if (!de || !de->low_ino)
-				continue;
-			if (de->namelen != dentry->d_name.len)
-				continue;
-			if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
-				int ino = de->low_ino | (dir->i_ino & ~(0xffff));
-				error = -EINVAL;
-				inode = proc_get_inode(dir->i_sb, ino, de);
-				break;
-			}
-		}
-	}
-
-	if (inode) {
-		dentry->d_op = &proc_dentry_operations;
-		d_add(dentry, inode);
-		error = 0;
-	}
-out:
-	return error;
-}
-
-/*
- * Function proc_irda_readdir (filp, dirent, filldir)
- *
- *    This is a copy from linux/fs/proc because the function is invisible
- *    to the irda module
- * 
- */
-static int proc_irda_readdir(struct file *filp, void *dirent, 
-			     filldir_t filldir)
-{
-	struct proc_dir_entry * de;
-	unsigned int ino;
 	int i;
-	
-	struct inode *inode = filp->f_dentry->d_inode;
-	if (!inode || !S_ISDIR(inode->i_mode))
-		return -ENOTDIR;
-	ino = inode->i_ino;
-	de = (struct proc_dir_entry *) inode->u.generic_ip;
-	if (!de)
-		return -EINVAL;
-	i = filp->f_pos;
-	switch (i) {
-	case 0:
-		if (filldir(dirent, ".", 1, i, ino) < 0)
-			return 0;
-		i++;
-		filp->f_pos++;
-		/* fall through */
-	case 1:
-		if (filldir(dirent, "..", 2, i, de->parent->low_ino) < 0)
-			return 0;
-		i++;
-		filp->f_pos++;
-		/* fall through */
-	default:
-		ino &= ~0xffff;
-		de = de->subdir;
-		i -= 2;
-		for (;;) {
-			if (!de)
-				return 1;
-			if (!i)
-				break;
-			de = de->next;
-			i--;
-		}
-		
-		do {
-			if (filldir(dirent, de->name, de->namelen, filp->f_pos,
-				    ino | de->low_ino) < 0)
-				return 0;
-			filp->f_pos++;
-			de = de->next;
-		} while (de);
-	}
-	return 1;
+	for (i=0;i<IRDA_ENTRIES_NUM;i++)
+		remove_proc_entry(dir[i].name, proc_irda);
+	remove_proc_entry("net/irda", NULL);
 }
-
-
-
diff -u --recursive --new-file v2.2.7/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c
--- v2.2.7/linux/net/sunrpc/sched.c	Wed Mar 10 15:29:53 1999
+++ linux/net/sunrpc/sched.c	Fri May  7 11:19:11 1999
@@ -174,6 +174,7 @@
 		printk(KERN_ERR "RPC: task w/ running timer in rpc_make_runnable!!\n");
 		return;
 	}
+	task->tk_flags |= RPC_TASK_RUNNING;
 	if (RPC_IS_ASYNC(task)) {
 		int status;
 		status = rpc_add_wait_queue(&schedq, task);
@@ -186,7 +187,6 @@
 	} else {
 		wake_up(&task->tk_wait);
 	}
-	task->tk_flags |= RPC_TASK_RUNNING;
 }
 
 
@@ -447,7 +447,10 @@
 							task->tk_pid);
 			if (current->pid == rpciod_pid)
 				printk(KERN_ERR "RPC: rpciod waiting on sync task!\n");
-			sleep_on(&task->tk_wait);
+
+			sti();
+			__wait_event(task->tk_wait, RPC_IS_RUNNING(task));
+			cli();
 
 			/*
 			 * When the task received a signal, remove from
diff -u --recursive --new-file v2.2.7/linux/net/sunrpc/svcsock.c linux/net/sunrpc/svcsock.c
--- v2.2.7/linux/net/sunrpc/svcsock.c	Tue Mar 23 14:35:48 1999
+++ linux/net/sunrpc/svcsock.c	Tue May  4 10:29:07 1999
@@ -249,7 +249,8 @@
 	msg.msg_namelen = sizeof(rqstp->rq_addr);
 	msg.msg_iov     = iov;
 	msg.msg_iovlen  = nr;
-	msg.msg_control = 0;
+	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
 
 #if LINUX_VERSION_CODE >= 0x020100
 	msg.msg_flags	= MSG_DONTWAIT;
@@ -308,7 +309,8 @@
 	msg.msg_namelen = sizeof(rqstp->rq_addr);
 	msg.msg_iov     = iov;
 	msg.msg_iovlen  = nr;
-	msg.msg_control = 0;
+	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
 
 #if LINUX_VERSION_CODE >= 0x020100
 	msg.msg_flags	= MSG_DONTWAIT;
diff -u --recursive --new-file v2.2.7/linux/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c
--- v2.2.7/linux/net/sunrpc/xprt.c	Tue Mar 23 14:35:48 1999
+++ linux/net/sunrpc/xprt.c	Tue May  4 10:29:07 1999
@@ -200,6 +200,7 @@
 	msg.msg_name	= (struct sockaddr *) &xprt->addr;
 	msg.msg_namelen = sizeof(xprt->addr);
 	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
 
 	/* Dont repeat bytes */
 	
@@ -256,6 +257,7 @@
 	msg.msg_name	= &sin;
 	msg.msg_namelen = sizeof(sin);
 	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
 
 	oldfs = get_fs(); set_fs(get_ds());
 	result = sock_recvmsg(sock, &msg, len, MSG_DONTWAIT);
@@ -268,6 +270,7 @@
 	msg.msg_name	= &sin;
 	msg.msg_namelen = sizeof(sin);
 	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
 
 	oldfs = get_fs(); set_fs(get_ds());
 	result = sock->ops->recvmsg(sock, &msg, len, 1, 0, &alen);
diff -u --recursive --new-file v2.2.7/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.2.7/linux/net/unix/af_unix.c	Mon Mar 29 11:09:12 1999
+++ linux/net/unix/af_unix.c	Mon May 10 09:55:25 1999
@@ -8,7 +8,7 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  *
- * Version:	$Id: af_unix.c,v 1.75 1999/03/22 05:02:45 davem Exp $
+ * Version:	$Id: af_unix.c,v 1.76 1999/05/08 05:54:55 davem Exp $
  *
  * Fixes:
  *		Linus Torvalds	:	Assorted bug cures.
@@ -322,7 +322,7 @@
 	{
 		if (sk->type==SOCK_STREAM && unix_our_peer(sk, skpair))
 		{
-			skpair->state_change(skpair);
+			skpair->data_ready(skpair,0);
 			skpair->shutdown=SHUTDOWN_MASK;	/* No more writes*/
 		}
 		unix_unlock(skpair); /* It may now die */
@@ -1409,7 +1409,10 @@
 			if (mode&SEND_SHUTDOWN)
 				peer_mode |= RCV_SHUTDOWN;
 			other->shutdown |= peer_mode;
-			other->state_change(other);
+			if (peer_mode&RCV_SHUTDOWN)
+				other->data_ready(other,0);
+			else
+				other->state_change(other);
 		}
 	}
 	return 0;
diff -u --recursive --new-file v2.2.7/linux/scripts/Menuconfig linux/scripts/Menuconfig
--- v2.2.7/linux/scripts/Menuconfig	Tue Feb 23 15:21:36 1999
+++ linux/scripts/Menuconfig	Sun May  2 09:51:16 1999
@@ -193,7 +193,7 @@
 	else if [ "$3" = "m" ]; then
 	    mod_bool "$1" "$2"
 	else 
-	    define_bool "$2" "$n"
+	    define_bool "$2" n
 	fi; fi
 }
 
diff -u --recursive --new-file v2.2.7/linux/scripts/tkgen.c linux/scripts/tkgen.c
--- v2.2.7/linux/scripts/tkgen.c	Tue Feb 23 15:21:36 1999
+++ linux/scripts/tkgen.c	Sun May  2 09:51:16 1999
@@ -930,8 +930,11 @@
 
 	case token_hex:
 	case token_int:
+	    printf( "set %s %s\n", cfg->optionname, cfg->value ? cfg->value : "0");
+	    break;
+
 	case token_string:
-	    printf( "set %s %s\n", cfg->optionname, cfg->value );
+	    printf( "set %s \"%s\"\n", cfg->optionname, cfg->value ? cfg->value : "");
 	    break;
 	}
     }
diff -u --recursive --new-file v2.2.7/linux/scripts/tkparse.c linux/scripts/tkparse.c
--- v2.2.7/linux/scripts/tkparse.c	Tue Feb 23 15:21:36 1999
+++ linux/scripts/tkparse.c	Sun May  2 09:51:16 1999
@@ -496,10 +496,15 @@
 
     case token_hex:
     case token_int:
-    case token_string:
 	pnt = get_qstring ( pnt, &cfg->label      );
 	pnt = get_string  ( pnt, &cfg->optionname );
 	pnt = get_string  ( pnt, &cfg->value      );
+	break;
+
+    case token_string:
+	pnt = get_qstring ( pnt, &cfg->label      );
+	pnt = get_string  ( pnt, &cfg->optionname );
+	pnt = get_qstring  ( pnt, &cfg->value      );
 	break;
 
     case token_if:
